| /* GENERATED SOURCE. DO NOT MODIFY. */ |
| package com.android.org.bouncycastle.crypto.digests; |
| |
| import com.android.org.bouncycastle.util.Memoable; |
| import com.android.org.bouncycastle.util.Pack; |
| |
| /** |
| * implementation of SHA-1 as outlined in "Handbook of Applied Cryptography", pages 346 - 349. |
| * |
| * It is interesting to ponder why the, apart from the extra IV, the other difference here from MD5 |
| * is the "endianness" of the word processing! |
| * @hide This class is not part of the Android public SDK API |
| */ |
| public class SHA1Digest |
| extends GeneralDigest |
| implements EncodableDigest |
| { |
| private static final int DIGEST_LENGTH = 20; |
| |
| private int H1, H2, H3, H4, H5; |
| |
| private int[] X = new int[80]; |
| private int xOff; |
| |
| /** |
| * Standard constructor |
| */ |
| public SHA1Digest() |
| { |
| reset(); |
| } |
| |
| /** |
| * Copy constructor. This will copy the state of the provided |
| * message digest. |
| */ |
| public SHA1Digest(SHA1Digest t) |
| { |
| super(t); |
| |
| copyIn(t); |
| } |
| |
| /** |
| * State constructor - create a digest initialised with the state of a previous one. |
| * |
| * @param encodedState the encoded state from the originating digest. |
| */ |
| public SHA1Digest(byte[] encodedState) |
| { |
| super(encodedState); |
| |
| H1 = Pack.bigEndianToInt(encodedState, 16); |
| H2 = Pack.bigEndianToInt(encodedState, 20); |
| H3 = Pack.bigEndianToInt(encodedState, 24); |
| H4 = Pack.bigEndianToInt(encodedState, 28); |
| H5 = Pack.bigEndianToInt(encodedState, 32); |
| |
| xOff = Pack.bigEndianToInt(encodedState, 36); |
| for (int i = 0; i != xOff; i++) |
| { |
| X[i] = Pack.bigEndianToInt(encodedState, 40 + (i * 4)); |
| } |
| } |
| |
| private void copyIn(SHA1Digest t) |
| { |
| H1 = t.H1; |
| H2 = t.H2; |
| H3 = t.H3; |
| H4 = t.H4; |
| H5 = t.H5; |
| |
| System.arraycopy(t.X, 0, X, 0, t.X.length); |
| xOff = t.xOff; |
| } |
| |
| public String getAlgorithmName() |
| { |
| return "SHA-1"; |
| } |
| |
| public int getDigestSize() |
| { |
| return DIGEST_LENGTH; |
| } |
| |
| protected void processWord( |
| byte[] in, |
| int inOff) |
| { |
| // Note: Inlined for performance |
| // X[xOff] = Pack.bigEndianToInt(in, inOff); |
| int n = in[ inOff] << 24; |
| n |= (in[++inOff] & 0xff) << 16; |
| n |= (in[++inOff] & 0xff) << 8; |
| n |= (in[++inOff] & 0xff); |
| X[xOff] = n; |
| |
| if (++xOff == 16) |
| { |
| processBlock(); |
| } |
| } |
| |
| protected void processLength( |
| long bitLength) |
| { |
| if (xOff > 14) |
| { |
| processBlock(); |
| } |
| |
| X[14] = (int)(bitLength >>> 32); |
| X[15] = (int)(bitLength & 0xffffffff); |
| } |
| |
| public int doFinal( |
| byte[] out, |
| int outOff) |
| { |
| finish(); |
| |
| Pack.intToBigEndian(H1, out, outOff); |
| Pack.intToBigEndian(H2, out, outOff + 4); |
| Pack.intToBigEndian(H3, out, outOff + 8); |
| Pack.intToBigEndian(H4, out, outOff + 12); |
| Pack.intToBigEndian(H5, out, outOff + 16); |
| |
| reset(); |
| |
| return DIGEST_LENGTH; |
| } |
| |
| /** |
| * reset the chaining variables |
| */ |
| public void reset() |
| { |
| super.reset(); |
| |
| H1 = 0x67452301; |
| H2 = 0xefcdab89; |
| H3 = 0x98badcfe; |
| H4 = 0x10325476; |
| H5 = 0xc3d2e1f0; |
| |
| xOff = 0; |
| for (int i = 0; i != X.length; i++) |
| { |
| X[i] = 0; |
| } |
| } |
| |
| // |
| // Additive constants |
| // |
| private static final int Y1 = 0x5a827999; |
| private static final int Y2 = 0x6ed9eba1; |
| private static final int Y3 = 0x8f1bbcdc; |
| private static final int Y4 = 0xca62c1d6; |
| |
| private int f( |
| int u, |
| int v, |
| int w) |
| { |
| return ((u & v) | ((~u) & w)); |
| } |
| |
| private int h( |
| int u, |
| int v, |
| int w) |
| { |
| return (u ^ v ^ w); |
| } |
| |
| private int g( |
| int u, |
| int v, |
| int w) |
| { |
| return ((u & v) | (u & w) | (v & w)); |
| } |
| |
| protected void processBlock() |
| { |
| // |
| // expand 16 word block into 80 word block. |
| // |
| for (int i = 16; i < 80; i++) |
| { |
| int t = X[i - 3] ^ X[i - 8] ^ X[i - 14] ^ X[i - 16]; |
| X[i] = t << 1 | t >>> 31; |
| } |
| |
| // |
| // set up working variables. |
| // |
| int A = H1; |
| int B = H2; |
| int C = H3; |
| int D = H4; |
| int E = H5; |
| |
| // |
| // round 1 |
| // |
| int idx = 0; |
| |
| for (int j = 0; j < 4; j++) |
| { |
| // E = rotateLeft(A, 5) + f(B, C, D) + E + X[idx++] + Y1 |
| // B = rotateLeft(B, 30) |
| E += (A << 5 | A >>> 27) + f(B, C, D) + X[idx++] + Y1; |
| B = B << 30 | B >>> 2; |
| |
| D += (E << 5 | E >>> 27) + f(A, B, C) + X[idx++] + Y1; |
| A = A << 30 | A >>> 2; |
| |
| C += (D << 5 | D >>> 27) + f(E, A, B) + X[idx++] + Y1; |
| E = E << 30 | E >>> 2; |
| |
| B += (C << 5 | C >>> 27) + f(D, E, A) + X[idx++] + Y1; |
| D = D << 30 | D >>> 2; |
| |
| A += (B << 5 | B >>> 27) + f(C, D, E) + X[idx++] + Y1; |
| C = C << 30 | C >>> 2; |
| } |
| |
| // |
| // round 2 |
| // |
| for (int j = 0; j < 4; j++) |
| { |
| // E = rotateLeft(A, 5) + h(B, C, D) + E + X[idx++] + Y2 |
| // B = rotateLeft(B, 30) |
| E += (A << 5 | A >>> 27) + h(B, C, D) + X[idx++] + Y2; |
| B = B << 30 | B >>> 2; |
| |
| D += (E << 5 | E >>> 27) + h(A, B, C) + X[idx++] + Y2; |
| A = A << 30 | A >>> 2; |
| |
| C += (D << 5 | D >>> 27) + h(E, A, B) + X[idx++] + Y2; |
| E = E << 30 | E >>> 2; |
| |
| B += (C << 5 | C >>> 27) + h(D, E, A) + X[idx++] + Y2; |
| D = D << 30 | D >>> 2; |
| |
| A += (B << 5 | B >>> 27) + h(C, D, E) + X[idx++] + Y2; |
| C = C << 30 | C >>> 2; |
| } |
| |
| // |
| // round 3 |
| // |
| for (int j = 0; j < 4; j++) |
| { |
| // E = rotateLeft(A, 5) + g(B, C, D) + E + X[idx++] + Y3 |
| // B = rotateLeft(B, 30) |
| E += (A << 5 | A >>> 27) + g(B, C, D) + X[idx++] + Y3; |
| B = B << 30 | B >>> 2; |
| |
| D += (E << 5 | E >>> 27) + g(A, B, C) + X[idx++] + Y3; |
| A = A << 30 | A >>> 2; |
| |
| C += (D << 5 | D >>> 27) + g(E, A, B) + X[idx++] + Y3; |
| E = E << 30 | E >>> 2; |
| |
| B += (C << 5 | C >>> 27) + g(D, E, A) + X[idx++] + Y3; |
| D = D << 30 | D >>> 2; |
| |
| A += (B << 5 | B >>> 27) + g(C, D, E) + X[idx++] + Y3; |
| C = C << 30 | C >>> 2; |
| } |
| |
| // |
| // round 4 |
| // |
| for (int j = 0; j <= 3; j++) |
| { |
| // E = rotateLeft(A, 5) + h(B, C, D) + E + X[idx++] + Y4 |
| // B = rotateLeft(B, 30) |
| E += (A << 5 | A >>> 27) + h(B, C, D) + X[idx++] + Y4; |
| B = B << 30 | B >>> 2; |
| |
| D += (E << 5 | E >>> 27) + h(A, B, C) + X[idx++] + Y4; |
| A = A << 30 | A >>> 2; |
| |
| C += (D << 5 | D >>> 27) + h(E, A, B) + X[idx++] + Y4; |
| E = E << 30 | E >>> 2; |
| |
| B += (C << 5 | C >>> 27) + h(D, E, A) + X[idx++] + Y4; |
| D = D << 30 | D >>> 2; |
| |
| A += (B << 5 | B >>> 27) + h(C, D, E) + X[idx++] + Y4; |
| C = C << 30 | C >>> 2; |
| } |
| |
| |
| H1 += A; |
| H2 += B; |
| H3 += C; |
| H4 += D; |
| H5 += E; |
| |
| // |
| // reset start of the buffer. |
| // |
| xOff = 0; |
| for (int i = 0; i < 16; i++) |
| { |
| X[i] = 0; |
| } |
| } |
| |
| public Memoable copy() |
| { |
| return new SHA1Digest(this); |
| } |
| |
| public void reset(Memoable other) |
| { |
| SHA1Digest d = (SHA1Digest)other; |
| |
| super.copyIn(d); |
| copyIn(d); |
| } |
| |
| public byte[] getEncodedState() |
| { |
| byte[] state = new byte[40 + xOff * 4]; |
| |
| super.populateState(state); |
| |
| Pack.intToBigEndian(H1, state, 16); |
| Pack.intToBigEndian(H2, state, 20); |
| Pack.intToBigEndian(H3, state, 24); |
| Pack.intToBigEndian(H4, state, 28); |
| Pack.intToBigEndian(H5, state, 32); |
| Pack.intToBigEndian(xOff, state, 36); |
| |
| for (int i = 0; i != xOff; i++) |
| { |
| Pack.intToBigEndian(X[i], state, 40 + (i * 4)); |
| } |
| |
| return state; |
| } |
| } |
| |
| |
| |
| |