summaryrefslogtreecommitdiffstats
path: root/pki/base/util/src/netscape/security/provider/SHA.java
diff options
context:
space:
mode:
Diffstat (limited to 'pki/base/util/src/netscape/security/provider/SHA.java')
-rw-r--r--pki/base/util/src/netscape/security/provider/SHA.java362
1 files changed, 362 insertions, 0 deletions
diff --git a/pki/base/util/src/netscape/security/provider/SHA.java b/pki/base/util/src/netscape/security/provider/SHA.java
new file mode 100644
index 000000000..09fdf2dfa
--- /dev/null
+++ b/pki/base/util/src/netscape/security/provider/SHA.java
@@ -0,0 +1,362 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program 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; version 2 of the License.
+//
+// This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.provider;
+
+import java.security.*;
+
+/**
+ * This class implements the Secure Hash Algorithm (SHA) developed by
+ * the National Institute of Standards and Technology along with the
+ * National Security Agency. This is the updated version of SHA
+ * fip-180 as superseded by fip-180-1.
+ *
+ * <p>It implement JavaSecurity MessageDigest, and can be used by in
+ * the Java Security framework, as a pluggable implementation, as a
+ * filter for the digest stream classes.
+ *
+ * @version 1.30 97/12/10
+ * @author Roger Riggs
+ * @author Benjamin Renaud
+ */
+
+public class SHA extends MessageDigestSpi implements Cloneable {
+
+ /* This private hookm controlled by the appropriate constructor,
+ causes this class to implement the first version of SHA,
+ as defined in FIPS 180, as opposed to FIPS 180-1. This was
+ useful for DSA testing. */
+ private int version = 1;
+
+ private static final int SHA_LENGTH = 20;
+
+ // Buffer of int's and count of characters accumulated
+ // 64 bytes are included in each hash block so the low order
+ // bits of count are used to know how to pack the bytes into ints
+ // and to know when to compute the block and start the next one.
+ private int W[] = new int[80];
+ private long count = 0;
+ private final int countmax = 64;
+ private final int countmask = (countmax-1);
+
+ private int AA, BB, CC, DD, EE;
+
+ /**
+ * Creates a SHA object.with state (for cloning) */
+ private SHA(SHA sha) {
+ this();
+ this.version = sha.version;
+ System.arraycopy(sha.W, 0, this.W, 0, W.length);
+ this.count = sha.count;
+ this.AA = sha.AA;
+ this.BB = sha.BB;
+ this.CC = sha.CC;
+ this.DD = sha.DD;
+ this.EE = sha.EE;
+ }
+
+ SHA(int version) {
+ this();
+ this.version = version;
+ }
+
+ /**
+ * Creates a new SHA object.
+ */
+ public SHA() {
+ init();
+ }
+
+ /**
+ * Return the length of the digest in bytes
+ */
+ protected int engineGetDigestLength() {
+ return (SHA_LENGTH);
+ }
+
+ public void engineUpdate(byte b) {
+ engineUpdate((int)b);
+ }
+
+ /**
+ * Update a byte.
+ *
+ * @param b the byte
+ */
+ private void engineUpdate(int b) {
+ int word;
+ int offset;
+
+ /* compute word offset and bit offset within word the low bits
+ of count are inverted to make put the bytes in the write
+ order */
+ word = ((int)count & countmask) >>> 2;
+ offset = (~(int)count & 3) << 3;
+
+ W[word] = (W[word] & ~(0xff << offset)) | ((b & 0xff) << offset);
+
+ /* If this is the last byte of a block, compute the partial hash */
+ if (((int)count & countmask) == countmask) {
+ computeBlock();
+ }
+ count++;
+ }
+
+ /**
+ * Update a buffer.
+ *
+ * @param b the data to be updated.
+ * @param off the start offset in the data
+ * @param len the number of bytes to be updated.
+ */
+ public void engineUpdate(byte b[], int off, int len) {
+ int word;
+ int offset;
+
+ if ((off < 0) || (len < 0) || (off + len > b.length))
+ throw new ArrayIndexOutOfBoundsException();
+
+ // Use single writes until integer aligned
+ while ((len > 0) &&
+ ((int)count & 3) != 0) {
+ engineUpdate(b[off]);
+ off++;
+ len--;
+ }
+
+ /* Assemble groups of 4 bytes to be inserted in integer array */
+ for (;len >= 4; len -= 4, off += 4) {
+
+ word = ((int)count & countmask) >> 2;
+
+ W[word] = ((b[off] & 0xff) << 24) |
+ ((b[off+1] & 0xff) << 16) |
+ ((b[off+2] & 0xff) << 8) |
+ ((b[off+3] & 0xff) );
+
+ count += 4;
+ if (((int)count & countmask) == 0) {
+ computeBlock();
+ }
+ }
+
+ /* Use single writes for last few bytes */
+ for (; len > 0; len--, off++) {
+ engineUpdate(b[off]);
+ }
+ }
+
+ /**
+ * Resets the buffers and hash value to start a new hash.
+ */
+ public void init() {
+ AA = 0x67452301;
+ BB = 0xefcdab89;
+ CC = 0x98badcfe;
+ DD = 0x10325476;
+ EE = 0xc3d2e1f0;
+
+ for (int i = 0; i < 80; i++)
+ W[i] = 0;
+ count = 0;
+ }
+
+ /**
+ * Resets the buffers and hash value to start a new hash.
+ */
+ public void engineReset() {
+ init();
+ }
+
+ /**
+ * Computes the final hash and returns the final value as a
+ * byte[20] array. The object is reset to be ready for further
+ * use, as specified in the JavaSecurity MessageDigest
+ * specification. */
+ public byte[] engineDigest() {
+ byte hashvalue[] = new byte[SHA_LENGTH];
+
+ try {
+ int outLen = engineDigest(hashvalue, 0, hashvalue.length);
+ } catch (DigestException e) {
+ throw new InternalError("");
+ }
+ return hashvalue;
+ }
+
+ /**
+ * Computes the final hash and returns the final value as a
+ * byte[20] array. The object is reset to be ready for further
+ * use, as specified in the JavaSecurity MessageDigest
+ * specification. */
+ public int engineDigest(byte[] hashvalue, int offset, int len)
+ throws DigestException {
+
+ if (len < SHA_LENGTH)
+ throw new DigestException("partial digests not returned");
+ if (hashvalue.length - offset < SHA_LENGTH)
+ throw new DigestException("insufficient space in the output " +
+ "buffer to store the digest");
+
+ /* The number of bits before padding occurs */
+ long bits = count << 3;
+
+ engineUpdate(0x80);
+
+ /* Pad with zeros until length is a multiple of 448 (the last two
+ 32 ints are used a holder for bits (see above). */
+ while ((int)(count & countmask) != 56) {
+ engineUpdate(0);
+ }
+
+ W[14] = (int)(bits >>> 32);
+ W[15] = (int)(bits & 0xffffffff);
+
+ count += 8;
+ computeBlock();
+
+ // Copy out the result
+ hashvalue[offset + 0] = (byte)(AA >>> 24);
+ hashvalue[offset + 1] = (byte)(AA >>> 16);
+ hashvalue[offset + 2] = (byte)(AA >>> 8);
+ hashvalue[offset + 3] = (byte)(AA >>> 0);
+
+ hashvalue[offset + 4] = (byte)(BB >>> 24);
+ hashvalue[offset + 5] = (byte)(BB >>> 16);
+ hashvalue[offset + 6] = (byte)(BB >>> 8);
+ hashvalue[offset + 7] = (byte)(BB >>> 0);
+
+ hashvalue[offset + 8] = (byte)(CC >>> 24);
+ hashvalue[offset + 9] = (byte)(CC >>> 16);
+ hashvalue[offset + 10] = (byte)(CC >>> 8);
+ hashvalue[offset + 11] = (byte)(CC >>> 0);
+
+ hashvalue[offset + 12] = (byte)(DD >>> 24);
+ hashvalue[offset + 13] = (byte)(DD >>> 16);
+ hashvalue[offset + 14] = (byte)(DD >>> 8);
+ hashvalue[offset + 15] = (byte)(DD >>> 0);
+
+ hashvalue[offset + 16] = (byte)(EE >>> 24);
+ hashvalue[offset + 17] = (byte)(EE >>> 16);
+ hashvalue[offset + 18] = (byte)(EE >>> 8);
+ hashvalue[offset + 19] = (byte)(EE >>> 0);
+
+ engineReset(); // remove the evidence
+
+ return SHA_LENGTH;
+ }
+
+ // Constants for each round
+ private final int round1_kt = 0x5a827999;
+ private final int round2_kt = 0x6ed9eba1;
+ private final int round3_kt = 0x8f1bbcdc;
+ private final int round4_kt = 0xca62c1d6;
+
+ /**
+ * Compute a the hash for the current block.
+ *
+ * This is in the same vein as Peter Gutmann's algorithm listed in
+ * the back of Applied Cryptography, Compact implementation of
+ * "old" NIST Secure Hash Algorithm.
+ *
+ */
+ private void computeBlock() {
+ int temp, a, b, c, d, e;
+
+ // The first 16 ints have the byte stream, compute the rest of
+ // the buffer
+ for (int t = 16; t <= 79; t++) {
+ if (version == 0) {
+ W[t] = W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16];
+ } else {
+ temp = W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16];
+ W[t] = ((temp << 1) | (temp >>>(32 - 1)));
+ }
+ }
+
+ a = AA;
+ b = BB;
+ c = CC;
+ d = DD;
+ e = EE;
+
+ // Round 1
+ for (int i = 0; i < 20; i++) {
+ temp = ((a<<5) | (a>>>(32-5))) +
+ ((b&c)|((~b)&d))+ e + W[i] + round1_kt;
+ e = d;
+ d = c;
+ c = ((b<<30) | (b>>>(32-30)));
+ b = a;
+ a = temp;
+ }
+
+ // Round 2
+ for (int i = 20; i < 40; i++) {
+ temp = ((a<<5) | (a>>>(32-5))) +
+ (b ^ c ^ d) + e + W[i] + round2_kt;
+ e = d;
+ d = c;
+ c = ((b<<30) | (b>>>(32-30)));
+ b = a;
+ a = temp;
+ }
+
+ // Round 3
+ for (int i = 40; i < 60; i++) {
+ temp = ((a<<5) | (a>>>(32-5))) +
+ ((b&c)|(b&d)|(c&d)) + e + W[i] + round3_kt;
+ e = d;
+ d = c;
+ c = ((b<<30) | (b>>>(32-30)));
+ b = a;
+ a = temp;
+ }
+
+ // Round 4
+ for (int i = 60; i < 80; i++) {
+ temp = ((a<<5) | (a>>>(32-5))) +
+ (b ^ c ^ d) + e + W[i] + round4_kt;
+ e = d;
+ d = c;
+ c = ((b<<30) | (b>>>(32-30)));
+ b = a;
+ a = temp;
+ }
+ AA += a;
+ BB += b;
+ CC += c;
+ DD += d;
+ EE += e;
+ }
+
+ /*
+ * Clones this object.
+ */
+ public Object clone() {
+ SHA that = null;
+ try {
+ that = (SHA)super.clone();
+ that.W = new int[80];
+ System.arraycopy(this.W, 0, that.W, 0, W.length);
+ return that;
+ } catch (CloneNotSupportedException e) {
+ }
+ return that;
+ }
+}
+