/
hash.clj
280 lines (237 loc) · 7.5 KB
/
hash.clj
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
;; Copyright 2014-2015 Andrey Antukh <niwi@niwi.nz>
;;
;; Licensed under the Apache License, Version 2.0 (the "License")
;; you may not use this file except in compliance with the License.
;; You may obtain a copy of the License at
;;
;; http://www.apache.org/licenses/LICENSE-2.0
;;
;; Unless required by applicable law or agreed to in writing, software
;; distributed under the License is distributed on an "AS IS" BASIS,
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;; See the License for the specific language governing permissions and
;; limitations under the License.
(ns buddy.core.hash
"Basic crypto primitives that used for more high
level abstractions."
(:refer-clojure :exclude [update reset!])
(:require [buddy.core.codecs :refer :all]
[clojure.java.io :as io])
(:import
org.bouncycastle.crypto.Digest
org.bouncycastle.crypto.digests.SHA1Digest
org.bouncycastle.crypto.digests.TigerDigest
org.bouncycastle.crypto.digests.MD5Digest
org.bouncycastle.crypto.digests.RIPEMD128Digest
org.bouncycastle.crypto.digests.RIPEMD160Digest
org.bouncycastle.crypto.digests.RIPEMD256Digest
org.bouncycastle.crypto.digests.RIPEMD320Digest
org.bouncycastle.crypto.digests.SHA3Digest
org.bouncycastle.crypto.digests.SHA256Digest
org.bouncycastle.crypto.digests.SHA384Digest
org.bouncycastle.crypto.digests.SHA512Digest
org.bouncycastle.crypto.digests.Blake2bDigest
org.bouncycastle.crypto.digests.SkeinDigest
org.bouncycastle.crypto.digests.WhirlpoolDigest))
(def ^:no-doc ^:static
+digest-engines+
{:sha256 #(SHA256Digest.)
:sha384 #(SHA384Digest.)
:sha512 #(SHA512Digest.)
:sha1 #(SHA1Digest.)
:ripemd128 #(RIPEMD128Digest.)
:ripemd160 #(RIPEMD160Digest.)
:ripemd256 #(RIPEMD256Digest.)
:ripemd320 #(RIPEMD320Digest.)
:tiger #(TigerDigest.)
:md5 #(MD5Digest.)
:sha3-256 #(SHA3Digest. 256)
:sha3-384 #(SHA3Digest. 384)
:sha3-512 #(SHA3Digest. 512)
:blake2b-128 #(Blake2bDigest. nil 16 nil nil)
:blake2b-256 #(Blake2bDigest. nil 32 nil nil)
:blake2b-512 #(Blake2bDigest. nil 64 nil nil)
:skein-256 #(SkeinDigest. 256 256)
:skein-512 #(SkeinDigest. 512 512)
:skein-1024 #(SkeinDigest. 1024 1024)
:whirlpool #(WhirlpoolDigest.)})
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Protocol definitions (abstractions)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defprotocol IDigest
(-digest [input engine] "Low level interface, always returns bytes"))
(defprotocol IEngine
"Hash engine common interface definition."
(-reset [_] "Reset the hash engine to its initial state.")
(-update [_ input offset length] "Update bytes in a current instance.")
(-end [_] "Return the computed mac and reset the engine."))
(extend-protocol IEngine
Digest
(-reset [it]
(.reset it))
(-update [it input offset length]
(.update it input offset length))
(-end [it]
(let [buffer (byte-array (.getDigestSize it))]
(.doFinal it buffer 0)
buffer)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Low level api
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn reset!
[engine]
(-reset engine))
(defn update!
([engine input]
(-update engine input 0 (count input)))
([engine input offset]
(-update engine input offset (count input)))
([engine input offset length]
(-update engine input offset length)))
(defn end!
[engine]
(-end engine))
(defn resolve-digest-engine
"Helper function for make Digest instances
from algorithm parameter."
[engine]
(cond
(keyword? engine)
(when-let [factory (get +digest-engines+ engine)]
(factory))
(instance? Digest engine) engine
(fn? engine) (engine)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Implementation details for different data types.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn- hash-plain-data
[^bytes input engine]
(-reset engine)
(-update engine input 0 (count input))
(-end engine))
(defn- hash-stream-data
[^java.io.InputStream input engine]
(-reset engine)
(let [buffer (byte-array 5120)]
(loop []
(let [readed (.read input buffer 0 5120)]
(when-not (= readed -1)
(-update engine buffer 0 readed)
(recur))))
(-end engine)))
(extend-protocol IDigest
(Class/forName "[B")
(-digest [^bytes input engine]
(hash-plain-data input engine))
String
(-digest [^String input engine]
(hash-plain-data (str->bytes input) engine))
java.io.InputStream
(-digest [^java.io.InputStream input engine]
(hash-stream-data input engine))
java.io.File
(-digest [^java.io.File input engine]
(with-open [is (io/input-stream input)]
(hash-stream-data is engine)))
java.net.URL
(-digest [^java.net.URL input engine]
(hash-stream-data (io/input-stream input) engine))
java.net.URI
(-digest [^java.net.URI input engine]
(hash-stream-data (io/input-stream input) engine)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; High level public api.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn digest
"Generic function for create cryptographic hash."
[input alg-or-engine]
(let [engine (resolve-digest-engine alg-or-engine)]
(-digest input engine)))
(defn blake2b
"BLAKE2 is a cryptographic hash function faster than MD5,
SHA-1, SHA-2, and SHA-3, yet is at least as secure as the
latest standard SHA-3."
[input length]
(let [engine (Blake2bDigest. nil length nil nil)]
(-digest input engine)))
(defn blake2b-128
"BLAKE2 cryptographic hash function with fixed output
digest size to 128 bits."
[input]
(digest input :blake2b-128))
(defn blake2b-256
"BLAKE2 cryptographic hash function with fixed output
digest size to 256 bits."
[input]
(digest input :blake2b-256))
(defn blake2b-512
"BLAKE2 cryptographic hash function with fixed output
digest size to 512 bits."
[input]
(digest input :blake2b-512))
(defn skein
"Skein is a cryptographic hash function based on
Threefish tweakable block cipher compressed using
Unique Block Iteration and is one of five finalists
in the NIST hash function competition for SHA3."
([input state]
(skein input state state))
([input state length]
(let [state (* state 8)
length (* length 8)
engine (SkeinDigest. state length)]
(-digest input engine))))
(defn skein-256
"Skein cryptographic hash function with fixed output
digest size to 256."
[input]
(skein input 32 32))
(defn skein-512
"Skein cryptographic hash function with fixed output
digest size to 256."
[input]
(skein input 64 64))
(defn skein-1024
"Skein cryptographic hash function with fixed output
digest size to 256."
[input]
(skein input 128 128))
(defn sha256
[input]
(digest input :sha256))
(defn sha384
[input]
(digest input :sha384))
(defn sha512
[input]
(digest input :sha512))
(defn sha3-256
[input]
(digest input :sha3-256))
(defn sha3-384
[input]
(digest input :sha3-384))
(defn sha3-512
[input]
(digest input :sha3-512))
(defn sha1
[input]
(digest input :sha1))
(defn md5
[input]
(digest input :md5))
(defn whirlpool
[input]
(digest input :whirlpool))
(defn ripemd128
[input]
(digest input :ripemd128))
(defn ripemd160
[input]
(digest input :ripemd160))
(defn ripemd256
[input]
(digest input :ripemd256))
(defn ripemd320
[input]
(digest input :ripemd320))