001: package org.bouncycastle.crypto.digests;
002:
003: /**
004: * implementation of SHA-1 as outlined in "Handbook of Applied Cryptography", pages 346 - 349.
005: *
006: * It is interesting to ponder why the, apart from the extra IV, the other difference here from MD5
007: * is the "endienness" of the word processing!
008: */
009: public class SHA1Digest extends GeneralDigest {
010: private static final int DIGEST_LENGTH = 20;
011:
012: private int H1, H2, H3, H4, H5;
013:
014: private int[] X = new int[80];
015: private int xOff;
016:
017: /**
018: * Standard constructor
019: */
020: public SHA1Digest() {
021: reset();
022: }
023:
024: /**
025: * Copy constructor. This will copy the state of the provided
026: * message digest.
027: */
028: public SHA1Digest(SHA1Digest t) {
029: super (t);
030:
031: H1 = t.H1;
032: H2 = t.H2;
033: H3 = t.H3;
034: H4 = t.H4;
035: H5 = t.H5;
036:
037: System.arraycopy(t.X, 0, X, 0, t.X.length);
038: xOff = t.xOff;
039: }
040:
041: public String getAlgorithmName() {
042: return "SHA-1";
043: }
044:
045: public int getDigestSize() {
046: return DIGEST_LENGTH;
047: }
048:
049: protected void processWord(byte[] in, int inOff) {
050: X[xOff++] = (in[inOff] & 0xff) << 24
051: | (in[inOff + 1] & 0xff) << 16
052: | (in[inOff + 2] & 0xff) << 8 | in[inOff + 3] & 0xff;
053:
054: if (xOff == 16) {
055: processBlock();
056: }
057: }
058:
059: private void unpackWord(int word, byte[] out, int outOff) {
060: out[outOff++] = (byte) (word >>> 24);
061: out[outOff++] = (byte) (word >>> 16);
062: out[outOff++] = (byte) (word >>> 8);
063: out[outOff++] = (byte) word;
064: }
065:
066: protected void processLength(long bitLength) {
067: if (xOff > 14) {
068: processBlock();
069: }
070:
071: X[14] = (int) (bitLength >>> 32);
072: X[15] = (int) (bitLength & 0xffffffff);
073: }
074:
075: public int doFinal(byte[] out, int outOff) {
076: finish();
077:
078: unpackWord(H1, out, outOff);
079: unpackWord(H2, out, outOff + 4);
080: unpackWord(H3, out, outOff + 8);
081: unpackWord(H4, out, outOff + 12);
082: unpackWord(H5, out, outOff + 16);
083:
084: reset();
085:
086: return DIGEST_LENGTH;
087: }
088:
089: /**
090: * reset the chaining variables
091: */
092: public void reset() {
093: super .reset();
094:
095: H1 = 0x67452301;
096: H2 = 0xefcdab89;
097: H3 = 0x98badcfe;
098: H4 = 0x10325476;
099: H5 = 0xc3d2e1f0;
100:
101: xOff = 0;
102: for (int i = 0; i != X.length; i++) {
103: X[i] = 0;
104: }
105: }
106:
107: //
108: // Additive constants
109: //
110: private static final int Y1 = 0x5a827999;
111: private static final int Y2 = 0x6ed9eba1;
112: private static final int Y3 = 0x8f1bbcdc;
113: private static final int Y4 = 0xca62c1d6;
114:
115: private int f(int u, int v, int w) {
116: return ((u & v) | ((~u) & w));
117: }
118:
119: private int h(int u, int v, int w) {
120: return (u ^ v ^ w);
121: }
122:
123: private int g(int u, int v, int w) {
124: return ((u & v) | (u & w) | (v & w));
125: }
126:
127: protected void processBlock() {
128: //
129: // expand 16 word block into 80 word block.
130: //
131: for (int i = 16; i < 80; i++) {
132: int t = X[i - 3] ^ X[i - 8] ^ X[i - 14] ^ X[i - 16];
133: X[i] = t << 1 | t >>> 31;
134: }
135:
136: //
137: // set up working variables.
138: //
139: int A = H1;
140: int B = H2;
141: int C = H3;
142: int D = H4;
143: int E = H5;
144:
145: //
146: // round 1
147: //
148: int idx = 0;
149:
150: for (int j = 0; j < 4; j++) {
151: // E = rotateLeft(A, 5) + f(B, C, D) + E + X[idx++] + Y1
152: // B = rotateLeft(B, 30)
153: E += (A << 5 | A >>> 27) + f(B, C, D) + X[idx++] + Y1;
154: B = B << 30 | B >>> 2;
155:
156: D += (E << 5 | E >>> 27) + f(A, B, C) + X[idx++] + Y1;
157: A = A << 30 | A >>> 2;
158:
159: C += (D << 5 | D >>> 27) + f(E, A, B) + X[idx++] + Y1;
160: E = E << 30 | E >>> 2;
161:
162: B += (C << 5 | C >>> 27) + f(D, E, A) + X[idx++] + Y1;
163: D = D << 30 | D >>> 2;
164:
165: A += (B << 5 | B >>> 27) + f(C, D, E) + X[idx++] + Y1;
166: C = C << 30 | C >>> 2;
167: }
168:
169: //
170: // round 2
171: //
172: for (int j = 0; j < 4; j++) {
173: // E = rotateLeft(A, 5) + h(B, C, D) + E + X[idx++] + Y2
174: // B = rotateLeft(B, 30)
175: E += (A << 5 | A >>> 27) + h(B, C, D) + X[idx++] + Y2;
176: B = B << 30 | B >>> 2;
177:
178: D += (E << 5 | E >>> 27) + h(A, B, C) + X[idx++] + Y2;
179: A = A << 30 | A >>> 2;
180:
181: C += (D << 5 | D >>> 27) + h(E, A, B) + X[idx++] + Y2;
182: E = E << 30 | E >>> 2;
183:
184: B += (C << 5 | C >>> 27) + h(D, E, A) + X[idx++] + Y2;
185: D = D << 30 | D >>> 2;
186:
187: A += (B << 5 | B >>> 27) + h(C, D, E) + X[idx++] + Y2;
188: C = C << 30 | C >>> 2;
189: }
190:
191: //
192: // round 3
193: //
194: for (int j = 0; j < 4; j++) {
195: // E = rotateLeft(A, 5) + g(B, C, D) + E + X[idx++] + Y3
196: // B = rotateLeft(B, 30)
197: E += (A << 5 | A >>> 27) + g(B, C, D) + X[idx++] + Y3;
198: B = B << 30 | B >>> 2;
199:
200: D += (E << 5 | E >>> 27) + g(A, B, C) + X[idx++] + Y3;
201: A = A << 30 | A >>> 2;
202:
203: C += (D << 5 | D >>> 27) + g(E, A, B) + X[idx++] + Y3;
204: E = E << 30 | E >>> 2;
205:
206: B += (C << 5 | C >>> 27) + g(D, E, A) + X[idx++] + Y3;
207: D = D << 30 | D >>> 2;
208:
209: A += (B << 5 | B >>> 27) + g(C, D, E) + X[idx++] + Y3;
210: C = C << 30 | C >>> 2;
211: }
212:
213: //
214: // round 4
215: //
216: for (int j = 0; j <= 3; j++) {
217: // E = rotateLeft(A, 5) + h(B, C, D) + E + X[idx++] + Y4
218: // B = rotateLeft(B, 30)
219: E += (A << 5 | A >>> 27) + h(B, C, D) + X[idx++] + Y4;
220: B = B << 30 | B >>> 2;
221:
222: D += (E << 5 | E >>> 27) + h(A, B, C) + X[idx++] + Y4;
223: A = A << 30 | A >>> 2;
224:
225: C += (D << 5 | D >>> 27) + h(E, A, B) + X[idx++] + Y4;
226: E = E << 30 | E >>> 2;
227:
228: B += (C << 5 | C >>> 27) + h(D, E, A) + X[idx++] + Y4;
229: D = D << 30 | D >>> 2;
230:
231: A += (B << 5 | B >>> 27) + h(C, D, E) + X[idx++] + Y4;
232: C = C << 30 | C >>> 2;
233: }
234:
235: H1 += A;
236: H2 += B;
237: H3 += C;
238: H4 += D;
239: H5 += E;
240:
241: //
242: // reset start of the buffer.
243: //
244: xOff = 0;
245: for (int i = 0; i < 16; i++) {
246: X[i] = 0;
247: }
248: }
249: }
|