1 package org.bouncycastle.crypto.digests; 2 3 4 import org.bouncycastle.util.Memoable; 5 import org.bouncycastle.util.Pack; 6 7 8 /** 9 * SHA-224 as described in RFC 3874 10 * <pre> 11 * block word digest 12 * SHA-1 512 32 160 13 * SHA-224 512 32 224 14 * SHA-256 512 32 256 15 * SHA-384 1024 64 384 16 * SHA-512 1024 64 512 17 * </pre> 18 */ 19 public class SHA224Digest 20 extends GeneralDigest 21 implements EncodableDigest 22 { 23 private static final int DIGEST_LENGTH = 28; 24 25 private int H1, H2, H3, H4, H5, H6, H7, H8; 26 27 private int[] X = new int[64]; 28 private int xOff; 29 30 /** 31 * Standard constructor 32 */ SHA224Digest()33 public SHA224Digest() 34 { 35 reset(); 36 } 37 38 /** 39 * Copy constructor. This will copy the state of the provided 40 * message digest. 41 */ SHA224Digest(SHA224Digest t)42 public SHA224Digest(SHA224Digest t) 43 { 44 super(t); 45 46 doCopy(t); 47 } 48 doCopy(SHA224Digest t)49 private void doCopy(SHA224Digest t) 50 { 51 super.copyIn(t); 52 53 H1 = t.H1; 54 H2 = t.H2; 55 H3 = t.H3; 56 H4 = t.H4; 57 H5 = t.H5; 58 H6 = t.H6; 59 H7 = t.H7; 60 H8 = t.H8; 61 62 System.arraycopy(t.X, 0, X, 0, t.X.length); 63 xOff = t.xOff; 64 } 65 SHA224Digest(byte[] encodedState)66 public SHA224Digest(byte[] encodedState) 67 { 68 super(encodedState); 69 70 H1 = Pack.bigEndianToInt(encodedState, 16); 71 H2 = Pack.bigEndianToInt(encodedState, 20); 72 H3 = Pack.bigEndianToInt(encodedState, 24); 73 H4 = Pack.bigEndianToInt(encodedState, 28); 74 H5 = Pack.bigEndianToInt(encodedState, 32); 75 H6 = Pack.bigEndianToInt(encodedState, 36); 76 H7 = Pack.bigEndianToInt(encodedState, 40); 77 H8 = Pack.bigEndianToInt(encodedState, 44); 78 79 xOff = Pack.bigEndianToInt(encodedState, 48); 80 for (int i = 0; i != xOff; i++) 81 { 82 X[i] = Pack.bigEndianToInt(encodedState, 52 + (i * 4)); 83 } 84 } 85 getAlgorithmName()86 public String getAlgorithmName() 87 { 88 return "SHA-224"; 89 } 90 getDigestSize()91 public int getDigestSize() 92 { 93 return DIGEST_LENGTH; 94 } 95 processWord( byte[] in, int inOff)96 protected void processWord( 97 byte[] in, 98 int inOff) 99 { 100 // Note: Inlined for performance 101 // X[xOff] = Pack.bigEndianToInt(in, inOff); 102 int n = in[ inOff] << 24; 103 n |= (in[++inOff] & 0xff) << 16; 104 n |= (in[++inOff] & 0xff) << 8; 105 n |= (in[++inOff] & 0xff); 106 X[xOff] = n; 107 108 if (++xOff == 16) 109 { 110 processBlock(); 111 } 112 } 113 processLength( long bitLength)114 protected void processLength( 115 long bitLength) 116 { 117 if (xOff > 14) 118 { 119 processBlock(); 120 } 121 122 X[14] = (int)(bitLength >>> 32); 123 X[15] = (int)(bitLength & 0xffffffff); 124 } 125 doFinal( byte[] out, int outOff)126 public int doFinal( 127 byte[] out, 128 int outOff) 129 { 130 finish(); 131 132 Pack.intToBigEndian(H1, out, outOff); 133 Pack.intToBigEndian(H2, out, outOff + 4); 134 Pack.intToBigEndian(H3, out, outOff + 8); 135 Pack.intToBigEndian(H4, out, outOff + 12); 136 Pack.intToBigEndian(H5, out, outOff + 16); 137 Pack.intToBigEndian(H6, out, outOff + 20); 138 Pack.intToBigEndian(H7, out, outOff + 24); 139 140 reset(); 141 142 return DIGEST_LENGTH; 143 } 144 145 /** 146 * reset the chaining variables 147 */ reset()148 public void reset() 149 { 150 super.reset(); 151 152 /* SHA-224 initial hash value 153 */ 154 155 H1 = 0xc1059ed8; 156 H2 = 0x367cd507; 157 H3 = 0x3070dd17; 158 H4 = 0xf70e5939; 159 H5 = 0xffc00b31; 160 H6 = 0x68581511; 161 H7 = 0x64f98fa7; 162 H8 = 0xbefa4fa4; 163 164 xOff = 0; 165 for (int i = 0; i != X.length; i++) 166 { 167 X[i] = 0; 168 } 169 } 170 processBlock()171 protected void processBlock() 172 { 173 // 174 // expand 16 word block into 64 word blocks. 175 // 176 for (int t = 16; t <= 63; t++) 177 { 178 X[t] = Theta1(X[t - 2]) + X[t - 7] + Theta0(X[t - 15]) + X[t - 16]; 179 } 180 181 // 182 // set up working variables. 183 // 184 int a = H1; 185 int b = H2; 186 int c = H3; 187 int d = H4; 188 int e = H5; 189 int f = H6; 190 int g = H7; 191 int h = H8; 192 193 194 int t = 0; 195 for(int i = 0; i < 8; i ++) 196 { 197 // t = 8 * i 198 h += Sum1(e) + Ch(e, f, g) + K[t] + X[t]; 199 d += h; 200 h += Sum0(a) + Maj(a, b, c); 201 ++t; 202 203 // t = 8 * i + 1 204 g += Sum1(d) + Ch(d, e, f) + K[t] + X[t]; 205 c += g; 206 g += Sum0(h) + Maj(h, a, b); 207 ++t; 208 209 // t = 8 * i + 2 210 f += Sum1(c) + Ch(c, d, e) + K[t] + X[t]; 211 b += f; 212 f += Sum0(g) + Maj(g, h, a); 213 ++t; 214 215 // t = 8 * i + 3 216 e += Sum1(b) + Ch(b, c, d) + K[t] + X[t]; 217 a += e; 218 e += Sum0(f) + Maj(f, g, h); 219 ++t; 220 221 // t = 8 * i + 4 222 d += Sum1(a) + Ch(a, b, c) + K[t] + X[t]; 223 h += d; 224 d += Sum0(e) + Maj(e, f, g); 225 ++t; 226 227 // t = 8 * i + 5 228 c += Sum1(h) + Ch(h, a, b) + K[t] + X[t]; 229 g += c; 230 c += Sum0(d) + Maj(d, e, f); 231 ++t; 232 233 // t = 8 * i + 6 234 b += Sum1(g) + Ch(g, h, a) + K[t] + X[t]; 235 f += b; 236 b += Sum0(c) + Maj(c, d, e); 237 ++t; 238 239 // t = 8 * i + 7 240 a += Sum1(f) + Ch(f, g, h) + K[t] + X[t]; 241 e += a; 242 a += Sum0(b) + Maj(b, c, d); 243 ++t; 244 } 245 246 H1 += a; 247 H2 += b; 248 H3 += c; 249 H4 += d; 250 H5 += e; 251 H6 += f; 252 H7 += g; 253 H8 += h; 254 255 // 256 // reset the offset and clean out the word buffer. 257 // 258 xOff = 0; 259 for (int i = 0; i < 16; i++) 260 { 261 X[i] = 0; 262 } 263 } 264 265 /* SHA-224 functions */ Ch( int x, int y, int z)266 private int Ch( 267 int x, 268 int y, 269 int z) 270 { 271 return ((x & y) ^ ((~x) & z)); 272 } 273 Maj( int x, int y, int z)274 private int Maj( 275 int x, 276 int y, 277 int z) 278 { 279 return ((x & y) ^ (x & z) ^ (y & z)); 280 } 281 Sum0( int x)282 private int Sum0( 283 int x) 284 { 285 return ((x >>> 2) | (x << 30)) ^ ((x >>> 13) | (x << 19)) ^ ((x >>> 22) | (x << 10)); 286 } 287 Sum1( int x)288 private int Sum1( 289 int x) 290 { 291 return ((x >>> 6) | (x << 26)) ^ ((x >>> 11) | (x << 21)) ^ ((x >>> 25) | (x << 7)); 292 } 293 Theta0( int x)294 private int Theta0( 295 int x) 296 { 297 return ((x >>> 7) | (x << 25)) ^ ((x >>> 18) | (x << 14)) ^ (x >>> 3); 298 } 299 Theta1( int x)300 private int Theta1( 301 int x) 302 { 303 return ((x >>> 17) | (x << 15)) ^ ((x >>> 19) | (x << 13)) ^ (x >>> 10); 304 } 305 306 /* SHA-224 Constants 307 * (represent the first 32 bits of the fractional parts of the 308 * cube roots of the first sixty-four prime numbers) 309 */ 310 static final int K[] = { 311 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 312 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 313 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 314 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 315 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 316 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 317 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 318 }; 319 copy()320 public Memoable copy() 321 { 322 return new SHA224Digest(this); 323 } 324 reset(Memoable other)325 public void reset(Memoable other) 326 { 327 SHA224Digest d = (SHA224Digest)other; 328 329 doCopy(d); 330 } 331 getEncodedState()332 public byte[] getEncodedState() 333 { 334 byte[] state = new byte[52 + xOff * 4]; 335 336 super.populateState(state); 337 338 Pack.intToBigEndian(H1, state, 16); 339 Pack.intToBigEndian(H2, state, 20); 340 Pack.intToBigEndian(H3, state, 24); 341 Pack.intToBigEndian(H4, state, 28); 342 Pack.intToBigEndian(H5, state, 32); 343 Pack.intToBigEndian(H6, state, 36); 344 Pack.intToBigEndian(H7, state, 40); 345 Pack.intToBigEndian(H8, state, 44); 346 Pack.intToBigEndian(xOff, state, 48); 347 348 for (int i = 0; i != xOff; i++) 349 { 350 Pack.intToBigEndian(X[i], state, 52 + (i * 4)); 351 } 352 353 return state; 354 } 355 } 356 357