001: /*
002: * $Id: SHA.java,v 1.1 2003/03/27 11:16:09 bs126381 Exp $
003: *
004: * Implements the SHA hashing algorithm.
005: *
006: * $Log: SHA.java,v $
007: * Revision 1.1 2003/03/27 11:16:09 bs126381
008: * Netlet on SSL, SunRay
009: *
010: * Revision 1.1.2.1 2003/01/27 09:51:38 bs126381
011: * Netlet on SSL
012: *
013: * Revision 1.2 2000/03/31 02:25:11 vgupta
014: * Modified reset() to zero out block and dd.
015: *
016: * Revision 1.1 2000/03/29 02:52:05 vgupta
017: * Initial revision
018: *
019: *
020: * --------------------------------------------------------------
021: * This is based on SHA1.java by Chuck McManis:
022: *
023: * SHA1.java - An implementation of the SHA-1 Algorithm
024: *
025: * This version by Chuck McManis (cmcmanis@netcom.com) and
026: * still public domain.
027: *
028: * Based on the C code that Steve Reid wrote his header
029: * was :
030: * SHA-1 in C
031: * By Steve Reid <steve@edmweb.com>
032: * 100% Public Domain
033: *
034: * Test Vectors (from FIPS PUB 180-1)
035: * "abc"
036: * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
037: * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
038: * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
039: * A million repetitions of "a"
040: * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
041: */
042:
043: // package javacard.security;
044: package com.sun.portal.ksecurity;
045:
046: /*
047: * This is a simple port of Steve Reid's SHA-1 code into Java.
048: * I've run his test vectors through the code and they all pass.
049: *
050: */
051: final class SHA extends MessageDigest {
052: /*
053: * The following array forms the basis for the transform
054: * buffer. Update puts bytes into this buffer and then
055: * transform adds it into the state of the digest.
056: */
057: /** Indicates the MD5 message digest algorithm. */
058: // public static final byte ALG_MD5 = 1;
059: /** Indicates the SHA message digest algorithm. */
060: // public static final byte ALG_SHA = 2;
061:
062: private int[] block = new int[16];
063: private int blockIndex;
064: private int[] dd = new int[5];
065: private int[] state = new int[5];
066: private long count = (long) 0;
067: private byte type;
068: private byte len;
069:
070: // Temporary variables used in R0-R4
071: private int tmp;
072:
073: SHA() {
074: type = ALG_SHA;
075: len = 20;
076: reset();
077: }
078:
079: public byte getAlgorithm() {
080: return type;
081: }
082:
083: public byte getLength() {
084: return len;
085: }
086:
087: public void reset() {
088: /* SHA1 initialization constants */
089: state[0] = 0x67452301;
090: state[1] = 0xEFCDAB89;
091: state[2] = 0x98BADCFE;
092: state[3] = 0x10325476;
093: state[4] = 0xC3D2E1F0;
094: count = 0;
095: blockIndex = 0;
096: for (int i = 0; i < 16; i++)
097: block[i] = 0;
098: for (int i = 0; i < 5; i++)
099: dd[i] = 0;
100: type = ALG_SHA;
101: len = 20;
102: }
103:
104: private final void R0(int data[], int v, int w, int x, int y,
105: int z, int i) {
106: block[i] = (((block[i] << 24) | (block[i] >>> 8)) & 0xFF00FF00)
107: | (((block[i] << 8) | (block[i] >>> 24)) & 0x00FF00FF);
108: data[z] += ((data[w] & (data[x] ^ data[y])) ^ data[y])
109: + block[i] + 0x5A827999
110: + ((data[v] << 5) | (data[v] >>> 27));
111: data[w] = (data[w] << 30) | (data[w] >>> 2);
112: }
113:
114: private final void R1(int data[], int v, int w, int x, int y,
115: int z, int i) {
116: tmp = block[(i + 13) & 15] ^ block[(i + 8) & 15]
117: ^ block[(i + 2) & 15] ^ block[i & 15];
118: tmp = (tmp << 1) | (tmp >>> 31);
119: block[i & 15] = tmp;
120:
121: data[z] += ((data[w] & (data[x] ^ data[y])) ^ data[y]) + tmp
122: + 0x5A827999 + ((data[v] << 5) | (data[v] >>> 27));
123: data[w] = (data[w] << 30) | (data[w] >>> 2);
124: }
125:
126: private final void R2(int data[], int v, int w, int x, int y,
127: int z, int i) {
128: tmp = block[(i + 13) & 15] ^ block[(i + 8) & 15]
129: ^ block[(i + 2) & 15] ^ block[i & 15];
130: tmp = (tmp << 1) | (tmp >>> 31);
131: block[i & 15] = tmp;
132:
133: data[z] += (data[w] ^ data[x] ^ data[y]) + tmp + 0x6ED9EBA1
134: + ((data[v] << 5) | (data[v] >>> 27));
135: data[w] = (data[w] << 30) | (data[w] >>> 2);
136: }
137:
138: private final void R3(int data[], int v, int w, int x, int y,
139: int z, int i) {
140: tmp = block[(i + 13) & 15] ^ block[(i + 8) & 15]
141: ^ block[(i + 2) & 15] ^ block[i & 15];
142: tmp = (tmp << 1) | (tmp >>> 31);
143: block[i & 15] = tmp;
144:
145: data[z] += (((data[w] | data[x]) & data[y]) | (data[w] & data[x]))
146: + tmp
147: + 0x8F1BBCDC
148: + ((data[v] << 5) | (data[v] >>> 27));
149: data[w] = (data[w] << 30) | (data[w] >>> 2);
150: }
151:
152: private final void R4(int data[], int v, int w, int x, int y,
153: int z, int i) {
154: tmp = block[(i + 13) & 15] ^ block[(i + 8) & 15]
155: ^ block[(i + 2) & 15] ^ block[i & 15];
156: tmp = (tmp << 1) | (tmp >>> 31);
157: block[i & 15] = tmp;
158:
159: data[z] += (data[w] ^ data[x] ^ data[y]) + tmp + 0xCA62C1D6
160: + ((data[v] << 5) | (data[v] >>> 27));
161: data[w] = (data[w] << 30) | (data[w] >>> 2);
162: }
163:
164: /*
165: * Steve's original code and comments :
166: *
167: * blk0() and blk() perform the initial expand.
168: * I got the idea of expanding during the round function from SSLeay
169: *
170: * #define blk0(i) block->l[i]
171: * #define blk(i) (block->l[i&15] =
172: * rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
173: * ^block->l[(i+2)&15]^block->l[i&15],1))
174: *
175: * (R0+R1), R2, R3, R4 are the different operations used in SHA1
176: * #define R0(v,w,x,y,z,i)
177: * z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
178: * #define R1(v,w,x,y,z,i)
179: * z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
180: * #define R2(v,w,x,y,z,i)
181: * z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
182: * #define R3(v,w,x,y,z,i)
183: * z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
184: * #define R4(v,w,x,y,z,i)
185: * z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
186: */
187:
188: /**
189: * Hash a single 512-bit block. This is the core of the algorithm.
190: *
191: * Note that working with arrays is very inefficent in Java as it
192: * does a class cast check each time you store into the array.
193: *
194: */
195: private void transform() {
196: /* Copy context->state[] to working vars */
197: dd[0] = state[0];
198: dd[1] = state[1];
199: dd[2] = state[2];
200: dd[3] = state[3];
201: dd[4] = state[4];
202: /* 4 rounds of 20 operations each. Loop unrolled. */
203: R0(dd, 0, 1, 2, 3, 4, 0);
204: R0(dd, 4, 0, 1, 2, 3, 1);
205: R0(dd, 3, 4, 0, 1, 2, 2);
206: R0(dd, 2, 3, 4, 0, 1, 3);
207: R0(dd, 1, 2, 3, 4, 0, 4);
208: R0(dd, 0, 1, 2, 3, 4, 5);
209: R0(dd, 4, 0, 1, 2, 3, 6);
210: R0(dd, 3, 4, 0, 1, 2, 7);
211: R0(dd, 2, 3, 4, 0, 1, 8);
212: R0(dd, 1, 2, 3, 4, 0, 9);
213: R0(dd, 0, 1, 2, 3, 4, 10);
214: R0(dd, 4, 0, 1, 2, 3, 11);
215: R0(dd, 3, 4, 0, 1, 2, 12);
216: R0(dd, 2, 3, 4, 0, 1, 13);
217: R0(dd, 1, 2, 3, 4, 0, 14);
218: R0(dd, 0, 1, 2, 3, 4, 15);
219: R1(dd, 4, 0, 1, 2, 3, 16);
220: R1(dd, 3, 4, 0, 1, 2, 17);
221: R1(dd, 2, 3, 4, 0, 1, 18);
222: R1(dd, 1, 2, 3, 4, 0, 19);
223: R2(dd, 0, 1, 2, 3, 4, 20);
224: R2(dd, 4, 0, 1, 2, 3, 21);
225: R2(dd, 3, 4, 0, 1, 2, 22);
226: R2(dd, 2, 3, 4, 0, 1, 23);
227: R2(dd, 1, 2, 3, 4, 0, 24);
228: R2(dd, 0, 1, 2, 3, 4, 25);
229: R2(dd, 4, 0, 1, 2, 3, 26);
230: R2(dd, 3, 4, 0, 1, 2, 27);
231: R2(dd, 2, 3, 4, 0, 1, 28);
232: R2(dd, 1, 2, 3, 4, 0, 29);
233: R2(dd, 0, 1, 2, 3, 4, 30);
234: R2(dd, 4, 0, 1, 2, 3, 31);
235: R2(dd, 3, 4, 0, 1, 2, 32);
236: R2(dd, 2, 3, 4, 0, 1, 33);
237: R2(dd, 1, 2, 3, 4, 0, 34);
238: R2(dd, 0, 1, 2, 3, 4, 35);
239: R2(dd, 4, 0, 1, 2, 3, 36);
240: R2(dd, 3, 4, 0, 1, 2, 37);
241: R2(dd, 2, 3, 4, 0, 1, 38);
242: R2(dd, 1, 2, 3, 4, 0, 39);
243: R3(dd, 0, 1, 2, 3, 4, 40);
244: R3(dd, 4, 0, 1, 2, 3, 41);
245: R3(dd, 3, 4, 0, 1, 2, 42);
246: R3(dd, 2, 3, 4, 0, 1, 43);
247: R3(dd, 1, 2, 3, 4, 0, 44);
248: R3(dd, 0, 1, 2, 3, 4, 45);
249: R3(dd, 4, 0, 1, 2, 3, 46);
250: R3(dd, 3, 4, 0, 1, 2, 47);
251: R3(dd, 2, 3, 4, 0, 1, 48);
252: R3(dd, 1, 2, 3, 4, 0, 49);
253: R3(dd, 0, 1, 2, 3, 4, 50);
254: R3(dd, 4, 0, 1, 2, 3, 51);
255: R3(dd, 3, 4, 0, 1, 2, 52);
256: R3(dd, 2, 3, 4, 0, 1, 53);
257: R3(dd, 1, 2, 3, 4, 0, 54);
258: R3(dd, 0, 1, 2, 3, 4, 55);
259: R3(dd, 4, 0, 1, 2, 3, 56);
260: R3(dd, 3, 4, 0, 1, 2, 57);
261: R3(dd, 2, 3, 4, 0, 1, 58);
262: R3(dd, 1, 2, 3, 4, 0, 59);
263: R4(dd, 0, 1, 2, 3, 4, 60);
264: R4(dd, 4, 0, 1, 2, 3, 61);
265: R4(dd, 3, 4, 0, 1, 2, 62);
266: R4(dd, 2, 3, 4, 0, 1, 63);
267: R4(dd, 1, 2, 3, 4, 0, 64);
268: R4(dd, 0, 1, 2, 3, 4, 65);
269: R4(dd, 4, 0, 1, 2, 3, 66);
270: R4(dd, 3, 4, 0, 1, 2, 67);
271: R4(dd, 2, 3, 4, 0, 1, 68);
272: R4(dd, 1, 2, 3, 4, 0, 69);
273: R4(dd, 0, 1, 2, 3, 4, 70);
274: R4(dd, 4, 0, 1, 2, 3, 71);
275: R4(dd, 3, 4, 0, 1, 2, 72);
276: R4(dd, 2, 3, 4, 0, 1, 73);
277: R4(dd, 1, 2, 3, 4, 0, 74);
278: R4(dd, 0, 1, 2, 3, 4, 75);
279: R4(dd, 4, 0, 1, 2, 3, 76);
280: R4(dd, 3, 4, 0, 1, 2, 77);
281: R4(dd, 2, 3, 4, 0, 1, 78);
282: R4(dd, 1, 2, 3, 4, 0, 79);
283:
284: /* Add the working vars back into context.state[] */
285: state[0] += dd[0];
286: state[1] += dd[1];
287: state[2] += dd[2];
288: state[3] += dd[3];
289: state[4] += dd[4];
290: }
291:
292: public void update(byte[] buf, int off, int len) {
293: int mask = 0;
294:
295: if (buf == null)
296: return;
297: for (int i = off; i < (off + len); i++) {
298: mask = (blockIndex & 3) << 3;
299:
300: block[blockIndex >> 2] &= ~(0xff << mask);
301: block[blockIndex >> 2] |= (buf[i] & 0xff) << mask;
302: blockIndex++;
303: if (blockIndex == 64) {
304: transform();
305: blockIndex = 0;
306: }
307: }
308: count += (len << 3);
309: }
310:
311: public short doFinal(byte[] inBuf, int inOff, int inLen,
312: byte[] outBuf, int outOff) {
313: // check parameters to avoid a VM crash
314: int test = outBuf[outOff] + outBuf[outOff + this .len - 1];
315:
316: this .update(inBuf, inOff, inLen);
317: System.arraycopy(this .digest(), 0, outBuf, outOff, this .len);
318: reset();
319: return (short) 20;
320: }
321:
322: /**
323: * Complete processing on the message digest.
324: */
325: private byte[] digest() {
326: byte[] result = new byte[20];
327: byte bits[] = new byte[8];
328: int i, j;
329:
330: for (i = 0; i < 8; i++) {
331: bits[i] = (byte) ((count >>> (((7 - i) * 8))) & 0xff);
332: }
333:
334: int padLen = 64 - 9 - blockIndex;
335: if (padLen < 0)
336: padLen += 64;
337: byte[] pad = new byte[padLen + 1];
338: pad[0] = (byte) 128;
339: for (i = 1; i < padLen + 1; i++) {
340: pad[i] = (byte) 0;
341: }
342: update(pad, (short) 0, (short) (padLen + 1));
343: update(bits, (short) 0, (short) 8);
344:
345: for (i = 0; i < 20; i++) {
346: result[i] = (byte) ((state[i >> 2] >> ((3 - (i & 3)) * 8)) & 0xff);
347: }
348: return result;
349: }
350:
351: public Object clone() {
352: SHA cpy = new SHA();
353:
354: System.arraycopy(this .block, 0, cpy.block, 0, 16);
355: System.arraycopy(this .dd, 0, cpy.dd, 0, 5);
356: System.arraycopy(this .state, 0, cpy.state, 0, 5);
357: cpy.blockIndex = this.blockIndex;
358: cpy.count = this.count;
359: cpy.type = this.type;
360: cpy.len = this.len;
361: return cpy;
362: }
363: }
|