]> git.ipfire.org Git - thirdparty/gcc.git/blame - libphobos/src/std/digest/sha.d
Add D front-end, libphobos library, and D2 testsuite.
[thirdparty/gcc.git] / libphobos / src / std / digest / sha.d
CommitLineData
b4c522fa
IB
1// Written in the D programming language.
2/**
3 * Computes SHA1 and SHA2 hashes of arbitrary data. SHA hashes are 20 to 64 byte
4 * quantities (depending on the SHA algorithm) that are like a checksum or CRC,
5 * but are more robust.
6 *
7$(SCRIPT inhibitQuickIndex = 1;)
8
9$(DIVC quickindex,
10$(BOOKTABLE ,
11$(TR $(TH Category) $(TH Functions)
12)
13$(TR $(TDNW Template API) $(TD $(MYREF SHA1)
14)
15)
16$(TR $(TDNW OOP API) $(TD $(MYREF SHA1Digest))
17)
18$(TR $(TDNW Helpers) $(TD $(MYREF sha1Of))
19)
20)
21)
22
23 * SHA2 comes in several different versions, all supported by this module:
24 * SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224 and SHA-512/256.
25 *
26 * This module conforms to the APIs defined in $(MREF std, digest). To understand the
27 * differences between the template and the OOP API, see $(MREF std, digest).
28 *
29 * This module publicly imports $(D std.digest) and can be used as a stand-alone
30 * module.
31 *
32 * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
33 *
34 * CTFE:
35 * Digests do not work in CTFE
36 *
37 * Authors:
38 * The routines and algorithms are derived from the
39 * $(I Secure Hash Signature Standard (SHS) (FIPS PUB 180-2)). $(BR )
40 * Kai Nacke, Johannes Pfau, Nick Sabalausky
41 *
42 * References:
43 * $(UL
44 * $(LI $(LINK2 http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf, FIPS PUB180-2))
45 * $(LI $(LINK2 http://software.intel.com/en-us/articles/improving-the-performance-of-the-secure-hash-algorithm-1/, Fast implementation of SHA1))
46 * $(LI $(LINK2 http://en.wikipedia.org/wiki/Secure_Hash_Algorithm, Wikipedia article about SHA))
47 * )
48 *
49 * Source: $(PHOBOSSRC std/digest/_sha.d)
50 *
51 */
52
53/* Copyright Kai Nacke 2012.
54 * Distributed under the Boost Software License, Version 1.0.
55 * (See accompanying file LICENSE_1_0.txt or copy at
56 * http://www.boost.org/LICENSE_1_0.txt)
57 */
58module std.digest.sha;
59
60///
61@safe unittest
62{
63 //Template API
64 import std.digest.sha;
65
66 ubyte[20] hash1 = sha1Of("abc");
67 assert(toHexString(hash1) == "A9993E364706816ABA3E25717850C26C9CD0D89D");
68
69 ubyte[28] hash224 = sha224Of("abc");
70 assert(toHexString(hash224) == "23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7");
71
72 //Feeding data
73 ubyte[1024] data;
74 SHA1 sha1;
75 sha1.start();
76 sha1.put(data[]);
77 sha1.start(); //Start again
78 sha1.put(data[]);
79 hash1 = sha1.finish();
80}
81
82///
83@safe unittest
84{
85 //OOP API
86 import std.digest.sha;
87
88 auto sha1 = new SHA1Digest();
89 ubyte[] hash1 = sha1.digest("abc");
90 assert(toHexString(hash1) == "A9993E364706816ABA3E25717850C26C9CD0D89D");
91
92 auto sha224 = new SHA224Digest();
93 ubyte[] hash224 = sha224.digest("abc");
94 assert(toHexString(hash224) == "23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7");
95
96 //Feeding data
97 ubyte[1024] data;
98 sha1.put(data[]);
99 sha1.reset(); //Start again
100 sha1.put(data[]);
101 hash1 = sha1.finish();
102}
103
104version (Win64)
105{
106 // wrong calling convention
107}
108else version (D_InlineAsm_X86)
109{
110 version (D_PIC) {} // Bugzilla 9378
111 else private version = USE_SSSE3;
112}
113else version (D_InlineAsm_X86_64)
114{
115 private version = USE_SSSE3;
116}
117
118version (LittleEndian) import core.bitop : bswap;
119
120
121version (unittest)
122{
123 import std.exception;
124}
125
126
127public import std.digest;
128
129/*
130 * Helper methods for encoding the buffer.
131 * Can be removed if the optimizer can inline the methods from std.bitmanip.
132 */
133private ubyte[8] nativeToBigEndian(ulong val) @trusted pure nothrow @nogc
134{
135 version (LittleEndian)
136 immutable ulong res = (cast(ulong) bswap(cast(uint) val)) << 32 | bswap(cast(uint) (val >> 32));
137 else
138 immutable ulong res = val;
139 return *cast(ubyte[8]*) &res;
140}
141
142private ubyte[4] nativeToBigEndian(uint val) @trusted pure nothrow @nogc
143{
144 version (LittleEndian)
145 immutable uint res = bswap(val);
146 else
147 immutable uint res = val;
148 return *cast(ubyte[4]*) &res;
149}
150
151private ulong bigEndianToNative(ubyte[8] val) @trusted pure nothrow @nogc
152{
153 version (LittleEndian)
154 {
155 import std.bitmanip : bigEndianToNative;
156 return bigEndianToNative!ulong(val);
157 }
158 else
159 return *cast(ulong*) &val;
160}
161
162private uint bigEndianToNative(ubyte[4] val) @trusted pure nothrow @nogc
163{
164 version (LittleEndian)
165 return bswap(*cast(uint*) &val);
166 else
167 return *cast(uint*) &val;
168}
169
170//rotateLeft rotates x left n bits
171private uint rotateLeft(uint x, uint n) @safe pure nothrow @nogc
172{
173 // With recently added optimization to DMD (commit 32ea0206 at 07/28/11), this is translated to rol.
174 // No assembler required.
175 return (x << n) | (x >> (32-n));
176}
177
178//rotateRight rotates x right n bits
179private uint rotateRight(uint x, uint n) @safe pure nothrow @nogc
180{
181 return (x >> n) | (x << (32-n));
182}
183private ulong rotateRight(ulong x, uint n) @safe pure nothrow @nogc
184{
185 return (x >> n) | (x << (64-n));
186}
187
188/**
189 * Template API SHA1/SHA2 implementation. Supports: SHA-1, SHA-224, SHA-256,
190 * SHA-384, SHA-512, SHA-512/224 and SHA-512/256.
191 *
192 * The hashBlockSize and digestSize are in bits. However, it's likely easier to
193 * simply use the convenience aliases: SHA1, SHA224, SHA256, SHA384, SHA512,
194 * SHA512_224 and SHA512_256.
195 *
196 * See $(D std.digest) for differences between template and OOP API.
197 */
198struct SHA(uint hashBlockSize, uint digestSize)
199{
200 enum blockSize = hashBlockSize;
201
202 static assert(blockSize == 512 || blockSize == 1024,
203 "Invalid SHA blockSize, must be 512 or 1024");
204 static assert(digestSize == 160 || digestSize == 224 || digestSize == 256 || digestSize == 384 || digestSize == 512,
205 "Invalid SHA digestSize, must be 224, 256, 384 or 512");
206 static assert(!(blockSize == 512 && digestSize > 256),
207 "Invalid SHA digestSize for a blockSize of 512. The digestSize must be 160, 224 or 256.");
208 static assert(!(blockSize == 1024 && digestSize < 224),
209 "Invalid SHA digestSize for a blockSize of 1024. The digestSize must be 224, 256, 384 or 512.");
210
211 static if (digestSize == 160) /* SHA-1 */
212 {
213 version (USE_SSSE3)
214 {
215 import core.cpuid : ssse3;
216 import std.internal.digest.sha_SSSE3 : sse3_constants=constants, transformSSSE3;
217
218 static void transform(uint[5]* state, const(ubyte[64])* block) pure nothrow @nogc
219 {
220 if (ssse3)
221 {
222 version (D_InlineAsm_X86_64)
223 // constants as extra argument for PIC, see Bugzilla 9378
224 transformSSSE3(state, block, &sse3_constants);
225 else
226 transformSSSE3(state, block);
227 }
228 else
229 transformX86(state, block);
230 }
231 }
232 else
233 {
234 alias transform = transformX86;
235 }
236 }
237 else static if (blockSize == 512) /* SHA-224, SHA-256 */
238 alias transform = transformSHA2!uint;
239 else static if (blockSize == 1024) /* SHA-384, SHA-512, SHA-512/224, SHA-512/256 */
240 alias transform = transformSHA2!ulong;
241 else
242 static assert(0);
243
244 private:
245 /* magic initialization constants - state (ABCDEFGH) */
246 static if (blockSize == 512 && digestSize == 160) /* SHA-1 */
247 {
248 uint[5] state =
249 [0x67452301,0xefcdab89,0x98badcfe,0x10325476,0xc3d2e1f0];
250 }
251 else static if (blockSize == 512 && digestSize == 224) /* SHA-224 */
252 {
253 uint[8] state = [
254 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
255 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4,
256 ];
257 }
258 else static if (blockSize == 512 && digestSize == 256) /* SHA-256 */
259 {
260 uint[8] state = [
261 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
262 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
263 ];
264 }
265 else static if (blockSize == 1024 && digestSize == 224) /* SHA-512/224 */
266 {
267 ulong[8] state = [
268 0x8C3D37C8_19544DA2, 0x73E19966_89DCD4D6,
269 0x1DFAB7AE_32FF9C82, 0x679DD514_582F9FCF,
270 0x0F6D2B69_7BD44DA8, 0x77E36F73_04C48942,
271 0x3F9D85A8_6A1D36C8, 0x1112E6AD_91D692A1,
272 ];
273 }
274 else static if (blockSize == 1024 && digestSize == 256) /* SHA-512/256 */
275 {
276 ulong[8] state = [
277 0x22312194_FC2BF72C, 0x9F555FA3_C84C64C2,
278 0x2393B86B_6F53B151, 0x96387719_5940EABD,
279 0x96283EE2_A88EFFE3, 0xBE5E1E25_53863992,
280 0x2B0199FC_2C85B8AA, 0x0EB72DDC_81C52CA2,
281 ];
282 }
283 else static if (blockSize == 1024 && digestSize == 384) /* SHA-384 */
284 {
285 ulong[8] state = [
286 0xcbbb9d5d_c1059ed8, 0x629a292a_367cd507,
287 0x9159015a_3070dd17, 0x152fecd8_f70e5939,
288 0x67332667_ffc00b31, 0x8eb44a87_68581511,
289 0xdb0c2e0d_64f98fa7, 0x47b5481d_befa4fa4,
290 ];
291 }
292 else static if (blockSize == 1024 && digestSize == 512) /* SHA-512 */
293 {
294 ulong[8] state = [
295 0x6a09e667_f3bcc908, 0xbb67ae85_84caa73b,
296 0x3c6ef372_fe94f82b, 0xa54ff53a_5f1d36f1,
297 0x510e527f_ade682d1, 0x9b05688c_2b3e6c1f,
298 0x1f83d9ab_fb41bd6b, 0x5be0cd19_137e2179,
299 ];
300 }
301 else
302 static assert(0);
303
304 /* constants */
305 static if (blockSize == 512)
306 {
307 static immutable uint[64] constants = [
308 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
309 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
310 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
311 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
312 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
313 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
314 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
315 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
316 ];
317 }
318 else static if (blockSize == 1024)
319 {
320 static immutable ulong[80] constants = [
321 0x428a2f98_d728ae22, 0x71374491_23ef65cd, 0xb5c0fbcf_ec4d3b2f, 0xe9b5dba5_8189dbbc,
322 0x3956c25b_f348b538, 0x59f111f1_b605d019, 0x923f82a4_af194f9b, 0xab1c5ed5_da6d8118,
323 0xd807aa98_a3030242, 0x12835b01_45706fbe, 0x243185be_4ee4b28c, 0x550c7dc3_d5ffb4e2,
324 0x72be5d74_f27b896f, 0x80deb1fe_3b1696b1, 0x9bdc06a7_25c71235, 0xc19bf174_cf692694,
325 0xe49b69c1_9ef14ad2, 0xefbe4786_384f25e3, 0x0fc19dc6_8b8cd5b5, 0x240ca1cc_77ac9c65,
326 0x2de92c6f_592b0275, 0x4a7484aa_6ea6e483, 0x5cb0a9dc_bd41fbd4, 0x76f988da_831153b5,
327 0x983e5152_ee66dfab, 0xa831c66d_2db43210, 0xb00327c8_98fb213f, 0xbf597fc7_beef0ee4,
328 0xc6e00bf3_3da88fc2, 0xd5a79147_930aa725, 0x06ca6351_e003826f, 0x14292967_0a0e6e70,
329 0x27b70a85_46d22ffc, 0x2e1b2138_5c26c926, 0x4d2c6dfc_5ac42aed, 0x53380d13_9d95b3df,
330 0x650a7354_8baf63de, 0x766a0abb_3c77b2a8, 0x81c2c92e_47edaee6, 0x92722c85_1482353b,
331 0xa2bfe8a1_4cf10364, 0xa81a664b_bc423001, 0xc24b8b70_d0f89791, 0xc76c51a3_0654be30,
332 0xd192e819_d6ef5218, 0xd6990624_5565a910, 0xf40e3585_5771202a, 0x106aa070_32bbd1b8,
333 0x19a4c116_b8d2d0c8, 0x1e376c08_5141ab53, 0x2748774c_df8eeb99, 0x34b0bcb5_e19b48a8,
334 0x391c0cb3_c5c95a63, 0x4ed8aa4a_e3418acb, 0x5b9cca4f_7763e373, 0x682e6ff3_d6b2b8a3,
335 0x748f82ee_5defb2fc, 0x78a5636f_43172f60, 0x84c87814_a1f0ab72, 0x8cc70208_1a6439ec,
336 0x90befffa_23631e28, 0xa4506ceb_de82bde9, 0xbef9a3f7_b2c67915, 0xc67178f2_e372532b,
337 0xca273ece_ea26619c, 0xd186b8c7_21c0c207, 0xeada7dd6_cde0eb1e, 0xf57d4f7f_ee6ed178,
338 0x06f067aa_72176fba, 0x0a637dc5_a2c898a6, 0x113f9804_bef90dae, 0x1b710b35_131c471b,
339 0x28db77f5_23047d84, 0x32caab7b_40c72493, 0x3c9ebe0a_15c9bebc, 0x431d67c4_9c100d4c,
340 0x4cc5d4be_cb3e42b6, 0x597f299c_fc657e2a, 0x5fcb6fab_3ad6faec, 0x6c44198c_4a475817,
341 ];
342 }
343 else
344 static assert(0);
345
346 /*
347 * number of bits, modulo 2^64 (ulong[1]) or 2^128 (ulong[2]),
348 * should just use ucent instead of ulong[2] once it's available
349 */
350 ulong[blockSize/512] count;
351 ubyte[blockSize/8] buffer; /* input buffer */
352
353 static immutable ubyte[128] padding =
354 [
355 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
356 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
357 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
358
359 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
360 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
361 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
362 ];
363
364 /*
365 * Basic SHA1/SHA2 functions.
366 */
367 static @safe pure nothrow @nogc
368 {
369 /* All SHA1/SHA2 */
370 T Ch(T)(T x, T y, T z) { return z ^ (x & (y ^ z)); }
371 T Maj(T)(T x, T y, T z) { return (x & y) | (z & (x ^ y)); }
372
373 /* SHA-1 */
374 uint Parity(uint x, uint y, uint z) { return x ^ y ^ z; }
375
376 /* SHA-224, SHA-256 */
377 uint BigSigma0(uint x) { return rotateRight(x, 2) ^ rotateRight(x, 13) ^ rotateRight(x, 22); }
378 uint BigSigma1(uint x) { return rotateRight(x, 6) ^ rotateRight(x, 11) ^ rotateRight(x, 25); }
379 uint SmSigma0(uint x) { return rotateRight(x, 7) ^ rotateRight(x, 18) ^ x >> 3; }
380 uint SmSigma1(uint x) { return rotateRight(x, 17) ^ rotateRight(x, 19) ^ x >> 10; }
381
382 /* SHA-384, SHA-512, SHA-512/224, SHA-512/256 */
383 ulong BigSigma0(ulong x) { return rotateRight(x, 28) ^ rotateRight(x, 34) ^ rotateRight(x, 39); }
384 ulong BigSigma1(ulong x) { return rotateRight(x, 14) ^ rotateRight(x, 18) ^ rotateRight(x, 41); }
385 ulong SmSigma0(ulong x) { return rotateRight(x, 1) ^ rotateRight(x, 8) ^ x >> 7; }
386 ulong SmSigma1(ulong x) { return rotateRight(x, 19) ^ rotateRight(x, 61) ^ x >> 6; }
387 }
388
389 /*
390 * SHA1 basic transformation. Transforms state based on block.
391 */
392 static void T_0_15(int i, const(ubyte[64])* input, ref uint[16] W, uint A, ref uint B, uint C, uint D,
393 uint E, ref uint T) pure nothrow @nogc
394 {
395 uint Wi = W[i] = bigEndianToNative(*cast(ubyte[4]*)&((*input)[i*4]));
396 T = Ch(B, C, D) + E + rotateLeft(A, 5) + Wi + 0x5a827999;
397 B = rotateLeft(B, 30);
398 }
399
400 static void T_16_19(int i, ref uint[16] W, uint A, ref uint B, uint C, uint D, uint E, ref uint T)
401 pure nothrow @nogc
402 {
403 W[i&15] = rotateLeft(W[(i-3)&15] ^ W[(i-8)&15] ^ W[(i-14)&15] ^ W[(i-16)&15], 1);
404 T = Ch(B, C, D) + E + rotateLeft(A, 5) + W[i&15] + 0x5a827999;
405 B = rotateLeft(B, 30);
406 }
407
408 static void T_20_39(int i, ref uint[16] W, uint A, ref uint B, uint C, uint D, uint E,
409 ref uint T) pure nothrow @nogc
410 {
411 W[i&15] = rotateLeft(W[(i-3)&15] ^ W[(i-8)&15] ^ W[(i-14)&15] ^ W[(i-16)&15], 1);
412 T = Parity(B, C, D) + E + rotateLeft(A, 5) + W[i&15] + 0x6ed9eba1;
413 B = rotateLeft(B, 30);
414 }
415
416 static void T_40_59(int i, ref uint[16] W, uint A, ref uint B, uint C, uint D, uint E,
417 ref uint T) pure nothrow @nogc
418 {
419 W[i&15] = rotateLeft(W[(i-3)&15] ^ W[(i-8)&15] ^ W[(i-14)&15] ^ W[(i-16)&15], 1);
420 T = Maj(B, C, D) + E + rotateLeft(A, 5) + W[i&15] + 0x8f1bbcdc;
421 B = rotateLeft(B, 30);
422 }
423
424 static void T_60_79(int i, ref uint[16] W, uint A, ref uint B, uint C, uint D, uint E,
425 ref uint T) pure nothrow @nogc
426 {
427 W[i&15] = rotateLeft(W[(i-3)&15] ^ W[(i-8)&15] ^ W[(i-14)&15] ^ W[(i-16)&15], 1);
428 T = Parity(B, C, D) + E + rotateLeft(A, 5) + W[i&15] + 0xca62c1d6;
429 B = rotateLeft(B, 30);
430 }
431
432 private static void transformX86(uint[5]* state, const(ubyte[64])* block) pure nothrow @nogc
433 {
434 uint A, B, C, D, E, T;
435 uint[16] W = void;
436
437 A = (*state)[0];
438 B = (*state)[1];
439 C = (*state)[2];
440 D = (*state)[3];
441 E = (*state)[4];
442
443 T_0_15 ( 0, block, W, A, B, C, D, E, T);
444 T_0_15 ( 1, block, W, T, A, B, C, D, E);
445 T_0_15 ( 2, block, W, E, T, A, B, C, D);
446 T_0_15 ( 3, block, W, D, E, T, A, B, C);
447 T_0_15 ( 4, block, W, C, D, E, T, A, B);
448 T_0_15 ( 5, block, W, B, C, D, E, T, A);
449 T_0_15 ( 6, block, W, A, B, C, D, E, T);
450 T_0_15 ( 7, block, W, T, A, B, C, D, E);
451 T_0_15 ( 8, block, W, E, T, A, B, C, D);
452 T_0_15 ( 9, block, W, D, E, T, A, B, C);
453 T_0_15 (10, block, W, C, D, E, T, A, B);
454 T_0_15 (11, block, W, B, C, D, E, T, A);
455 T_0_15 (12, block, W, A, B, C, D, E, T);
456 T_0_15 (13, block, W, T, A, B, C, D, E);
457 T_0_15 (14, block, W, E, T, A, B, C, D);
458 T_0_15 (15, block, W, D, E, T, A, B, C);
459 T_16_19(16, W, C, D, E, T, A, B);
460 T_16_19(17, W, B, C, D, E, T, A);
461 T_16_19(18, W, A, B, C, D, E, T);
462 T_16_19(19, W, T, A, B, C, D, E);
463 T_20_39(20, W, E, T, A, B, C, D);
464 T_20_39(21, W, D, E, T, A, B, C);
465 T_20_39(22, W, C, D, E, T, A, B);
466 T_20_39(23, W, B, C, D, E, T, A);
467 T_20_39(24, W, A, B, C, D, E, T);
468 T_20_39(25, W, T, A, B, C, D, E);
469 T_20_39(26, W, E, T, A, B, C, D);
470 T_20_39(27, W, D, E, T, A, B, C);
471 T_20_39(28, W, C, D, E, T, A, B);
472 T_20_39(29, W, B, C, D, E, T, A);
473 T_20_39(30, W, A, B, C, D, E, T);
474 T_20_39(31, W, T, A, B, C, D, E);
475 T_20_39(32, W, E, T, A, B, C, D);
476 T_20_39(33, W, D, E, T, A, B, C);
477 T_20_39(34, W, C, D, E, T, A, B);
478 T_20_39(35, W, B, C, D, E, T, A);
479 T_20_39(36, W, A, B, C, D, E, T);
480 T_20_39(37, W, T, A, B, C, D, E);
481 T_20_39(38, W, E, T, A, B, C, D);
482 T_20_39(39, W, D, E, T, A, B, C);
483 T_40_59(40, W, C, D, E, T, A, B);
484 T_40_59(41, W, B, C, D, E, T, A);
485 T_40_59(42, W, A, B, C, D, E, T);
486 T_40_59(43, W, T, A, B, C, D, E);
487 T_40_59(44, W, E, T, A, B, C, D);
488 T_40_59(45, W, D, E, T, A, B, C);
489 T_40_59(46, W, C, D, E, T, A, B);
490 T_40_59(47, W, B, C, D, E, T, A);
491 T_40_59(48, W, A, B, C, D, E, T);
492 T_40_59(49, W, T, A, B, C, D, E);
493 T_40_59(50, W, E, T, A, B, C, D);
494 T_40_59(51, W, D, E, T, A, B, C);
495 T_40_59(52, W, C, D, E, T, A, B);
496 T_40_59(53, W, B, C, D, E, T, A);
497 T_40_59(54, W, A, B, C, D, E, T);
498 T_40_59(55, W, T, A, B, C, D, E);
499 T_40_59(56, W, E, T, A, B, C, D);
500 T_40_59(57, W, D, E, T, A, B, C);
501 T_40_59(58, W, C, D, E, T, A, B);
502 T_40_59(59, W, B, C, D, E, T, A);
503 T_60_79(60, W, A, B, C, D, E, T);
504 T_60_79(61, W, T, A, B, C, D, E);
505 T_60_79(62, W, E, T, A, B, C, D);
506 T_60_79(63, W, D, E, T, A, B, C);
507 T_60_79(64, W, C, D, E, T, A, B);
508 T_60_79(65, W, B, C, D, E, T, A);
509 T_60_79(66, W, A, B, C, D, E, T);
510 T_60_79(67, W, T, A, B, C, D, E);
511 T_60_79(68, W, E, T, A, B, C, D);
512 T_60_79(69, W, D, E, T, A, B, C);
513 T_60_79(70, W, C, D, E, T, A, B);
514 T_60_79(71, W, B, C, D, E, T, A);
515 T_60_79(72, W, A, B, C, D, E, T);
516 T_60_79(73, W, T, A, B, C, D, E);
517 T_60_79(74, W, E, T, A, B, C, D);
518 T_60_79(75, W, D, E, T, A, B, C);
519 T_60_79(76, W, C, D, E, T, A, B);
520 T_60_79(77, W, B, C, D, E, T, A);
521 T_60_79(78, W, A, B, C, D, E, T);
522 T_60_79(79, W, T, A, B, C, D, E);
523
524 (*state)[0] += E;
525 (*state)[1] += T;
526 (*state)[2] += A;
527 (*state)[3] += B;
528 (*state)[4] += C;
529
530 /* Zeroize sensitive information. */
531 W[] = 0;
532 }
533
534 /*
535 * SHA2 basic transformation. Transforms state based on block.
536 */
537 static void T_SHA2_0_15(Word)(int i, const(ubyte[blockSize/8])* input, ref Word[16] W,
538 Word A, Word B, Word C, ref Word D, Word E, Word F, Word G, ref Word H, Word K)
539 pure nothrow @nogc
540 {
541 Word Wi = W[i] = bigEndianToNative(*cast(ubyte[Word.sizeof]*)&((*input)[i*Word.sizeof]));
542 Word T1 = H + BigSigma1(E) + Ch(E, F, G) + K + Wi;
543 Word T2 = BigSigma0(A) + Maj(A, B, C);
544 D += T1;
545 H = T1 + T2;
546 }
547
548 static void T_SHA2_16_79(Word)(int i, ref Word[16] W,
549 Word A, Word B, Word C, ref Word D, Word E, Word F, Word G, ref Word H, Word K)
550 pure nothrow @nogc
551 {
552 W[i&15] = SmSigma1(W[(i-2)&15]) + W[(i-7)&15] + SmSigma0(W[(i-15)&15]) + W[i&15];
553 Word T1 = H + BigSigma1(E) + Ch(E, F, G) + K + W[i&15];
554 Word T2 = BigSigma0(A) + Maj(A, B, C);
555 D += T1;
556 H = T1 + T2;
557 }
558
559 private static void transformSHA2(Word)(Word[8]* state, const(ubyte[blockSize/8])* block)
560 pure nothrow @nogc
561 {
562 Word A, B, C, D, E, F, G, H;
563 Word[16] W = void;
564
565 A = (*state)[0];
566 B = (*state)[1];
567 C = (*state)[2];
568 D = (*state)[3];
569 E = (*state)[4];
570 F = (*state)[5];
571 G = (*state)[6];
572 H = (*state)[7];
573
574 T_SHA2_0_15!Word ( 0, block, W, A, B, C, D, E, F, G, H, constants[ 0]);
575 T_SHA2_0_15!Word ( 1, block, W, H, A, B, C, D, E, F, G, constants[ 1]);
576 T_SHA2_0_15!Word ( 2, block, W, G, H, A, B, C, D, E, F, constants[ 2]);
577 T_SHA2_0_15!Word ( 3, block, W, F, G, H, A, B, C, D, E, constants[ 3]);
578 T_SHA2_0_15!Word ( 4, block, W, E, F, G, H, A, B, C, D, constants[ 4]);
579 T_SHA2_0_15!Word ( 5, block, W, D, E, F, G, H, A, B, C, constants[ 5]);
580 T_SHA2_0_15!Word ( 6, block, W, C, D, E, F, G, H, A, B, constants[ 6]);
581 T_SHA2_0_15!Word ( 7, block, W, B, C, D, E, F, G, H, A, constants[ 7]);
582 T_SHA2_0_15!Word ( 8, block, W, A, B, C, D, E, F, G, H, constants[ 8]);
583 T_SHA2_0_15!Word ( 9, block, W, H, A, B, C, D, E, F, G, constants[ 9]);
584 T_SHA2_0_15!Word (10, block, W, G, H, A, B, C, D, E, F, constants[10]);
585 T_SHA2_0_15!Word (11, block, W, F, G, H, A, B, C, D, E, constants[11]);
586 T_SHA2_0_15!Word (12, block, W, E, F, G, H, A, B, C, D, constants[12]);
587 T_SHA2_0_15!Word (13, block, W, D, E, F, G, H, A, B, C, constants[13]);
588 T_SHA2_0_15!Word (14, block, W, C, D, E, F, G, H, A, B, constants[14]);
589 T_SHA2_0_15!Word (15, block, W, B, C, D, E, F, G, H, A, constants[15]);
590 T_SHA2_16_79!Word(16, W, A, B, C, D, E, F, G, H, constants[16]);
591 T_SHA2_16_79!Word(17, W, H, A, B, C, D, E, F, G, constants[17]);
592 T_SHA2_16_79!Word(18, W, G, H, A, B, C, D, E, F, constants[18]);
593 T_SHA2_16_79!Word(19, W, F, G, H, A, B, C, D, E, constants[19]);
594 T_SHA2_16_79!Word(20, W, E, F, G, H, A, B, C, D, constants[20]);
595 T_SHA2_16_79!Word(21, W, D, E, F, G, H, A, B, C, constants[21]);
596 T_SHA2_16_79!Word(22, W, C, D, E, F, G, H, A, B, constants[22]);
597 T_SHA2_16_79!Word(23, W, B, C, D, E, F, G, H, A, constants[23]);
598 T_SHA2_16_79!Word(24, W, A, B, C, D, E, F, G, H, constants[24]);
599 T_SHA2_16_79!Word(25, W, H, A, B, C, D, E, F, G, constants[25]);
600 T_SHA2_16_79!Word(26, W, G, H, A, B, C, D, E, F, constants[26]);
601 T_SHA2_16_79!Word(27, W, F, G, H, A, B, C, D, E, constants[27]);
602 T_SHA2_16_79!Word(28, W, E, F, G, H, A, B, C, D, constants[28]);
603 T_SHA2_16_79!Word(29, W, D, E, F, G, H, A, B, C, constants[29]);
604 T_SHA2_16_79!Word(30, W, C, D, E, F, G, H, A, B, constants[30]);
605 T_SHA2_16_79!Word(31, W, B, C, D, E, F, G, H, A, constants[31]);
606 T_SHA2_16_79!Word(32, W, A, B, C, D, E, F, G, H, constants[32]);
607 T_SHA2_16_79!Word(33, W, H, A, B, C, D, E, F, G, constants[33]);
608 T_SHA2_16_79!Word(34, W, G, H, A, B, C, D, E, F, constants[34]);
609 T_SHA2_16_79!Word(35, W, F, G, H, A, B, C, D, E, constants[35]);
610 T_SHA2_16_79!Word(36, W, E, F, G, H, A, B, C, D, constants[36]);
611 T_SHA2_16_79!Word(37, W, D, E, F, G, H, A, B, C, constants[37]);
612 T_SHA2_16_79!Word(38, W, C, D, E, F, G, H, A, B, constants[38]);
613 T_SHA2_16_79!Word(39, W, B, C, D, E, F, G, H, A, constants[39]);
614 T_SHA2_16_79!Word(40, W, A, B, C, D, E, F, G, H, constants[40]);
615 T_SHA2_16_79!Word(41, W, H, A, B, C, D, E, F, G, constants[41]);
616 T_SHA2_16_79!Word(42, W, G, H, A, B, C, D, E, F, constants[42]);
617 T_SHA2_16_79!Word(43, W, F, G, H, A, B, C, D, E, constants[43]);
618 T_SHA2_16_79!Word(44, W, E, F, G, H, A, B, C, D, constants[44]);
619 T_SHA2_16_79!Word(45, W, D, E, F, G, H, A, B, C, constants[45]);
620 T_SHA2_16_79!Word(46, W, C, D, E, F, G, H, A, B, constants[46]);
621 T_SHA2_16_79!Word(47, W, B, C, D, E, F, G, H, A, constants[47]);
622 T_SHA2_16_79!Word(48, W, A, B, C, D, E, F, G, H, constants[48]);
623 T_SHA2_16_79!Word(49, W, H, A, B, C, D, E, F, G, constants[49]);
624 T_SHA2_16_79!Word(50, W, G, H, A, B, C, D, E, F, constants[50]);
625 T_SHA2_16_79!Word(51, W, F, G, H, A, B, C, D, E, constants[51]);
626 T_SHA2_16_79!Word(52, W, E, F, G, H, A, B, C, D, constants[52]);
627 T_SHA2_16_79!Word(53, W, D, E, F, G, H, A, B, C, constants[53]);
628 T_SHA2_16_79!Word(54, W, C, D, E, F, G, H, A, B, constants[54]);
629 T_SHA2_16_79!Word(55, W, B, C, D, E, F, G, H, A, constants[55]);
630 T_SHA2_16_79!Word(56, W, A, B, C, D, E, F, G, H, constants[56]);
631 T_SHA2_16_79!Word(57, W, H, A, B, C, D, E, F, G, constants[57]);
632 T_SHA2_16_79!Word(58, W, G, H, A, B, C, D, E, F, constants[58]);
633 T_SHA2_16_79!Word(59, W, F, G, H, A, B, C, D, E, constants[59]);
634 T_SHA2_16_79!Word(60, W, E, F, G, H, A, B, C, D, constants[60]);
635 T_SHA2_16_79!Word(61, W, D, E, F, G, H, A, B, C, constants[61]);
636 T_SHA2_16_79!Word(62, W, C, D, E, F, G, H, A, B, constants[62]);
637 T_SHA2_16_79!Word(63, W, B, C, D, E, F, G, H, A, constants[63]);
638
639 static if (is(Word == ulong))
640 {
641 T_SHA2_16_79!Word(64, W, A, B, C, D, E, F, G, H, constants[64]);
642 T_SHA2_16_79!Word(65, W, H, A, B, C, D, E, F, G, constants[65]);
643 T_SHA2_16_79!Word(66, W, G, H, A, B, C, D, E, F, constants[66]);
644 T_SHA2_16_79!Word(67, W, F, G, H, A, B, C, D, E, constants[67]);
645 T_SHA2_16_79!Word(68, W, E, F, G, H, A, B, C, D, constants[68]);
646 T_SHA2_16_79!Word(69, W, D, E, F, G, H, A, B, C, constants[69]);
647 T_SHA2_16_79!Word(70, W, C, D, E, F, G, H, A, B, constants[70]);
648 T_SHA2_16_79!Word(71, W, B, C, D, E, F, G, H, A, constants[71]);
649 T_SHA2_16_79!Word(72, W, A, B, C, D, E, F, G, H, constants[72]);
650 T_SHA2_16_79!Word(73, W, H, A, B, C, D, E, F, G, constants[73]);
651 T_SHA2_16_79!Word(74, W, G, H, A, B, C, D, E, F, constants[74]);
652 T_SHA2_16_79!Word(75, W, F, G, H, A, B, C, D, E, constants[75]);
653 T_SHA2_16_79!Word(76, W, E, F, G, H, A, B, C, D, constants[76]);
654 T_SHA2_16_79!Word(77, W, D, E, F, G, H, A, B, C, constants[77]);
655 T_SHA2_16_79!Word(78, W, C, D, E, F, G, H, A, B, constants[78]);
656 T_SHA2_16_79!Word(79, W, B, C, D, E, F, G, H, A, constants[79]);
657 }
658
659 (*state)[0] += A;
660 (*state)[1] += B;
661 (*state)[2] += C;
662 (*state)[3] += D;
663 (*state)[4] += E;
664 (*state)[5] += F;
665 (*state)[6] += G;
666 (*state)[7] += H;
667
668 /* Zeroize sensitive information. */
669 W[] = 0;
670 }
671
672 public:
673 /**
674 * SHA initialization. Begins an SHA1/SHA2 operation.
675 *
676 * Note:
677 * For this SHA Digest implementation calling start after default construction
678 * is not necessary. Calling start is only necessary to reset the Digest.
679 *
680 * Generic code which deals with different Digest types should always call start though.
681 *
682 * Example:
683 * --------
684 * SHA1 digest;
685 * //digest.start(); //Not necessary
686 * digest.put(0);
687 * --------
688 */
689 void start() @safe pure nothrow @nogc
690 {
691 this = typeof(this).init;
692 }
693
694 /**
695 * Use this to feed the digest with data.
696 * Also implements the $(REF isOutputRange, std,range,primitives)
697 * interface for $(D ubyte) and $(D const(ubyte)[]).
698 */
699 void put(scope const(ubyte)[] input...) @trusted pure nothrow @nogc
700 {
701 enum blockSizeInBytes = blockSize/8;
702 uint i, index, partLen;
703 auto inputLen = input.length;
704
705 /* Compute number of bytes mod block size (64 or 128 bytes) */
706 index = (cast(uint) count[0] >> 3) & (blockSizeInBytes - 1);
707
708 /* Update number of bits */
709 static if (blockSize == 512)
710 count[0] += inputLen * 8;
711 else static if (blockSize == 1024)
712 {
713 /* ugly hack to work around lack of ucent */
714 auto oldCount0 = count[0];
715 count[0] += inputLen * 8;
716 if (count[0] < oldCount0)
717 count[1]++;
718 }
719 else
720 static assert(0);
721
722 partLen = blockSizeInBytes - index;
723
724 /* Transform as many times as possible. */
725 if (inputLen >= partLen)
726 {
727 (&buffer[index])[0 .. partLen] = input.ptr[0 .. partLen];
728 transform (&state, &buffer);
729
730 for (i = partLen; i + blockSizeInBytes-1 < inputLen; i += blockSizeInBytes)
731 transform(&state, cast(ubyte[blockSizeInBytes]*)(input.ptr + i));
732
733 index = 0;
734 }
735 else
736 i = 0;
737
738 /* Buffer remaining input */
739 if (inputLen - i)
740 (&buffer[index])[0 .. inputLen-i] = (&input[i])[0 .. inputLen-i];
741 }
742
743 @safe unittest
744 {
745 typeof(this) dig;
746 dig.put(cast(ubyte) 0); //single ubyte
747 dig.put(cast(ubyte) 0, cast(ubyte) 0); //variadic
748 ubyte[10] buf;
749 dig.put(buf); //buffer
750 }
751
752
753 /**
754 * Returns the finished SHA hash. This also calls $(LREF start) to
755 * reset the internal state.
756 */
757 ubyte[digestSize/8] finish() @trusted pure nothrow @nogc
758 {
759 static if (blockSize == 512)
760 {
761 ubyte[32] data = void;
762 uint index, padLen;
763
764 /* Save number of bits */
765 ubyte[8] bits = nativeToBigEndian(count[0]);
766
767 /* Pad out to 56 mod 64. */
768 index = (cast(uint) count[0] >> 3) & (64 - 1);
769 padLen = (index < 56) ? (56 - index) : (120 - index);
770 put(padding[0 .. padLen]);
771
772 /* Append length (before padding) */
773 put(bits);
774
775 /* Store state in digest */
776 for (auto i = 0; i < ((digestSize == 160)? 5 : 8); i++)
777 data[i*4..(i+1)*4] = nativeToBigEndian(state[i])[];
778
779 /* Zeroize sensitive information. */
780 start();
781 return data[0 .. digestSize/8];
782 }
783 else static if (blockSize == 1024)
784 {
785 ubyte[64] data = void;
786 uint index, padLen;
787
788 /* Save number of bits */
789 ubyte[16] bits;
790 bits[ 0 .. 8] = nativeToBigEndian(count[1]);
791 bits[8 .. 16] = nativeToBigEndian(count[0]);
792
793 /* Pad out to 112 mod 128. */
794 index = (cast(uint) count[0] >> 3) & (128 - 1);
795 padLen = (index < 112) ? (112 - index) : (240 - index);
796 put(padding[0 .. padLen]);
797
798 /* Append length (before padding) */
799 put(bits);
800
801 /* Store state in digest */
802 for (auto i = 0; i < 8; i++)
803 data[i*8..(i+1)*8] = nativeToBigEndian(state[i])[];
804
805 /* Zeroize sensitive information. */
806 start();
807 return data[0 .. digestSize/8];
808 }
809 else
810 static assert(0);
811 }
812 ///
813 @safe unittest
814 {
815 //Simple example
816 SHA1 hash;
817 hash.start();
818 hash.put(cast(ubyte) 0);
819 ubyte[20] result = hash.finish();
820 }
821}
822
823alias SHA1 = SHA!(512, 160); /// SHA alias for SHA-1, hash is ubyte[20]
824alias SHA224 = SHA!(512, 224); /// SHA alias for SHA-224, hash is ubyte[28]
825alias SHA256 = SHA!(512, 256); /// SHA alias for SHA-256, hash is ubyte[32]
826alias SHA384 = SHA!(1024, 384); /// SHA alias for SHA-384, hash is ubyte[48]
827alias SHA512 = SHA!(1024, 512); /// SHA alias for SHA-512, hash is ubyte[64]
828alias SHA512_224 = SHA!(1024, 224); /// SHA alias for SHA-512/224, hash is ubyte[28]
829alias SHA512_256 = SHA!(1024, 256); /// SHA alias for SHA-512/256, hash is ubyte[32]
830
831///
832@safe unittest
833{
834 //Simple example, hashing a string using sha1Of helper function
835 ubyte[20] hash = sha1Of("abc");
836 //Let's get a hash string
837 assert(toHexString(hash) == "A9993E364706816ABA3E25717850C26C9CD0D89D");
838
839 //The same, but using SHA-224
840 ubyte[28] hash224 = sha224Of("abc");
841 assert(toHexString(hash224) == "23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7");
842}
843
844///
845@safe unittest
846{
847 //Using the basic API
848 SHA1 hash;
849 hash.start();
850 ubyte[1024] data;
851 //Initialize data here...
852 hash.put(data);
853 ubyte[20] result = hash.finish();
854}
855
856///
857@safe unittest
858{
859 //Let's use the template features:
860 //Note: When passing a SHA1 to a function, it must be passed by reference!
861 void doSomething(T)(ref T hash)
862 if (isDigest!T)
863 {
864 hash.put(cast(ubyte) 0);
865 }
866 SHA1 sha;
867 sha.start();
868 doSomething(sha);
869 assert(toHexString(sha.finish()) == "5BA93C9DB0CFF93F52B521D7420E43F6EDA2784F");
870}
871
872@safe unittest
873{
874 assert(isDigest!SHA1);
875 assert(isDigest!SHA224);
876 assert(isDigest!SHA256);
877 assert(isDigest!SHA384);
878 assert(isDigest!SHA512);
879 assert(isDigest!SHA512_224);
880 assert(isDigest!SHA512_256);
881}
882
883@system unittest
884{
885 import std.conv : hexString;
886 import std.range;
887
888 ubyte[20] digest;
889 ubyte[28] digest224;
890 ubyte[32] digest256;
891 ubyte[48] digest384;
892 ubyte[64] digest512;
893 ubyte[28] digest512_224;
894 ubyte[32] digest512_256;
895
896 SHA1 sha;
897 sha.put(cast(ubyte[])"abcdef");
898 sha.start();
899 sha.put(cast(ubyte[])"");
900 assert(sha.finish() == cast(ubyte[]) x"da39a3ee5e6b4b0d3255bfef95601890afd80709");
901
902 SHA224 sha224;
903 sha224.put(cast(ubyte[])"abcdef");
904 sha224.start();
905 sha224.put(cast(ubyte[])"");
906 assert(sha224.finish() == cast(ubyte[]) x"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f");
907
908 SHA256 sha256;
909 sha256.put(cast(ubyte[])"abcdef");
910 sha256.start();
911 sha256.put(cast(ubyte[])"");
912 assert(sha256.finish() == cast(ubyte[]) x"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
913
914 SHA384 sha384;
915 sha384.put(cast(ubyte[])"abcdef");
916 sha384.start();
917 sha384.put(cast(ubyte[])"");
918 assert(sha384.finish() == cast(ubyte[]) hexString!("38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c"
919 ~"0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b"));
920
921 SHA512 sha512;
922 sha512.put(cast(ubyte[])"abcdef");
923 sha512.start();
924 sha512.put(cast(ubyte[])"");
925 assert(sha512.finish() == cast(ubyte[]) hexString!("cf83e1357eefb8bdf1542850d66d8007d620e4050b571"
926 ~"5dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"));
927
928 SHA512_224 sha512_224;
929 sha512_224.put(cast(ubyte[])"abcdef");
930 sha512_224.start();
931 sha512_224.put(cast(ubyte[])"");
932 assert(sha512_224.finish() == cast(ubyte[]) x"6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4");
933
934 SHA512_256 sha512_256;
935 sha512_256.put(cast(ubyte[])"abcdef");
936 sha512_256.start();
937 sha512_256.put(cast(ubyte[])"");
938 assert(sha512_256.finish() == cast(ubyte[]) x"c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a");
939
940 digest = sha1Of ("");
941 digest224 = sha224Of ("");
942 digest256 = sha256Of ("");
943 digest384 = sha384Of ("");
944 digest512 = sha512Of ("");
945 digest512_224 = sha512_224Of("");
946 digest512_256 = sha512_256Of("");
947 assert(digest == cast(ubyte[]) x"da39a3ee5e6b4b0d3255bfef95601890afd80709");
948 assert(digest224 == cast(ubyte[]) x"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f");
949 assert(digest256 == cast(ubyte[]) x"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
950 assert(digest384 == cast(ubyte[]) hexString!("38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c"
951 ~"0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b"));
952 assert(digest512 == cast(ubyte[]) hexString!("cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83"
953 ~"f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"));
954 assert(digest512_224 == cast(ubyte[]) x"6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4");
955 assert(digest512_256 == cast(ubyte[]) x"c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a");
956
957 digest = sha1Of ("a");
958 digest224 = sha224Of ("a");
959 digest256 = sha256Of ("a");
960 digest384 = sha384Of ("a");
961 digest512 = sha512Of ("a");
962 digest512_224 = sha512_224Of("a");
963 digest512_256 = sha512_256Of("a");
964 assert(digest == cast(ubyte[]) x"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8");
965 assert(digest224 == cast(ubyte[]) x"abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5");
966 assert(digest256 == cast(ubyte[]) x"ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb");
967 assert(digest384 == cast(ubyte[]) hexString!("54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9"
968 ~"cd697e85175033caa88e6d57bc35efae0b5afd3145f31"));
969 assert(digest512 == cast(ubyte[]) hexString!("1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05ab"
970 ~"c54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75"));
971 assert(digest512_224 == cast(ubyte[]) x"d5cdb9ccc769a5121d4175f2bfdd13d6310e0d3d361ea75d82108327");
972 assert(digest512_256 == cast(ubyte[]) x"455e518824bc0601f9fb858ff5c37d417d67c2f8e0df2babe4808858aea830f8");
973
974 digest = sha1Of ("abc");
975 digest224 = sha224Of ("abc");
976 digest256 = sha256Of ("abc");
977 digest384 = sha384Of ("abc");
978 digest512 = sha512Of ("abc");
979 digest512_224 = sha512_224Of("abc");
980 digest512_256 = sha512_256Of("abc");
981 assert(digest == cast(ubyte[]) x"a9993e364706816aba3e25717850c26c9cd0d89d");
982 assert(digest224 == cast(ubyte[]) x"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7");
983 assert(digest256 == cast(ubyte[]) x"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
984 assert(digest384 == cast(ubyte[]) hexString!("cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a"
985 ~"8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7"));
986 assert(digest512 == cast(ubyte[]) hexString!("ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9"
987 ~"eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"));
988 assert(digest512_224 == cast(ubyte[]) x"4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa");
989 assert(digest512_256 == cast(ubyte[]) x"53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23");
990
991 digest = sha1Of ("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
992 digest224 = sha224Of ("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
993 digest256 = sha256Of ("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
994 digest384 = sha384Of ("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
995 digest512 = sha512Of ("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
996 digest512_224 = sha512_224Of("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
997 digest512_256 = sha512_256Of("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
998 assert(digest == cast(ubyte[]) x"84983e441c3bd26ebaae4aa1f95129e5e54670f1");
999 assert(digest224 == cast(ubyte[]) x"75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525");
1000 assert(digest256 == cast(ubyte[]) x"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1");
1001 assert(digest384 == cast(ubyte[]) hexString!("3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe"
1002 ~"8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b"));
1003 assert(digest512 == cast(ubyte[]) hexString!("204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a827"
1004 ~"9be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445"));
1005 assert(digest512_224 == cast(ubyte[]) x"e5302d6d54bb242275d1e7622d68df6eb02dedd13f564c13dbda2174");
1006 assert(digest512_256 == cast(ubyte[]) x"bde8e1f9f19bb9fd3406c90ec6bc47bd36d8ada9f11880dbc8a22a7078b6a461");
1007
1008 digest = sha1Of ("message digest");
1009 digest224 = sha224Of ("message digest");
1010 digest256 = sha256Of ("message digest");
1011 digest384 = sha384Of ("message digest");
1012 digest512 = sha512Of ("message digest");
1013 digest512_224 = sha512_224Of("message digest");
1014 digest512_256 = sha512_256Of("message digest");
1015 assert(digest == cast(ubyte[]) x"c12252ceda8be8994d5fa0290a47231c1d16aae3");
1016 assert(digest224 == cast(ubyte[]) x"2cb21c83ae2f004de7e81c3c7019cbcb65b71ab656b22d6d0c39b8eb");
1017 assert(digest256 == cast(ubyte[]) x"f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650");
1018 assert(digest384 == cast(ubyte[]) hexString!("473ed35167ec1f5d8e550368a3db39be54639f828868e9454c"
1019 ~"239fc8b52e3c61dbd0d8b4de1390c256dcbb5d5fd99cd5"));
1020 assert(digest512 == cast(ubyte[]) hexString!("107dbf389d9e9f71a3a95f6c055b9251bc5268c2be16d6c134"
1021 ~"92ea45b0199f3309e16455ab1e96118e8a905d5597b72038ddb372a89826046de66687bb420e7c"));
1022 assert(digest512_224 == cast(ubyte[]) x"ad1a4db188fe57064f4f24609d2a83cd0afb9b398eb2fcaeaae2c564");
1023 assert(digest512_256 == cast(ubyte[]) x"0cf471fd17ed69d990daf3433c89b16d63dec1bb9cb42a6094604ee5d7b4e9fb");
1024
1025 digest = sha1Of ("abcdefghijklmnopqrstuvwxyz");
1026 digest224 = sha224Of ("abcdefghijklmnopqrstuvwxyz");
1027 digest256 = sha256Of ("abcdefghijklmnopqrstuvwxyz");
1028 digest384 = sha384Of ("abcdefghijklmnopqrstuvwxyz");
1029 digest512 = sha512Of ("abcdefghijklmnopqrstuvwxyz");
1030 digest512_224 = sha512_224Of("abcdefghijklmnopqrstuvwxyz");
1031 digest512_256 = sha512_256Of("abcdefghijklmnopqrstuvwxyz");
1032 assert(digest == cast(ubyte[]) x"32d10c7b8cf96570ca04ce37f2a19d84240d3a89");
1033 assert(digest224 == cast(ubyte[]) x"45a5f72c39c5cff2522eb3429799e49e5f44b356ef926bcf390dccc2");
1034 assert(digest256 == cast(ubyte[]) x"71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73");
1035 assert(digest384 == cast(ubyte[]) hexString!("feb67349df3db6f5924815d6c3dc133f091809213731fe5c7b5"
1036 ~"f4999e463479ff2877f5f2936fa63bb43784b12f3ebb4"));
1037 assert(digest512 == cast(ubyte[]) hexString!("4dbff86cc2ca1bae1e16468a05cb9881c97f1753bce3619034"
1038 ~"898faa1aabe429955a1bf8ec483d7421fe3c1646613a59ed5441fb0f321389f77f48a879c7b1f1"));
1039 assert(digest512_224 == cast(ubyte[]) x"ff83148aa07ec30655c1b40aff86141c0215fe2a54f767d3f38743d8");
1040 assert(digest512_256 == cast(ubyte[]) x"fc3189443f9c268f626aea08a756abe7b726b05f701cb08222312ccfd6710a26");
1041
1042 digest = sha1Of ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
1043 digest224 = sha224Of ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
1044 digest256 = sha256Of ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
1045 digest384 = sha384Of ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
1046 digest512 = sha512Of ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
1047 digest512_224 = sha512_224Of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
1048 digest512_256 = sha512_256Of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
1049 assert(digest == cast(ubyte[]) x"761c457bf73b14d27e9e9265c46f4b4dda11f940");
1050 assert(digest224 == cast(ubyte[]) x"bff72b4fcb7d75e5632900ac5f90d219e05e97a7bde72e740db393d9");
1051 assert(digest256 == cast(ubyte[]) x"db4bfcbd4da0cd85a60c3c37d3fbd8805c77f15fc6b1fdfe614ee0a7c8fdb4c0");
1052 assert(digest384 == cast(ubyte[]) hexString!("1761336e3f7cbfe51deb137f026f89e01a448e3b1fafa64039"
1053 ~"c1464ee8732f11a5341a6f41e0c202294736ed64db1a84"));
1054 assert(digest512 == cast(ubyte[]) hexString!("1e07be23c26a86ea37ea810c8ec7809352515a970e9253c26f"
1055 ~"536cfc7a9996c45c8370583e0a78fa4a90041d71a4ceab7423f19c71b9d5a3e01249f0bebd5894"));
1056 assert(digest512_224 == cast(ubyte[]) x"a8b4b9174b99ffc67d6f49be9981587b96441051e16e6dd036b140d3");
1057 assert(digest512_256 == cast(ubyte[]) x"cdf1cc0effe26ecc0c13758f7b4a48e000615df241284185c39eb05d355bb9c8");
1058
1059 digest = sha1Of ("1234567890123456789012345678901234567890"~
1060 "1234567890123456789012345678901234567890");
1061 digest224 = sha224Of ("1234567890123456789012345678901234567890"~
1062 "1234567890123456789012345678901234567890");
1063 digest256 = sha256Of ("1234567890123456789012345678901234567890"~
1064 "1234567890123456789012345678901234567890");
1065 digest384 = sha384Of ("1234567890123456789012345678901234567890"~
1066 "1234567890123456789012345678901234567890");
1067 digest512 = sha512Of ("1234567890123456789012345678901234567890"~
1068 "1234567890123456789012345678901234567890");
1069 digest512_224 = sha512_224Of("1234567890123456789012345678901234567890"~
1070 "1234567890123456789012345678901234567890");
1071 digest512_256 = sha512_256Of("1234567890123456789012345678901234567890"~
1072 "1234567890123456789012345678901234567890");
1073 assert(digest == cast(ubyte[]) x"50abf5706a150990a08b2c5ea40fa0e585554732");
1074 assert(digest224 == cast(ubyte[]) x"b50aecbe4e9bb0b57bc5f3ae760a8e01db24f203fb3cdcd13148046e");
1075 assert(digest256 == cast(ubyte[]) x"f371bc4a311f2b009eef952dd83ca80e2b60026c8e935592d0f9c308453c813e");
1076 assert(digest384 == cast(ubyte[]) hexString!("b12932b0627d1c060942f5447764155655bd4da0c9afa6dd9b"
1077 ~"9ef53129af1b8fb0195996d2de9ca0df9d821ffee67026"));
1078 assert(digest512 == cast(ubyte[]) hexString!("72ec1ef1124a45b047e8b7c75a932195135bb61de24ec0d191"
1079 ~"4042246e0aec3a2354e093d76f3048b456764346900cb130d2a4fd5dd16abb5e30bcb850dee843"));
1080 assert(digest512_224 == cast(ubyte[]) x"ae988faaa47e401a45f704d1272d99702458fea2ddc6582827556dd2");
1081 assert(digest512_256 == cast(ubyte[]) x"2c9fdbc0c90bdd87612ee8455474f9044850241dc105b1e8b94b8ddf5fac9148");
1082
1083 ubyte[] onemilliona = new ubyte[1000000];
1084 onemilliona[] = 'a';
1085 digest = sha1Of(onemilliona);
1086 digest224 = sha224Of(onemilliona);
1087 digest256 = sha256Of(onemilliona);
1088 digest384 = sha384Of(onemilliona);
1089 digest512 = sha512Of(onemilliona);
1090 digest512_224 = sha512_224Of(onemilliona);
1091 digest512_256 = sha512_256Of(onemilliona);
1092 assert(digest == cast(ubyte[]) x"34aa973cd4c4daa4f61eeb2bdbad27316534016f");
1093 assert(digest224 == cast(ubyte[]) x"20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67");
1094 assert(digest256 == cast(ubyte[]) x"cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0");
1095 assert(digest384 == cast(ubyte[]) hexString!("9d0e1809716474cb086e834e310a4a1ced149e9c00f2485279"
1096 ~"72cec5704c2a5b07b8b3dc38ecc4ebae97ddd87f3d8985"));
1097 assert(digest512 == cast(ubyte[]) hexString!("e718483d0ce769644e2e42c7bc15b4638e1f98b13b20442856"
1098 ~"32a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b"));
1099 assert(digest512_224 == cast(ubyte[]) x"37ab331d76f0d36de422bd0edeb22a28accd487b7a8453ae965dd287");
1100 assert(digest512_256 == cast(ubyte[]) x"9a59a052930187a97038cae692f30708aa6491923ef5194394dc68d56c74fb21");
1101
1102 auto oneMillionRange = repeat!ubyte(cast(ubyte)'a', 1000000);
1103 digest = sha1Of(oneMillionRange);
1104 digest224 = sha224Of(oneMillionRange);
1105 digest256 = sha256Of(oneMillionRange);
1106 digest384 = sha384Of(oneMillionRange);
1107 digest512 = sha512Of(oneMillionRange);
1108 digest512_224 = sha512_224Of(oneMillionRange);
1109 digest512_256 = sha512_256Of(oneMillionRange);
1110 assert(digest == cast(ubyte[]) x"34aa973cd4c4daa4f61eeb2bdbad27316534016f");
1111 assert(digest224 == cast(ubyte[]) x"20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67");
1112 assert(digest256 == cast(ubyte[]) x"cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0");
1113 assert(digest384 == cast(ubyte[]) hexString!("9d0e1809716474cb086e834e310a4a1ced149e9c00f2485279"
1114 ~"72cec5704c2a5b07b8b3dc38ecc4ebae97ddd87f3d8985"));
1115 assert(digest512 == cast(ubyte[]) hexString!("e718483d0ce769644e2e42c7bc15b4638e1f98b13b20442856"
1116 ~"32a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b"));
1117 assert(digest512_224 == cast(ubyte[]) x"37ab331d76f0d36de422bd0edeb22a28accd487b7a8453ae965dd287");
1118 assert(digest512_256 == cast(ubyte[]) x"9a59a052930187a97038cae692f30708aa6491923ef5194394dc68d56c74fb21");
1119
1120 assert(toHexString(cast(ubyte[20]) x"a9993e364706816aba3e25717850c26c9cd0d89d")
1121 == "A9993E364706816ABA3E25717850C26C9CD0D89D");
1122}
1123
1124/**
1125 * These are convenience aliases for $(REF digest, std,digest) using the
1126 * SHA implementation.
1127 */
1128//simple alias doesn't work here, hope this gets inlined...
1129auto sha1Of(T...)(T data)
1130{
1131 return digest!(SHA1, T)(data);
1132}
1133///ditto
1134auto sha224Of(T...)(T data)
1135{
1136 return digest!(SHA224, T)(data);
1137}
1138///ditto
1139auto sha256Of(T...)(T data)
1140{
1141 return digest!(SHA256, T)(data);
1142}
1143///ditto
1144auto sha384Of(T...)(T data)
1145{
1146 return digest!(SHA384, T)(data);
1147}
1148///ditto
1149auto sha512Of(T...)(T data)
1150{
1151 return digest!(SHA512, T)(data);
1152}
1153///ditto
1154auto sha512_224Of(T...)(T data)
1155{
1156 return digest!(SHA512_224, T)(data);
1157}
1158///ditto
1159auto sha512_256Of(T...)(T data)
1160{
1161 return digest!(SHA512_256, T)(data);
1162}
1163
1164///
1165@safe unittest
1166{
1167 ubyte[20] hash = sha1Of("abc");
1168 assert(hash == digest!SHA1("abc"));
1169
1170 ubyte[28] hash224 = sha224Of("abc");
1171 assert(hash224 == digest!SHA224("abc"));
1172
1173 ubyte[32] hash256 = sha256Of("abc");
1174 assert(hash256 == digest!SHA256("abc"));
1175
1176 ubyte[48] hash384 = sha384Of("abc");
1177 assert(hash384 == digest!SHA384("abc"));
1178
1179 ubyte[64] hash512 = sha512Of("abc");
1180 assert(hash512 == digest!SHA512("abc"));
1181
1182 ubyte[28] hash512_224 = sha512_224Of("abc");
1183 assert(hash512_224 == digest!SHA512_224("abc"));
1184
1185 ubyte[32] hash512_256 = sha512_256Of("abc");
1186 assert(hash512_256 == digest!SHA512_256("abc"));
1187}
1188
1189@safe unittest
1190{
1191 string a = "Mary has ", b = "a little lamb";
1192 int[] c = [ 1, 2, 3, 4, 5 ];
1193 string d = toHexString(sha1Of(a, b, c));
1194 version (LittleEndian)
1195 assert(d == "CDBB611D00AC2387B642D3D7BDF4C3B342237110", d);
1196 else
1197 assert(d == "A0F1196C7A379C09390476D9CA4AA11B71FD11C8", d);
1198}
1199
1200/**
1201 * OOP API SHA1 and SHA2 implementations.
1202 * See $(D std.digest) for differences between template and OOP API.
1203 *
1204 * This is an alias for $(D $(REF WrapperDigest, std,digest)!SHA1), see
1205 * there for more information.
1206 */
1207alias SHA1Digest = WrapperDigest!SHA1;
1208alias SHA224Digest = WrapperDigest!SHA224; ///ditto
1209alias SHA256Digest = WrapperDigest!SHA256; ///ditto
1210alias SHA384Digest = WrapperDigest!SHA384; ///ditto
1211alias SHA512Digest = WrapperDigest!SHA512; ///ditto
1212alias SHA512_224Digest = WrapperDigest!SHA512_224; ///ditto
1213alias SHA512_256Digest = WrapperDigest!SHA512_256; ///ditto
1214
1215///
1216@safe unittest
1217{
1218 //Simple example, hashing a string using Digest.digest helper function
1219 auto sha = new SHA1Digest();
1220 ubyte[] hash = sha.digest("abc");
1221 //Let's get a hash string
1222 assert(toHexString(hash) == "A9993E364706816ABA3E25717850C26C9CD0D89D");
1223
1224 //The same, but using SHA-224
1225 auto sha224 = new SHA224Digest();
1226 ubyte[] hash224 = sha224.digest("abc");
1227 //Let's get a hash string
1228 assert(toHexString(hash224) == "23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7");
1229}
1230
1231///
1232@system unittest
1233{
1234 //Let's use the OOP features:
1235 void test(Digest dig)
1236 {
1237 dig.put(cast(ubyte) 0);
1238 }
1239 auto sha = new SHA1Digest();
1240 test(sha);
1241
1242 //Let's use a custom buffer:
1243 ubyte[20] buf;
1244 ubyte[] result = sha.finish(buf[]);
1245 assert(toHexString(result) == "5BA93C9DB0CFF93F52B521D7420E43F6EDA2784F");
1246}
1247
1248@system unittest
1249{
1250 auto sha = new SHA1Digest();
1251
1252 sha.put(cast(ubyte[])"abcdef");
1253 sha.reset();
1254 sha.put(cast(ubyte[])"");
1255 assert(sha.finish() == cast(ubyte[]) x"da39a3ee5e6b4b0d3255bfef95601890afd80709");
1256
1257 sha.put(cast(ubyte[])"abcdefghijklmnopqrstuvwxyz");
1258 ubyte[22] result;
1259 auto result2 = sha.finish(result[]);
1260 assert(result[0 .. 20] == result2 && result2 == cast(ubyte[]) x"32d10c7b8cf96570ca04ce37f2a19d84240d3a89");
1261
1262 debug
1263 assertThrown!Error(sha.finish(result[0 .. 15]));
1264
1265 assert(sha.length == 20);
1266
1267 assert(sha.digest("") == cast(ubyte[]) x"da39a3ee5e6b4b0d3255bfef95601890afd80709");
1268
1269 assert(sha.digest("a") == cast(ubyte[]) x"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8");
1270
1271 assert(sha.digest("abc") == cast(ubyte[]) x"a9993e364706816aba3e25717850c26c9cd0d89d");
1272
1273 assert(sha.digest("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")
1274 == cast(ubyte[]) x"84983e441c3bd26ebaae4aa1f95129e5e54670f1");
1275
1276 assert(sha.digest("message digest") == cast(ubyte[]) x"c12252ceda8be8994d5fa0290a47231c1d16aae3");
1277
1278 assert(sha.digest("abcdefghijklmnopqrstuvwxyz")
1279 == cast(ubyte[]) x"32d10c7b8cf96570ca04ce37f2a19d84240d3a89");
1280
1281 assert(sha.digest("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
1282 == cast(ubyte[]) x"761c457bf73b14d27e9e9265c46f4b4dda11f940");
1283
1284 assert(sha.digest("1234567890123456789012345678901234567890",
1285 "1234567890123456789012345678901234567890")
1286 == cast(ubyte[]) x"50abf5706a150990a08b2c5ea40fa0e585554732");
1287
1288 ubyte[] onemilliona = new ubyte[1000000];
1289 onemilliona[] = 'a';
1290 assert(sha.digest(onemilliona) == cast(ubyte[]) x"34aa973cd4c4daa4f61eeb2bdbad27316534016f");
1291}