-
Notifications
You must be signed in to change notification settings - Fork 6
/
mac.cljc
137 lines (117 loc) · 4.15 KB
/
mac.cljc
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
(ns axel-f.buddy.mac
"Message Authentication Code algorithms."
(:refer-clojure :exclude [hash reset! #?@(:cljs [-reset -hash])])
(:require [axel-f.buddy.codecs :as codecs]
[axel-f.buddy.hash :as h]
[axel-f.buddy.bytes :as bytes]
#?(:cljs [goog.crypt.Hmac]))
#?(:clj (:import org.bouncycastle.crypto.Mac
org.bouncycastle.crypto.params.KeyParameter
org.bouncycastle.crypto.macs.HMac)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Abstraction
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defprotocol IMac
(-hash [_ engine] "Generate the auth message code")
(-verify [_ sig engine] "Verify the auth message code"))
(defprotocol IEngineInit
(-init [_ options] "Initialize the mac"))
(defprotocol IEngine
(-reset [_] "Reset engine state")
(-update [_ input offset length] "Update the engine state.")
(-end [_] "Generates the mac"))
(defmulti ^:no-doc engine
"A engine constructor."
:alg)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Impl
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#?(:clj
(extend-type Mac
IEngineInit
(-init [it options]
(let [key (:key options)
keyparam (KeyParameter. (codecs/to-bytes key))]
(.init it keyparam)))
IEngine
(-reset [it]
(.reset it))
(-update [it input offset length]
(.update it input offset length))
(-end [it]
(let [buffer (byte-array (.getMacSize it))]
(.doFinal it buffer 0)
buffer))))
#?(:cljs
(extend-type goog.crypt.Hmac
IEngineInit
(-init [it options])
IEngine
(-reset [it]
(.reset it))
(-update [it input offset length]
(.update it input))
(-end [it]
(let [buffer (.digest it)]
(.reset it)
buffer))))
(defmethod engine :hmac+sha256
[#?(:clj _options :cljs options)]
(let [digest (h/resolve-digest-engine :sha256)]
#?(:clj (HMac. digest)
:cljs (goog.crypt.Hmac. digest (codecs/str->bytes (:key options))))))
(defmethod engine :hmac+sha384
[#?(:clj _options :cljs options)]
(let [digest (h/resolve-digest-engine :sha384)]
#?(:clj (HMac. digest)
:cljs (goog.crypt.Hmac. digest (codecs/to-bytes (:key options))))))
(defmethod engine :hmac+sha512
[#?(:clj _options :cljs options)]
(let [digest (h/resolve-digest-engine :sha512)]
#?(:clj (HMac. digest)
:cljs (goog.crypt.Hmac. digest (codecs/to-bytes (:key options))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Implementation details for different data types.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn- hash-plain-data
[input engine]
(-reset engine)
(-update engine input 0 (count input))
(-end engine))
(defn- verify-plain-data
[input signature engine]
(let [sig (hash-plain-data input engine)]
(bytes/equals? sig signature)))
(extend-protocol IMac
#?(:clj (Class/forName "[B")
:cljs array)
(-hash [input engine]
(hash-plain-data input engine))
(-verify [input signature engine]
(verify-plain-data input signature engine))
#?(:clj java.lang.String
:cljs string)
(-hash [input engine]
(hash-plain-data (codecs/to-bytes input) engine))
(-verify [input signature engine]
(verify-plain-data (codecs/to-bytes input) signature engine)))
(defn hash
"Generate hmac digest for arbitrary
input data, a secret key and hash algorithm.
If algorithm is not supplied, sha256
will be used as default value."
[input engine-or-options]
(if (satisfies? IEngine engine-or-options)
(-hash input engine-or-options)
(let [engine (engine engine-or-options)]
(-init engine engine-or-options)
(-hash input engine))))
(defn verify
"Verify hmac for artbitrary input and signature."
[input signature engine-or-options]
(let [signature (codecs/to-bytes signature)]
(if (satisfies? IEngine engine-or-options)
(-verify input signature engine-or-options)
(let [engine (engine engine-or-options)]
(-init engine engine-or-options)
(-verify input signature engine)))))