| /* SHA.java -- Class implementing the SHA-1 algorithm as specified in [1]. | |
| Copyright (C) 1999, 2000 Free Software Foundation, Inc. | |
| This file is part of GNU Classpath. | |
| GNU Classpath is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 2, or (at your option) | |
| any later version. | |
| GNU Classpath is distributed in the hope that it will be useful, but | |
| WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with GNU Classpath; see the file COPYING. If not, write to the | |
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
| 02111-1307 USA. | |
| As a special exception, if you link this library with other files to | |
| produce an executable, this library does not by itself cause the | |
| resulting executable to be covered by the GNU General Public License. | |
| This exception does not however invalidate any other reasons why the | |
| executable file might be covered by the GNU General Public License. */ | |
| package gnu.java.security.provider; | |
| import java.security.MessageDigest; | |
| /** | |
| This class implements the SHA-1 algorithm as described in [1]. | |
| [1] Federal Information Processing Standards Publication 180-1. | |
| Specifications for the Secure Hash Standard. April 17, 1995. | |
| @see java.security.MessageDigest | |
| */ | |
| public class SHA extends MessageDigest implements Cloneable | |
| { | |
| public SHA () | |
| { | |
| super("SHA"); | |
| engineReset (); | |
| } | |
| public int engineGetDigestLength() | |
| { | |
| return 16; | |
| } | |
| public void engineUpdate (byte b) | |
| { | |
| int i = (int)bytecount % 64; | |
| int shift = (3 - i % 4) * 8; | |
| int idx = i / 4; | |
| // if you could index ints, this would be: W[idx][shift/8] = b | |
| W[idx] = (W[idx] & ~(0xff << shift)) | ((b & 0xff) << shift); | |
| // if we've filled up a block, then process it | |
| if ((++ bytecount) % 64 == 0) | |
| munch (); | |
| } | |
| // This could be optimized. | |
| public void engineUpdate (byte bytes[], int off, int len) | |
| { | |
| if (len < 0) | |
| throw new ArrayIndexOutOfBoundsException (); | |
| int end = off + len; | |
| while (off < end) | |
| engineUpdate (bytes[off++]); | |
| } | |
| public void engineReset () | |
| { | |
| bytecount = 0; | |
| // magic numbers from [1] p. 10. | |
| H0 = 0x67452301; | |
| H1 = 0xefcdab89; | |
| H2 = 0x98badcfe; | |
| H3 = 0x10325476; | |
| H4 = 0xc3d2e1f0; | |
| } | |
| public byte[] engineDigest () | |
| { | |
| long bitcount = bytecount * 8; | |
| engineUpdate ((byte)0x80); // 10000000 in binary; the start of the padding | |
| // add the rest of the padding to fill this block out, but leave 8 | |
| // bytes to put in the original bytecount | |
| while ((int)bytecount % 64 != 56) | |
| engineUpdate ((byte)0); | |
| // add the length of the original, unpadded block to the end of | |
| // the padding | |
| W[14] = (int)(bitcount >>> 32); | |
| W[15] = (int)bitcount; | |
| bytecount += 8; | |
| // digest the fully padded block | |
| munch (); | |
| byte[] result | |
| = new byte[] {(byte)(H0 >>> 24), (byte)(H0 >>> 16), | |
| (byte)(H0 >>> 8), (byte)H0, | |
| (byte)(H1 >>> 24), (byte)(H1 >>> 16), | |
| (byte)(H1 >>> 8), (byte)H1, | |
| (byte)(H2 >>> 24), (byte)(H2 >>> 16), | |
| (byte)(H2 >>> 8), (byte)H2, | |
| (byte)(H3 >>> 24), (byte)(H3 >>> 16), | |
| (byte)(H3 >>> 8), (byte)H3, | |
| (byte)(H4 >>> 24), (byte)(H4 >>> 16), | |
| (byte)(H4 >>> 8), (byte)H4}; | |
| engineReset (); | |
| return result; | |
| } | |
| // Process a single block. This is pretty much copied verbatim from | |
| // [1] pp. 9, 10. | |
| private void munch () | |
| { | |
| for (int t = 16; t < 80; ++ t) | |
| { | |
| int Wt = W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]; | |
| W[t] = Wt << 1 | Wt >>> 31; | |
| } | |
| int A = H0; | |
| int B = H1; | |
| int C = H2; | |
| int D = H3; | |
| int E = H4; | |
| for (int t = 0; t < 20; ++ t) | |
| { | |
| int TEMP = (A << 5 | A >>> 27) // S^5(A) | |
| + ((B & C) | (~B & D)) // f_t(B,C,D) | |
| + E + W[t] | |
| + 0x5a827999; // K_t | |
| E = D; | |
| D = C; | |
| C = B << 30 | B >>> 2; // S^30(B) | |
| B = A; | |
| A = TEMP; | |
| } | |
| for (int t = 20; t < 40; ++ t) | |
| { | |
| int TEMP = (A << 5 | A >>> 27) // S^5(A) | |
| + (B ^ C ^ D) // f_t(B,C,D) | |
| + E + W[t] | |
| + 0x6ed9eba1; // K_t | |
| E = D; | |
| D = C; | |
| C = B << 30 | B >>> 2; // S^30(B) | |
| B = A; | |
| A = TEMP; | |
| } | |
| for (int t = 40; t < 60; ++ t) | |
| { | |
| int TEMP = (A << 5 | A >>> 27) // S^5(A) | |
| + (B & C | B & D | C & D) // f_t(B,C,D) | |
| + E + W[t] | |
| + 0x8f1bbcdc; // K_t | |
| E = D; | |
| D = C; | |
| C = B << 30 | B >>> 2; // S^30(B) | |
| B = A; | |
| A = TEMP; | |
| } | |
| for (int t = 60; t < 80; ++ t) | |
| { | |
| int TEMP = (A << 5 | A >>> 27) // S^5(A) | |
| + (B ^ C ^ D) // f_t(B,C,D) | |
| + E + W[t] | |
| + 0xca62c1d6; // K_t | |
| E = D; | |
| D = C; | |
| C = B << 30 | B >>> 2; // S^30(B) | |
| B = A; | |
| A = TEMP; | |
| } | |
| H0 += A; | |
| H1 += B; | |
| H2 += C; | |
| H3 += D; | |
| H4 += E; | |
| // Reset W by clearing it. | |
| for (int t = 0; t < 80; ++ t) | |
| W[t] = 0; | |
| } | |
| public Object clone () | |
| { | |
| return new SHA (this); | |
| } | |
| private SHA (SHA copy) | |
| { | |
| this (); | |
| bytecount = copy.bytecount; | |
| H0 = copy.H0; | |
| H1 = copy.H1; | |
| H2 = copy.H2; | |
| H3 = copy.H3; | |
| H4 = copy.H4; | |
| System.arraycopy (copy.W, 0, W, 0, 80); | |
| } | |
| private final int W[] = new int[80]; | |
| private long bytecount; | |
| private int H0; | |
| private int H1; | |
| private int H2; | |
| private int H3; | |
| private int H4; | |
| } |