-
Notifications
You must be signed in to change notification settings - Fork 1
/
aes.cljs
108 lines (102 loc) · 3.74 KB
/
aes.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
(ns uniformity.internals.js.aes
(:require [uniformity.internals.js.node-browser-compat :refer [crypto-type crypto]]
[cljs.core.async :as async]
[cljs.core.async.interop :refer [p->c]]
[async-error.core :refer-macros [go-try <?]]))
(defn node-aes-gcm-encrypt
[^js/Uint8Array plaintext
^js/Uint8Array key
^js/Uint8Array nonce]
(go-try
(when-not (contains? #{16 24 32} (.-length key))
(throw (js/Error. "AES key must be 128, 192, or 256 bits")))
(when-not (= 12 (.-length nonce))
(throw (js/Error. "AES-GCM nonce must be 96 bits")))
(let [keysize (* 8 (.-length key))
algo (str "aes-" keysize "-gcm")
cipher (.createCipheriv crypto
algo
key
nonce
(clj->js {"authTagLength" 16}))
ciphertext (.update cipher plaintext)]
(.final cipher)
(js/Uint8Array.
(concat
ciphertext
(.getAuthTag cipher))))))
(defn node-aes-gcm-decrypt
[^js/Uint8Array ciphertext
^js/Uint8Array key
^js/Uint8Array nonce]
(go-try
(when-not (contains? #{16 24 32} (.-length key))
(throw (js/Error. "AES key must be 128, 192, or 256 bits")))
(when-not (= 12 (.-length nonce))
(throw (js/Error. "AES-GCM nonce must be 96 bits")))
(let [keysize (* 8 (.-length key))
algo (str "aes-" keysize "-gcm")
cipher (.createDecipheriv ^Object crypto
algo
key
nonce)
;; assume last 128 bits are auth tag
ct-tag (split-at (- (.-length ciphertext) 16) ciphertext)
ciphertext (js/Uint8Array. (nth ct-tag 0))
tag (js/Uint8Array. (nth ct-tag 1))
plaintext (.update cipher ciphertext)]
(.setAuthTag cipher tag)
(.final cipher)
(js/Uint8Array. plaintext))))
(defn browser-aes-gcm-encrypt
[^js/Uint8Array plaintext
^js/Uint8Array key
^js/Uint8Array nonce]
;; {:pre [(contains? #{16 24 32} (.-length key))
;; (= 12 (.-length nonce))]}
(let [algo-params (clj->js {"name" "AES-GCM"
"iv" nonce
"tagLength" 128})
subtle (.-subtle crypto)]
(-> (.importKey subtle
"raw"
key
"AES-GCM"
false
["encrypt"])
(.then (fn [cryptokey] (.encrypt ^Object subtle
algo-params
cryptokey
plaintext)))
(.then (fn [ciphertext] (js/Uint8Array. ciphertext)))
p->c)))
(defn browser-aes-gcm-decrypt
[^js/Uint8Array ciphertext
^js/Uint8Array key
^js/Uint8Array nonce]
;; {:pre [(contains? #{16 24 32} (.-length key))
;; (= 12 (.-length nonce))]}
(let [algo-params (clj->js {"name" "AES-GCM"
"iv" nonce
"tagLength" 128})
subtle (.-subtle crypto)]
(-> (.importKey subtle
"raw"
key
"AES-GCM"
false
["decrypt"])
(.then (fn [cryptokey] (.decrypt ^Object subtle
algo-params
cryptokey
ciphertext)))
(.then (fn [plaintext] (js/Uint8Array. plaintext)))
p->c)))
(def aes-gcm-encrypt
(if (= :browser crypto-type)
browser-aes-gcm-encrypt
node-aes-gcm-encrypt))
(def aes-gcm-decrypt
(if (= :browser crypto-type)
browser-aes-gcm-decrypt
node-aes-gcm-decrypt))