1 package org.bouncycastle.crypto.digests; 2 3 import org.bouncycastle.crypto.util.Pack; 4 import org.bouncycastle.util.Memoable; 5 6 /** 7 * implementation of SHA-1 as outlined in "Handbook of Applied Cryptography", pages 346 - 349. 8 * 9 * It is interesting to ponder why the, apart from the extra IV, the other difference here from MD5 10 * is the "endianness" of the word processing! 11 */ 12 public class SHA1Digest 13 extends GeneralDigest 14 { 15 private static final int DIGEST_LENGTH = 20; 16 17 private int H1, H2, H3, H4, H5; 18 19 private int[] X = new int[80]; 20 private int xOff; 21 22 /** 23 * Standard constructor 24 */ 25 public SHA1Digest() 26 { 27 reset(); 28 } 29 30 /** 31 * Copy constructor. This will copy the state of the provided 32 * message digest. 33 */ 34 public SHA1Digest(SHA1Digest t) 35 { 36 super(t); 37 38 copyIn(t); 39 } 40 41 private void copyIn(SHA1Digest t) 42 { 43 H1 = t.H1; 44 H2 = t.H2; 45 H3 = t.H3; 46 H4 = t.H4; 47 H5 = t.H5; 48 49 System.arraycopy(t.X, 0, X, 0, t.X.length); 50 xOff = t.xOff; 51 } 52 53 public String getAlgorithmName() 54 { 55 return "SHA-1"; 56 } 57 58 public int getDigestSize() 59 { 60 return DIGEST_LENGTH; 61 } 62 63 protected void processWord( 64 byte[] in, 65 int inOff) 66 { 67 // Note: Inlined for performance 68 // X[xOff] = Pack.bigEndianToInt(in, inOff); 69 int n = in[ inOff] << 24; 70 n |= (in[++inOff] & 0xff) << 16; 71 n |= (in[++inOff] & 0xff) << 8; 72 n |= (in[++inOff] & 0xff); 73 X[xOff] = n; 74 75 if (++xOff == 16) 76 { 77 processBlock(); 78 } 79 } 80 81 protected void processLength( 82 long bitLength) 83 { 84 if (xOff > 14) 85 { 86 processBlock(); 87 } 88 89 X[14] = (int)(bitLength >>> 32); 90 X[15] = (int)(bitLength & 0xffffffff); 91 } 92 93 public int doFinal( 94 byte[] out, 95 int outOff) 96 { 97 finish(); 98 99 Pack.intToBigEndian(H1, out, outOff); 100 Pack.intToBigEndian(H2, out, outOff + 4); 101 Pack.intToBigEndian(H3, out, outOff + 8); 102 Pack.intToBigEndian(H4, out, outOff + 12); 103 Pack.intToBigEndian(H5, out, outOff + 16); 104 105 reset(); 106 107 return DIGEST_LENGTH; 108 } 109 110 /** 111 * reset the chaining variables 112 */ 113 public void reset() 114 { 115 super.reset(); 116 117 H1 = 0x67452301; 118 H2 = 0xefcdab89; 119 H3 = 0x98badcfe; 120 H4 = 0x10325476; 121 H5 = 0xc3d2e1f0; 122 123 xOff = 0; 124 for (int i = 0; i != X.length; i++) 125 { 126 X[i] = 0; 127 } 128 } 129 130 // 131 // Additive constants 132 // 133 private static final int Y1 = 0x5a827999; 134 private static final int Y2 = 0x6ed9eba1; 135 private static final int Y3 = 0x8f1bbcdc; 136 private static final int Y4 = 0xca62c1d6; 137 138 private int f( 139 int u, 140 int v, 141 int w) 142 { 143 return ((u & v) | ((~u) & w)); 144 } 145 146 private int h( 147 int u, 148 int v, 149 int w) 150 { 151 return (u ^ v ^ w); 152 } 153 154 private int g( 155 int u, 156 int v, 157 int w) 158 { 159 return ((u & v) | (u & w) | (v & w)); 160 } 161 162 protected void processBlock() 163 { 164 // 165 // expand 16 word block into 80 word block. 166 // 167 for (int i = 16; i < 80; i++) 168 { 169 int t = X[i - 3] ^ X[i - 8] ^ X[i - 14] ^ X[i - 16]; 170 X[i] = t << 1 | t >>> 31; 171 } 172 173 // 174 // set up working variables. 175 // 176 int A = H1; 177 int B = H2; 178 int C = H3; 179 int D = H4; 180 int E = H5; 181 182 // 183 // round 1 184 // 185 int idx = 0; 186 187 for (int j = 0; j < 4; j++) 188 { 189 // E = rotateLeft(A, 5) + f(B, C, D) + E + X[idx++] + Y1 190 // B = rotateLeft(B, 30) 191 E += (A << 5 | A >>> 27) + f(B, C, D) + X[idx++] + Y1; 192 B = B << 30 | B >>> 2; 193 194 D += (E << 5 | E >>> 27) + f(A, B, C) + X[idx++] + Y1; 195 A = A << 30 | A >>> 2; 196 197 C += (D << 5 | D >>> 27) + f(E, A, B) + X[idx++] + Y1; 198 E = E << 30 | E >>> 2; 199 200 B += (C << 5 | C >>> 27) + f(D, E, A) + X[idx++] + Y1; 201 D = D << 30 | D >>> 2; 202 203 A += (B << 5 | B >>> 27) + f(C, D, E) + X[idx++] + Y1; 204 C = C << 30 | C >>> 2; 205 } 206 207 // 208 // round 2 209 // 210 for (int j = 0; j < 4; j++) 211 { 212 // E = rotateLeft(A, 5) + h(B, C, D) + E + X[idx++] + Y2 213 // B = rotateLeft(B, 30) 214 E += (A << 5 | A >>> 27) + h(B, C, D) + X[idx++] + Y2; 215 B = B << 30 | B >>> 2; 216 217 D += (E << 5 | E >>> 27) + h(A, B, C) + X[idx++] + Y2; 218 A = A << 30 | A >>> 2; 219 220 C += (D << 5 | D >>> 27) + h(E, A, B) + X[idx++] + Y2; 221 E = E << 30 | E >>> 2; 222 223 B += (C << 5 | C >>> 27) + h(D, E, A) + X[idx++] + Y2; 224 D = D << 30 | D >>> 2; 225 226 A += (B << 5 | B >>> 27) + h(C, D, E) + X[idx++] + Y2; 227 C = C << 30 | C >>> 2; 228 } 229 230 // 231 // round 3 232 // 233 for (int j = 0; j < 4; j++) 234 { 235 // E = rotateLeft(A, 5) + g(B, C, D) + E + X[idx++] + Y3 236 // B = rotateLeft(B, 30) 237 E += (A << 5 | A >>> 27) + g(B, C, D) + X[idx++] + Y3; 238 B = B << 30 | B >>> 2; 239 240 D += (E << 5 | E >>> 27) + g(A, B, C) + X[idx++] + Y3; 241 A = A << 30 | A >>> 2; 242 243 C += (D << 5 | D >>> 27) + g(E, A, B) + X[idx++] + Y3; 244 E = E << 30 | E >>> 2; 245 246 B += (C << 5 | C >>> 27) + g(D, E, A) + X[idx++] + Y3; 247 D = D << 30 | D >>> 2; 248 249 A += (B << 5 | B >>> 27) + g(C, D, E) + X[idx++] + Y3; 250 C = C << 30 | C >>> 2; 251 } 252 253 // 254 // round 4 255 // 256 for (int j = 0; j <= 3; j++) 257 { 258 // E = rotateLeft(A, 5) + h(B, C, D) + E + X[idx++] + Y4 259 // B = rotateLeft(B, 30) 260 E += (A << 5 | A >>> 27) + h(B, C, D) + X[idx++] + Y4; 261 B = B << 30 | B >>> 2; 262 263 D += (E << 5 | E >>> 27) + h(A, B, C) + X[idx++] + Y4; 264 A = A << 30 | A >>> 2; 265 266 C += (D << 5 | D >>> 27) + h(E, A, B) + X[idx++] + Y4; 267 E = E << 30 | E >>> 2; 268 269 B += (C << 5 | C >>> 27) + h(D, E, A) + X[idx++] + Y4; 270 D = D << 30 | D >>> 2; 271 272 A += (B << 5 | B >>> 27) + h(C, D, E) + X[idx++] + Y4; 273 C = C << 30 | C >>> 2; 274 } 275 276 277 H1 += A; 278 H2 += B; 279 H3 += C; 280 H4 += D; 281 H5 += E; 282 283 // 284 // reset start of the buffer. 285 // 286 xOff = 0; 287 for (int i = 0; i < 16; i++) 288 { 289 X[i] = 0; 290 } 291 } 292 293 public Memoable copy() 294 { 295 return new SHA1Digest(this); 296 } 297 298 public void reset(Memoable other) 299 { 300 SHA1Digest d = (SHA1Digest)other; 301 302 super.copyIn(d); 303 copyIn(d); 304 } 305 } 306 307 308 309 310