-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathdigest.clj
108 lines (90 loc) · 3.24 KB
/
digest.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
(ns
^{:author "Miki Tebeka <miki.tebeka@gmail.com>"
:doc "Message digest algorithms for Clojure"}
clj-commons.digest
(:require [clojure.string :refer [join lower-case split]])
(:import (java.io File FileInputStream InputStream)
(java.security MessageDigest Provider Security)
(java.util Arrays)))
; Default buffer size for reading
(def ^:dynamic *buffer-size* 1024)
(defn- read-some
"Read some data from reader. Return [data size] if there's more to read,
otherwise nil."
[^InputStream reader]
(let [^bytes buffer (make-array Byte/TYPE *buffer-size*)
size (.read reader buffer)]
(when (pos? size)
(if (= size *buffer-size*) buffer (Arrays/copyOf buffer size)))))
(defn- byte-seq
"Return a sequence of [data size] from reader."
[^InputStream reader]
(take-while some? (repeatedly (partial read-some reader))))
(defn- signature
"Get signature (string) of digest."
[^MessageDigest algorithm]
(let [size (* 2 (.getDigestLength algorithm))
sig (.toString (BigInteger. 1 (.digest algorithm)) 16)
padding (join (repeat (- size (count sig)) "0"))]
(str padding sig)))
(defprotocol Digestible
(-digest [message algorithm]))
(extend-protocol Digestible
(class (make-array Byte/TYPE 0))
(-digest [message algorithm]
(-digest [message] algorithm))
java.util.Collection
;; Code "borrowed" from
;; * http://www.holygoat.co.uk/blog/entry/2009-03-26-1
;; * http://www.rgagnon.com/javadetails/java-0416.html
(-digest [message algorithm]
(let [^MessageDigest algo (MessageDigest/getInstance algorithm)]
(.reset algo)
(doseq [^bytes b message] (.update algo b))
(signature algo)))
String
(-digest [message algorithm]
(-digest [(.getBytes message)] algorithm))
InputStream
(-digest [reader algorithm]
(-digest (byte-seq reader) algorithm))
File
(-digest [file algorithm]
(with-open [f (FileInputStream. file)]
(-digest f algorithm)))
nil
(-digest [message algorithm]
nil))
(defn digest
"Returns digest for message with given algorithm."
[algorithm message]
(-digest message algorithm))
(defn algorithms
"List supported digest algorithms."
[]
(let [providers (vec (Security/getProviders))
names (mapcat (fn [^Provider p] (enumeration-seq (.keys p))) providers)
digest-names (filter #(re-find #"MessageDigest\.[A-Z0-9-]+$" %) names)]
(set (map #(last (split % #"\.")) digest-names))))
(defn- create-fn!
[algorithm-name]
(let [update-meta (fn [meta]
(assoc meta
:doc (str "Encode the given message with the " algorithm-name " algorithm.")
:arglists '([message])))]
(-> (intern *ns*
(symbol (lower-case algorithm-name))
(partial digest algorithm-name))
(alter-meta! update-meta))))
(defn- create-fns
"Create utility function for each digest algorithms.
For example will create an md5 function for MD5 algorithm."
[]
(doseq [algorithm (algorithms)]
(create-fn! algorithm)))
; Create utility functions such as md5, sha-256 ...
(create-fns)
;;;; Hints for clj-kondo
(comment
(declare sha3-384 sha-256 sha3-256 sha-384 sha3-512 sha-1 sha-224 sha1 sha-512 md2 sha sha3-224 md5)
)