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