35628
|
1 |
(* Title: Pure/General/sha1.ML
|
|
2 |
Author: Makarius
|
|
3 |
|
|
4 |
Digesting strings according to SHA-1 (see RFC 3174) -- relatively slow
|
|
5 |
version in pure ML.
|
|
6 |
*)
|
|
7 |
|
|
8 |
signature SHA1 =
|
|
9 |
sig
|
41954
|
10 |
eqtype digest
|
|
11 |
val digest: string -> digest
|
|
12 |
val rep: digest -> string
|
35628
|
13 |
end;
|
|
14 |
|
|
15 |
structure SHA1: SHA1 =
|
|
16 |
struct
|
|
17 |
|
|
18 |
(* 32bit words *)
|
|
19 |
|
|
20 |
infix 4 << >>;
|
|
21 |
infix 3 andb;
|
|
22 |
infix 2 orb xorb;
|
|
23 |
|
|
24 |
val op << = Word32.<<;
|
|
25 |
val op >> = Word32.>>;
|
|
26 |
val op andb = Word32.andb;
|
|
27 |
val op orb = Word32.orb;
|
|
28 |
val op xorb = Word32.xorb;
|
|
29 |
val notb = Word32.notb;
|
|
30 |
|
|
31 |
fun rotate k w = w << k orb w >> (0w32 - k);
|
|
32 |
|
|
33 |
|
|
34 |
(* hexadecimal words *)
|
|
35 |
|
|
36 |
fun hex_digit (text, w: Word32.word) =
|
|
37 |
let
|
|
38 |
val d = Word32.toInt (w andb 0wxf);
|
|
39 |
val dig = if d < 10 then chr (ord "0" + d) else chr (ord "a" + d - 10);
|
|
40 |
in (dig ^ text, w >> 0w4) end;
|
|
41 |
|
|
42 |
fun hex_word w = #1 (funpow 8 hex_digit ("", w));
|
|
43 |
|
|
44 |
|
|
45 |
(* padding *)
|
|
46 |
|
|
47 |
fun pack_bytes 0 n = ""
|
|
48 |
| pack_bytes k n = pack_bytes (k - 1) (n div 256) ^ chr (n mod 256);
|
|
49 |
|
|
50 |
fun padded_text str =
|
|
51 |
let
|
|
52 |
val len = size str;
|
|
53 |
val padding = chr 128 ^ replicate_string (~ (len + 9) mod 64) (chr 0) ^ pack_bytes 8 (len * 8);
|
|
54 |
fun byte i = Char.ord (String.sub (if i < len then (str, i) else (padding, (i - len))));
|
|
55 |
fun word i =
|
|
56 |
Word32.fromInt (byte (4 * i)) << 0w24 orb
|
|
57 |
Word32.fromInt (byte (4 * i + 1)) << 0w16 orb
|
|
58 |
Word32.fromInt (byte (4 * i + 2)) << 0w8 orb
|
|
59 |
Word32.fromInt (byte (4 * i + 3));
|
|
60 |
in ((len + size padding) div 4, word) end;
|
|
61 |
|
|
62 |
|
41954
|
63 |
(* digest_string *)
|
35628
|
64 |
|
|
65 |
fun digest_word (i, w, {a, b, c, d, e}) =
|
|
66 |
let
|
|
67 |
val {f, k} =
|
|
68 |
if i < 20 then
|
|
69 |
{f = (b andb c) orb (notb b andb d),
|
|
70 |
k = 0wx5A827999}
|
|
71 |
else if i < 40 then
|
|
72 |
{f = b xorb c xorb d,
|
|
73 |
k = 0wx6ED9EBA1}
|
|
74 |
else if i < 60 then
|
|
75 |
{f = (b andb c) orb (b andb d) orb (c andb d),
|
|
76 |
k = 0wx8F1BBCDC}
|
|
77 |
else
|
|
78 |
{f = b xorb c xorb d,
|
|
79 |
k = 0wxCA62C1D6};
|
|
80 |
val op + = Word32.+;
|
|
81 |
in
|
|
82 |
{a = rotate 0w5 a + f + e + w + k,
|
|
83 |
b = a,
|
|
84 |
c = rotate 0w30 b,
|
|
85 |
d = c,
|
|
86 |
e = d}
|
|
87 |
end;
|
|
88 |
|
41954
|
89 |
fun digest_string str =
|
35628
|
90 |
let
|
|
91 |
val (text_len, text) = padded_text str;
|
|
92 |
|
|
93 |
(*hash result -- 5 words*)
|
|
94 |
val hash_array : Word32.word Array.array =
|
|
95 |
Array.fromList [0wx67452301, 0wxEFCDAB89, 0wx98BADCFE, 0wx10325476, 0wxC3D2E1F0];
|
|
96 |
fun hash i = Array.sub (hash_array, i);
|
|
97 |
fun add_hash x i = Array.update (hash_array, i, hash i + x);
|
|
98 |
|
|
99 |
(*current chunk -- 80 words*)
|
|
100 |
val chunk_array = Array.array (80, 0w0: Word32.word);
|
|
101 |
fun chunk i = Array.sub (chunk_array, i);
|
|
102 |
fun init_chunk pos =
|
|
103 |
Array.modifyi (fn (i, _) =>
|
|
104 |
if i < 16 then text (pos + i)
|
|
105 |
else rotate 0w1 (chunk (i - 3) xorb chunk (i - 8) xorb chunk (i - 14) xorb chunk (i - 16)))
|
|
106 |
chunk_array;
|
|
107 |
|
|
108 |
fun digest_chunks pos =
|
|
109 |
if pos < text_len then
|
|
110 |
let
|
|
111 |
val _ = init_chunk pos;
|
|
112 |
val {a, b, c, d, e} = Array.foldli digest_word
|
|
113 |
{a = hash 0,
|
|
114 |
b = hash 1,
|
|
115 |
c = hash 2,
|
|
116 |
d = hash 3,
|
|
117 |
e = hash 4}
|
|
118 |
chunk_array;
|
|
119 |
val _ = add_hash a 0;
|
|
120 |
val _ = add_hash b 1;
|
|
121 |
val _ = add_hash c 2;
|
|
122 |
val _ = add_hash d 3;
|
|
123 |
val _ = add_hash e 4;
|
|
124 |
in digest_chunks (pos + 16) end
|
|
125 |
else ();
|
|
126 |
val _ = digest_chunks 0;
|
|
127 |
|
|
128 |
val hex = hex_word o hash;
|
|
129 |
in hex 0 ^ hex 1 ^ hex 2 ^ hex 3 ^ hex 4 end;
|
|
130 |
|
41954
|
131 |
|
|
132 |
(* type digest *)
|
|
133 |
|
|
134 |
datatype digest = Digest of string;
|
|
135 |
|
|
136 |
val digest = Digest o digest_string;
|
|
137 |
fun rep (Digest s) = s;
|
|
138 |
|
35628
|
139 |
end;
|