-
Notifications
You must be signed in to change notification settings - Fork 1
/
rsa.cljs
148 lines (136 loc) · 5.23 KB
/
rsa.cljs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
(ns uniformity.internals.js.rsa
(:require [uniformity.internals.js.node-browser-compat :refer [crypto-type crypto]]
[cljs.core.async :refer [go chan <! put!]]
[cljs.core.async.interop :refer [p->c]]
[async-error.core :refer-macros [go-try <?]]))
(def subtle (.-subtle crypto))
(defn browser-rsa-generate-keypair
[^number bits]
(go-try
(when-not (or (= bits 2048)
(= bits 3072)
(= bits 4092))
(throw (js/Error. "RSA key size must be one of 2048, 3072, or 4096")))
(let [pub-chan (chan 1)
priv-chan (chan 1)
params (clj->js {"name" "RSA-OAEP"
"modulusLength" bits
"publicExponent" (js/Uint8Array. [0x01, 0x00, 0x01])
"hash" "SHA-256"})
extractable true
key-usages ["encrypt" "decrypt"]]
(-> (.generateKey subtle
params
extractable
key-usages)
(.then (fn [keypair]
((-> (.exportKey ^Object subtle
"spki"
(.-publicKey keypair))
(.then (fn [key] (js/Uint8Array. key)))
(.then (fn [key] (put! pub-chan key))))
(-> (.exportKey subtle
"pkcs8"
(.-privateKey keypair))
(.then (fn [key] (js/Uint8Array. key)))
(.then (fn [key] (put! priv-chan key))))))))
{:public (<? pub-chan)
:private (<? priv-chan)})))
(defn browser-rsa-encrypt
[^js/Uint8Array plaintext
^js/Uint8Array pubkey]
(-> (.importKey subtle
"spki"
pubkey
(clj->js {"name" "RSA-OAEP"
"hash" "SHA-256"})
true
["encrypt"])
(.then (fn [cryptokey]
(.encrypt ^Object subtle
(clj->js {"name" "RSA-OAEP"})
cryptokey
plaintext)))
(.then (fn [ciphertext] (js/Uint8Array. ciphertext)))
p->c))
(defn browser-rsa-decrypt
[^js/Uint8Array ciphertext
^js/Uint8Array pubkey]
(-> (.importKey subtle
"pkcs8"
pubkey
(clj->js {"name" "RSA-OAEP"
"hash" "SHA-256"})
true
["decrypt"])
(.then (fn [cryptokey]
(.decrypt ^Object subtle
(clj->js {"name" "RSA-OAEP"})
cryptokey
ciphertext)))
(.then (fn [plaintext] (js/Uint8Array. plaintext)))
p->c))
(defn node-rsa-generate-keypair
[^number bits]
(go-try
(when-not (or (= bits 2048)
(= bits 3072)
(= bits 4092))
(throw (js/Error. "RSA key size must be one of 2048, 3072, or 4096")))
(let [pubkey-chan (chan 1)
privkey-chan (chan 1)
err-chan (chan 1)]
(.generateKeyPair ^Object crypto
"rsa"
(clj->js {"modulusLength" bits})
(fn [err pubkey privkey]
(if (some? err)
(put! err-chan err)
(do (put! err-chan false)
(->> (.export pubkey (clj->js {"type" "spki"
"format" "der"}))
js/Uint8Array.
(put! pubkey-chan))
(->> (.export privkey (clj->js {"type" "pkcs8"
"format" "der"}))
js/Uint8Array.
(put! privkey-chan))))))
(<? err-chan)
{:public (<? pubkey-chan)
:private (<? privkey-chan)})))
(defn node-rsa-encrypt
[^js/Uint8Array plaintext
^js/Uint8Array pubkey]
(go-try
(let [key-opts (clj->js {"key" pubkey
"format" "der"
"type" "spki"})
crypto-pubkey (.createPublicKey ^Object crypto key-opts)
rsa-opts (clj->js {"key" crypto-pubkey
"oaepHash" "sha256"})
ciphertext (.publicEncrypt ^Object crypto rsa-opts plaintext)]
(js/Uint8Array. ciphertext))))
(defn node-rsa-decrypt
^js/Uint8Array
[^js/Uint8Array ciphertext
^js/Uint8Array privkey]
(go-try
(let [key-options (clj->js {"key" privkey
"format" "der"
"type" "pkcs8"})
privkey (.createPrivateKey ^Object crypto key-options)
rsa-opts (clj->js {"key" privkey
"oaepHash" "sha256"})]
(js/Uint8Array. (.privateDecrypt ^Object crypto rsa-opts ciphertext)))))
(def rsa-generate-keypair
(if (= :browser crypto-type)
#'browser-rsa-generate-keypair
#'node-rsa-generate-keypair))
(def rsa-encrypt
(if (= :browser crypto-type)
#'browser-rsa-encrypt
#'node-rsa-encrypt))
(def rsa-decrypt
(if (= :browser crypto-type)
#'browser-rsa-decrypt
#'node-rsa-decrypt))