1 /******************************************************************************* 2 3 This module implements the SHA-512 Algorithm described by Secure Hash 4 Standard, FIPS PUB 180-2 5 6 Copyright: 7 Copyright (c) 2006 Tango contributors. 8 Some parts copyright (c) 2009-2016 dunnhumby Germany GmbH. 9 All rights reserved. 10 11 License: 12 Tango Dual License: 3-Clause BSD License / Academic Free License v3.0. 13 See LICENSE_TANGO.txt for details. 14 15 Version: Initial release: Feb 2006 16 17 Authors: Regan Heath, Oskar Linde 18 19 *******************************************************************************/ 20 21 module ocean.util.digest.Sha512; 22 23 import ocean.meta.types.Qualifiers; 24 25 import ocean.core.ByteSwap; 26 27 import ocean.util.digest.MerkleDamgard; 28 29 public import ocean.util.digest.Digest; 30 31 version (unittest) import ocean.core.Test; 32 33 /******************************************************************************* 34 35 *******************************************************************************/ 36 37 final class Sha512 : MerkleDamgard 38 { 39 private ulong[8] context; 40 private static immutable uint padChar = 0x80; 41 42 /*********************************************************************** 43 44 Construct a Sha512 hash algorithm context 45 46 ***********************************************************************/ 47 48 this() { } 49 50 /*********************************************************************** 51 52 ***********************************************************************/ 53 54 protected override void createDigest(ubyte[] buf) 55 { 56 version (LittleEndian) 57 ByteSwap.swap64(context.ptr, context.length * ulong.sizeof); 58 59 buf[] = cast(ubyte[]) context[]; 60 } 61 62 /*********************************************************************** 63 64 The digest size of Sha-512 is 64 bytes 65 66 ***********************************************************************/ 67 68 override uint digestSize() {return 64;} 69 70 /*********************************************************************** 71 72 Initialize the cipher 73 74 Remarks: 75 Returns the cipher state to it's initial value 76 77 ***********************************************************************/ 78 79 protected override void reset() 80 { 81 super.reset(); 82 context[] = initial[]; 83 } 84 85 /*********************************************************************** 86 87 Cipher block size 88 89 Returns: 90 the block size 91 92 Remarks: 93 Specifies the size (in bytes) of the block of data to pass to 94 each call to transform(). For SHA512 the blockSize is 128. 95 96 ***********************************************************************/ 97 98 protected override uint blockSize() { return 128; } 99 100 /*********************************************************************** 101 102 Length padding size 103 104 Returns: 105 the length padding size 106 107 Remarks: 108 Specifies the size (in bytes) of the padding which uses the 109 length of the data which has been ciphered, this padding is 110 carried out by the padLength method. For SHA512 the addSize is 16. 111 112 ***********************************************************************/ 113 114 protected override uint addSize() { return 16; } 115 116 /*********************************************************************** 117 118 Pads the cipher data 119 120 Params: 121 data = a slice of the cipher buffer to fill with padding 122 123 Remarks: 124 Fills the passed buffer slice with the appropriate padding for 125 the final call to transform(). This padding will fill the cipher 126 buffer up to blockSize()-addSize(). 127 128 ***********************************************************************/ 129 130 protected override void padMessage(ubyte[] data) 131 { 132 data[0] = padChar; 133 data[1..$] = 0; 134 } 135 136 /*********************************************************************** 137 138 Performs the length padding 139 140 Params: 141 data = the slice of the cipher buffer to fill with padding 142 length = the length of the data which has been ciphered 143 144 Remarks: 145 Fills the passed buffer slice with addSize() bytes of padding 146 based on the length in bytes of the input data which has been 147 ciphered. 148 149 ***********************************************************************/ 150 151 protected override void padLength(ubyte[] data, ulong length) 152 { 153 length <<= 3; 154 for(auto j = data.length; j > 0;) { 155 j--; 156 data[data.length-j-1] = cast(ubyte) (length >> j*8); 157 } 158 data[0..8] = 0; 159 } 160 161 /*********************************************************************** 162 163 Performs the cipher on a block of data 164 165 Params: 166 input = the block of data to cipher 167 168 Remarks: 169 The actual cipher algorithm is carried out by this method on 170 the passed block of data. This method is called for every 171 blockSize() bytes of input data and once more with the remaining 172 data padded to blockSize(). 173 174 ***********************************************************************/ 175 176 protected override void transform(ubyte[] input) 177 { 178 ulong[80] W; 179 ulong a,b,c,d,e,f,g,h; 180 ulong t1,t2; 181 uint j; 182 183 a = context[0]; 184 b = context[1]; 185 c = context[2]; 186 d = context[3]; 187 e = context[4]; 188 f = context[5]; 189 g = context[6]; 190 h = context[7]; 191 192 bigEndian64(input,W[0..16]); 193 for(j = 16; j < 80; j++) { 194 W[j] = mix1(W[j-2]) + W[j-7] + mix0(W[j-15]) + W[j-16]; 195 } 196 197 for(j = 0; j < 80; j++) { 198 t1 = h + sum1(e) + Ch(e,f,g) + K[j] + W[j]; 199 t2 = sum0(a) + Maj(a,b,c); 200 h = g; 201 g = f; 202 f = e; 203 e = d + t1; 204 d = c; 205 c = b; 206 b = a; 207 a = t1 + t2; 208 } 209 210 context[0] += a; 211 context[1] += b; 212 context[2] += c; 213 context[3] += d; 214 context[4] += e; 215 context[5] += f; 216 context[6] += g; 217 context[7] += h; 218 } 219 220 /*********************************************************************** 221 222 ***********************************************************************/ 223 224 private static ulong Ch(ulong x, ulong y, ulong z) 225 { 226 return (x&y)^(~x&z); 227 } 228 229 /*********************************************************************** 230 231 ***********************************************************************/ 232 233 private static ulong Maj(ulong x, ulong y, ulong z) 234 { 235 return (x&y)^(x&z)^(y&z); 236 } 237 238 /*********************************************************************** 239 240 ***********************************************************************/ 241 242 private static ulong sum0(ulong x) 243 { 244 return rotateRight(x,28)^rotateRight(x,34)^rotateRight(x,39); 245 } 246 247 /*********************************************************************** 248 249 ***********************************************************************/ 250 251 private static ulong sum1(ulong x) 252 { 253 return rotateRight(x,14)^rotateRight(x,18)^rotateRight(x,41); 254 } 255 256 /*********************************************************************** 257 258 ***********************************************************************/ 259 260 private static ulong mix0(ulong x) 261 { 262 return rotateRight(x,1)^rotateRight(x,8)^shiftRight(x,7); 263 } 264 265 /*********************************************************************** 266 267 ***********************************************************************/ 268 269 private static ulong mix1(ulong x) 270 { 271 return rotateRight(x,19)^rotateRight(x,61)^shiftRight(x,6); 272 } 273 274 /*********************************************************************** 275 276 ***********************************************************************/ 277 278 private static ulong rotateRight(ulong x, uint n) 279 { 280 return (x >> n) | (x << (64-n)); 281 } 282 283 /*********************************************************************** 284 285 ***********************************************************************/ 286 287 private static ulong shiftRight(ulong x, uint n) 288 { 289 return x >> n; 290 } 291 292 } 293 294 /******************************************************************************* 295 296 *******************************************************************************/ 297 298 private static const(ulong[]) K = 299 [ 300 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 301 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 302 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, 303 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694, 304 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, 305 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, 306 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, 307 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70, 308 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, 309 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, 310 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, 311 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, 312 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, 313 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, 314 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, 315 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, 316 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 317 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, 318 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, 319 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817 320 ]; 321 322 /******************************************************************************* 323 324 *******************************************************************************/ 325 326 private static const(ulong[8]) initial = 327 [ 328 0x6a09e667f3bcc908, 329 0xbb67ae8584caa73b, 330 0x3c6ef372fe94f82b, 331 0xa54ff53a5f1d36f1, 332 0x510e527fade682d1, 333 0x9b05688c2b3e6c1f, 334 0x1f83d9abfb41bd6b, 335 0x5be0cd19137e2179 336 ]; 337 338 339 /******************************************************************************* 340 341 *******************************************************************************/ 342 343 unittest 344 { 345 static istring[] strings = [ 346 "", 347 "abc", 348 "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" 349 ]; 350 351 static istring[] results = [ 352 "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", 353 "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", 354 "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909" 355 ]; 356 357 Sha512 h = new Sha512; 358 359 foreach (i, s; strings) 360 { 361 h.update(cast(ubyte[])s); 362 char[] d = h.hexDigest(); 363 test(d == results[i],"DigestTransform:("~s~")("~d~")!=("~results[i]~")"); 364 } 365 }