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