1 /******************************************************************************* 2 3 This module implements the SHA-256 Algorithm described by Secure 4 Hash 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.Sha256; 22 23 import ocean.meta.types.Qualifiers; 24 25 import ocean.core.ByteSwap; 26 27 public import ocean.util.digest.Digest; 28 29 import ocean.util.digest.MerkleDamgard; 30 31 version (unittest) import ocean.core.Test; 32 33 /******************************************************************************* 34 35 *******************************************************************************/ 36 37 final class Sha256 : MerkleDamgard 38 { 39 private uint[8] context; 40 private static immutable uint padChar = 0x80; 41 42 /*********************************************************************** 43 44 Construct an Sha256 45 46 ***********************************************************************/ 47 48 this() { } 49 50 /*********************************************************************** 51 52 Initialize the cipher 53 54 Remarks: 55 Returns the cipher state to it's initial value 56 57 ***********************************************************************/ 58 59 protected override void reset() 60 { 61 super.reset(); 62 context[] = initial[]; 63 } 64 65 /*********************************************************************** 66 67 Obtain the digest 68 69 Remarks: 70 Returns a digest of the current cipher state, this may be the 71 final digest, or a digest of the state between calls to update() 72 73 ***********************************************************************/ 74 75 protected override void createDigest (ubyte[] buf) 76 { 77 version (LittleEndian) 78 ByteSwap.swap32 (context.ptr, context.length * uint.sizeof); 79 80 buf[] = cast(ubyte[]) context; 81 } 82 83 /*********************************************************************** 84 85 The digest size of Sha-256 is 32 bytes 86 87 ***********************************************************************/ 88 89 override uint digestSize() { return 32; } 90 91 /*********************************************************************** 92 93 Cipher block size 94 95 Returns: 96 the block size 97 98 Remarks: 99 Specifies the size (in bytes) of the block of data to pass to 100 each call to transform(). For SHA256 the blockSize is 64. 101 102 ***********************************************************************/ 103 104 protected override uint blockSize() { return 64; } 105 106 /*********************************************************************** 107 108 Length padding size 109 110 Returns: 111 the length padding size 112 113 Remarks: 114 Specifies the size (in bytes) of the padding which uses the 115 length of the data which has been ciphered, this padding is 116 carried out by the padLength method. For SHA256 the addSize is 8. 117 118 ***********************************************************************/ 119 120 protected override uint addSize() { return 8; } 121 122 /*********************************************************************** 123 124 Pads the cipher data 125 126 Params: 127 data = a slice of the cipher buffer to fill with padding 128 129 Remarks: 130 Fills the passed buffer slice with the appropriate padding for 131 the final call to transform(). This padding will fill the cipher 132 buffer up to blockSize()-addSize(). 133 134 ***********************************************************************/ 135 136 protected override void padMessage(ubyte[] data) 137 { 138 data[0] = padChar; 139 data[1..$] = 0; 140 } 141 142 /*********************************************************************** 143 144 Performs the length padding 145 146 Params: 147 data = the slice of the cipher buffer to fill with padding 148 length = the length of the data which has been ciphered 149 150 Remarks: 151 Fills the passed buffer slice with addSize() bytes of padding 152 based on the length in bytes of the input data which has been 153 ciphered. 154 155 ***********************************************************************/ 156 157 protected override void padLength(ubyte[] data, size_t length) 158 { 159 length <<= 3; 160 for(ptrdiff_t j = data.length-1; j >= 0; j--) 161 data[$-j-1] = cast(ubyte) (length >> j*8); 162 } 163 164 /*********************************************************************** 165 166 Performs the cipher on a block of data 167 168 Params: 169 input = the block of data to cipher 170 171 Remarks: 172 The actual cipher algorithm is carried out by this method on 173 the passed block of data. This method is called for every 174 blockSize() bytes of input data and once more with the remaining 175 data padded to blockSize(). 176 177 ***********************************************************************/ 178 179 protected override void transform(ubyte[] input) 180 { 181 uint[64] W; 182 uint a,b,c,d,e,f,g,h; 183 uint j,t1,t2; 184 185 a = context[0]; 186 b = context[1]; 187 c = context[2]; 188 d = context[3]; 189 e = context[4]; 190 f = context[5]; 191 g = context[6]; 192 h = context[7]; 193 194 bigEndian32(input,W[0..16]); 195 for(j = 16; j < 64; j++) { 196 W[j] = mix1(W[j-2]) + W[j-7] + mix0(W[j-15]) + W[j-16]; 197 } 198 199 for(j = 0; j < 64; j++) { 200 t1 = h + sum1(e) + Ch(e,f,g) + K[j] + W[j]; 201 t2 = sum0(a) + Maj(a,b,c); 202 h = g; 203 g = f; 204 f = e; 205 e = d + t1; 206 d = c; 207 c = b; 208 b = a; 209 a = t1 + t2; 210 } 211 212 context[0] += a; 213 context[1] += b; 214 context[2] += c; 215 context[3] += d; 216 context[4] += e; 217 context[5] += f; 218 context[6] += g; 219 context[7] += h; 220 } 221 222 /*********************************************************************** 223 224 ***********************************************************************/ 225 226 private static uint Ch(uint x, uint y, uint z) 227 { 228 return (x&y)^(~x&z); 229 } 230 231 /*********************************************************************** 232 233 ***********************************************************************/ 234 235 private static uint Maj(uint x, uint y, uint z) 236 { 237 return (x&y)^(x&z)^(y&z); 238 } 239 240 /*********************************************************************** 241 242 ***********************************************************************/ 243 244 private static uint sum0(uint x) 245 { 246 return rotateRight(x,2)^rotateRight(x,13)^rotateRight(x,22); 247 } 248 249 /*********************************************************************** 250 251 ***********************************************************************/ 252 253 private static uint sum1(uint x) 254 { 255 return rotateRight(x,6)^rotateRight(x,11)^rotateRight(x,25); 256 } 257 258 /*********************************************************************** 259 260 ***********************************************************************/ 261 262 private static uint mix0(uint x) 263 { 264 return rotateRight(x,7)^rotateRight(x,18)^shiftRight(x,3); 265 } 266 267 /*********************************************************************** 268 269 ***********************************************************************/ 270 271 private static uint mix1(uint x) 272 { 273 return rotateRight(x,17)^rotateRight(x,19)^shiftRight(x,10); 274 } 275 276 /*********************************************************************** 277 278 ***********************************************************************/ 279 280 private static uint rotateRight(uint x, uint n) 281 { 282 return (x >> n) | (x << (32-n)); 283 } 284 285 /*********************************************************************** 286 287 ***********************************************************************/ 288 289 private static uint shiftRight(uint x, uint n) 290 { 291 return x >> n; 292 } 293 } 294 295 296 /******************************************************************************* 297 298 *******************************************************************************/ 299 300 private static uint[] K = 301 [ 302 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 303 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 304 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 305 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 306 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 307 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 308 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 309 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 310 ]; 311 312 /******************************************************************************* 313 314 *******************************************************************************/ 315 316 private static const(uint[8]) initial = 317 [ 318 0x6a09e667, 319 0xbb67ae85, 320 0x3c6ef372, 321 0xa54ff53a, 322 0x510e527f, 323 0x9b05688c, 324 0x1f83d9ab, 325 0x5be0cd19 326 ]; 327 328 /******************************************************************************* 329 330 *******************************************************************************/ 331 332 unittest 333 { 334 static istring[] strings = 335 [ 336 "abc", 337 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" 338 ]; 339 340 static istring[] results = 341 [ 342 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", 343 "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1" 344 ]; 345 346 Sha256 h = new Sha256(); 347 348 foreach (i, s; strings) 349 { 350 h.update(s); 351 char[] d = h.hexDigest(); 352 test(d == results[i],"Cipher:("~s~")("~d~")!=("~results[i]~")"); 353 } 354 }