/*
* SHA1.java - An implementation of the SHA-1 Algorithm
*
* Modified for Jython by Finn Bock. The original was split
* into two files.
*
* Original author and copyright:
*
* Copyright (c) 1997 Systemics Ltd
* on behalf of the Cryptix Development Team. All rights reserved.
* @author David Hopwood
*
* Cryptix General License
* Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000 The Cryptix Foundation
* Limited.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the
* following conditions are met:
*
* - Redistributions of source code must retain the copyright notice, this
* list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE CRYPTIX FOUNDATION LIMITED
* AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CRYPTIX FOUNDATION LIMITED
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.python.modules;
import java.io.UnsupportedEncodingException;
import org.python.core.*;
/**
* This class implements the SHA-1 message digest algorithm.
* <p>
* <b>References:</b>
* <ol>
* <li> Bruce Schneier,
* "Section 18.7 Secure Hash Algorithm (SHA),"
* <cite>Applied Cryptography, 2nd edition</cite>,
* John Wiley & Sons, 1996
* <p>
* <li> NIST FIPS PUB 180-1,
* "Secure Hash Standard",
* U.S. Department of Commerce, May 1993.<br>
* <a href="http://www.itl.nist.gov/div897/pubs/fip180-1.htm">
* http://www.itl.nist.gov/div897/pubs/fip180-1.htm</a>
* </ol>
* <p>
* <b>Copyright</b> © 1995-1997
* <a href="http://www.systemics.com/">Systemics Ltd</a> on behalf of the
* <a href="http://www.systemics.com/docs/cryptix/">Cryptix Development
* Team</a>.
* <br>All rights reserved.
* <p>
* <b>Revision: 1.7</b>
* @author Systemics Ltd
* @author David Hopwood
* @since Cryptix 2.2.2
*/
public final class SHA1 {
/**
* The buffer used to store the last incomplete block.
*/
private byte[] buffer;
/**
* The number of bytes currently stored in <code>buffer</code>.
*/
private int buffered;
/**
* The number of bytes that have been input to the digest.
*/
private long count;
public int digest_size = 20;
/**
* <b>SPI</b>: Updates the message digest with a byte of new data.
*
* @param b the byte to be added.
*/
protected void engineUpdate(byte b) {
byte[] data = { b };
engineUpdate(data, 0, 1);
}
/**
* <b>SPI</b>: Updates the message digest with new data.
*
* @param data the data to be added.
* @param offset the start of the data in the array.
* @param length the number of bytes of data to add.
*/
protected void engineUpdate(byte[] data, int offset, int length) {
count += length;
int datalen = DATA_LENGTH;
int remainder;
while (length >= (remainder = datalen - buffered)) {
System.arraycopy(data, offset, buffer, buffered, remainder);
engineTransform(buffer);
length -= remainder;
offset += remainder;
buffered = 0;
}
if (length > 0) {
System.arraycopy(data, offset, buffer, buffered, length);
buffered += length;
}
}
/**
* <b>SPI</b>: Calculates the final digest. BlockMessageDigest
* subclasses should not usually override this method.
*
* @return the digest as a byte array.
*/
protected byte[] engineDigest() {
return engineDigest(buffer, buffered);
}
// SHA-1 constants and variables
//...........................................................................
/**
* Length of the final hash (in bytes).
*/
private static final int HASH_LENGTH = 20;
/**
* Length of a block (i.e. the number of bytes hashed in every transform).
*/
private static final int DATA_LENGTH = 64;
private int[] data;
private int[] digest;
private byte[] tmp;
private int[] w;
/**
* Constructs a SHA-1 message digest.
*/
public SHA1() {
buffer = new byte[DATA_LENGTH];
java_init();
engineReset();
}
private void java_init() {
digest = new int[HASH_LENGTH / 4];
data = new int[DATA_LENGTH / 4];
tmp = new byte[DATA_LENGTH];
w = new int[80];
}
/**
* This constructor is here to implement cloneability of this class.
*/
private SHA1(SHA1 md) {
this();
data = (int[]) md.data.clone();
digest = (int[]) md.digest.clone();
tmp = (byte[]) md.tmp.clone();
w = (int[]) md.w.clone();
buffer = (byte[]) md.buffer.clone();
buffered = md.buffered;
count = md.count;
}
/**
* Initializes (resets) the message digest.
*/
protected void engineReset() {
buffered = 0;
count = 0;
java_reset();
}
private void java_reset() {
digest[0] = 0x67452301;
digest[1] = 0xefcdab89;
digest[2] = 0x98badcfe;
digest[3] = 0x10325476;
digest[4] = 0xc3d2e1f0;
}
/**
* Adds data to the message digest.
*
* @param data The data to be added.
* @param offset The start of the data in the array.
* @param length The amount of data to add.
*/
protected void engineTransform(byte[] in) {
java_transform(in);
}
private void java_transform(byte[] in) {
byte2int(in, 0, data, 0, DATA_LENGTH / 4);
transform(data);
}
/**
* Returns the digest of the data added and resets the digest.
* @return the digest of all the data added to the message digest
* as a byte array.
*/
protected byte[] engineDigest(byte[] in, int length) {
byte b[] = java_digest(in, length);
return b;
}
private byte[] java_digest(byte[] in, int pos) {
int[] digest_save = (int[]) digest.clone();
if (pos != 0)
System.arraycopy(in, 0, tmp, 0, pos);
tmp[pos++] = (byte) 0x80;
if (pos > DATA_LENGTH - 8) {
while (pos < DATA_LENGTH)
tmp[pos++] = 0;
byte2int(tmp, 0, data, 0, DATA_LENGTH / 4);
transform(data);
pos = 0;
}
while (pos < DATA_LENGTH - 8)
tmp[pos++] = 0;
byte2int(tmp, 0, data, 0, (DATA_LENGTH / 4) - 2);
// Big endian
// WARNING: int>>>32 != 0 !!!
// bitcount() used to return a long, now it's an int.
long bc = count * 8;
data[14] = (int) (bc >>> 32);
data[15] = (int) bc;
transform(data);
byte buf[] = new byte[HASH_LENGTH];
// Big endian
int off = 0;
for (int i = 0; i < HASH_LENGTH / 4; ++i) {
int d = digest[i];
buf[off++] = (byte) (d >>> 24);
buf[off++] = (byte) (d >>> 16);
buf[off++] = (byte) (d >>> 8);
buf[off++] = (byte) d;
}
digest = digest_save;
return buf;
}
// SHA-1 transform routines
//...........................................................................
private static int f1(int a, int b, int c) {
return (c ^ (a & (b ^ c))) + 0x5A827999;
}
private static int f2(int a, int b, int c) {
return (a ^ b ^ c) + 0x6ED9EBA1;
}
private static int f3(int a, int b, int c) {
return ((a & b) | (c & (a | b))) + 0x8F1BBCDC;
}
private static int f4(int a, int b, int c) {
return (a ^ b ^ c) + 0xCA62C1D6;
}
private void transform(int[] X) {
int A = digest[0];
int B = digest[1];
int C = digest[2];
int D = digest[3];
int E = digest[4];
int W[] = w;
for (int i = 0; i < 16; i++) {
W[i] = X[i];
}
for (int i = 16; i < 80; i++) {
int j = W[i - 16] ^ W[i - 14] ^ W[i - 8] ^ W[i - 3];
W[i] = j;
W[i] = (j << 1) | (j >>> -1);
}
E += ((A << 5) | (A >>> -5)) + f1(B, C, D) + W[0];
B = ((B << 30) | (B >>> -30));
D += ((E << 5) | (E >>> -5)) + f1(A, B, C) + W[1];
A = ((A << 30) | (A >>> -30));
C += ((D << 5) | (D >>> -5)) + f1(E, A, B) + W[2];
E = ((E << 30) | (E >>> -30));
B += ((C << 5) | (C >>> -5)) + f1(D, E, A) + W[3];
D = ((D << 30) | (D >>> -30));
A += ((B << 5) | (B >>> -5)) + f1(C, D, E) + W[4];
C = ((C << 30) | (C >>> -30));
E += ((A << 5) | (A >>> -5)) + f1(B, C, D) + W[5];
B = ((B << 30) | (B >>> -30));
D += ((E << 5) | (E >>> -5)) + f1(A, B, C) + W[6];
A = ((A << 30) | (A >>> -30));
C += ((D << 5) | (D >>> -5)) + f1(E, A, B) + W[7];
E = ((E << 30) | (E >>> -30));
B += ((C << 5) | (C >>> -5)) + f1(D, E, A) + W[8];
D = ((D << 30) | (D >>> -30));
A += ((B << 5) | (B >>> -5)) + f1(C, D, E) + W[9];
C = ((C << 30) | (C >>> -30));
E += ((A << 5) | (A >>> -5)) + f1(B, C, D) + W[10];
B = ((B << 30) | (B >>> -30));
D += ((E << 5) | (E >>> -5)) + f1(A, B, C) + W[11];
A = ((A << 30) | (A >>> -30));
C += ((D << 5) | (D >>> -5)) + f1(E, A, B) + W[12];
E = ((E << 30) | (E >>> -30));
B += ((C << 5) | (C >>> -5)) + f1(D, E, A) + W[13];
D = ((D << 30) | (D >>> -30));
A += ((B << 5) | (B >>> -5)) + f1(C, D, E) + W[14];
C = ((C << 30) | (C >>> -30));
E += ((A << 5) | (A >>> -5)) + f1(B, C, D) + W[15];
B = ((B << 30) | (B >>> -30));
D += ((E << 5) | (E >>> -5)) + f1(A, B, C) + W[16];
A = ((A << 30) | (A >>> -30));
C += ((D << 5) | (D >>> -5)) + f1(E, A, B) + W[17];
E = ((E << 30) | (E >>> -30));
B += ((C << 5) | (C >>> -5)) + f1(D, E, A) + W[18];
D = ((D << 30) | (D >>> -30));
A += ((B << 5) | (B >>> -5)) + f1(C, D, E) + W[19];
C = ((C << 30) | (C >>> -30));
E += ((A << 5) | (A >>> -5)) + f2(B, C, D) + W[20];
B = ((B << 30) | (B >>> -30));
D += ((E << 5) | (E >>> -5)) + f2(A, B, C) + W[21];
A = ((A << 30) | (A >>> -30));
C += ((D << 5) | (D >>> -5)) + f2(E, A, B) + W[22];
E = ((E << 30) | (E >>> -30));
B += ((C << 5) | (C >>> -5)) + f2(D, E, A) + W[23];
D = ((D << 30) | (D >>> -30));
A += ((B << 5) | (B >>> -5)) + f2(C, D, E) + W[24];
C = ((C << 30) | (C >>> -30));
E += ((A << 5) | (A >>> -5)) + f2(B, C, D) + W[25];
B = ((B << 30) | (B >>> -30));
D += ((E << 5) | (E >>> -5)) + f2(A, B, C) + W[26];
A = ((A << 30) | (A >>> -30));
C += ((D << 5) | (D >>> -5)) + f2(E, A, B) + W[27];
E = ((E << 30) | (E >>> -30));
B += ((C << 5) | (C >>> -5)) + f2(D, E, A) + W[28];
D = ((D << 30) | (D >>> -30));
A += ((B << 5) | (B >>> -5)) + f2(C, D, E) + W[29];
C = ((C << 30) | (C >>> -30));
E += ((A << 5) | (A >>> -5)) + f2(B, C, D) + W[30];
B = ((B << 30) | (B >>> -30));
D += ((E << 5) | (E >>> -5)) + f2(A, B, C) + W[31];
A = ((A << 30) | (A >>> -30));
C += ((D << 5) | (D >>> -5)) + f2(E, A, B) + W[32];
E = ((E << 30) | (E >>> -30));
B += ((C << 5) | (C >>> -5)) + f2(D, E, A) + W[33];
D = ((D << 30) | (D >>> -30));
A += ((B << 5) | (B >>> -5)) + f2(C, D, E) + W[34];
C = ((C << 30) | (C >>> -30));
E += ((A << 5) | (A >>> -5)) + f2(B, C, D) + W[35];
B = ((B << 30) | (B >>> -30));
D += ((E << 5) | (E >>> -5)) + f2(A, B, C) + W[36];
A = ((A << 30) | (A >>> -30));
C += ((D << 5) | (D >>> -5)) + f2(E, A, B) + W[37];
E = ((E << 30) | (E >>> -30));
B += ((C << 5) | (C >>> -5)) + f2(D, E, A) + W[38];
D = ((D << 30) | (D >>> -30));
A += ((B << 5) | (B >>> -5)) + f2(C, D, E) + W[39];
C = ((C << 30) | (C >>> -30));
E += ((A << 5) | (A >>> -5)) + f3(B, C, D) + W[40];
B = ((B << 30) | (B >>> -30));
D += ((E << 5) | (E >>> -5)) + f3(A, B, C) + W[41];
A = ((A << 30) | (A >>> -30));
C += ((D << 5) | (D >>> -5)) + f3(E, A, B) + W[42];
E = ((E << 30) | (E >>> -30));
B += ((C << 5) | (C >>> -5)) + f3(D, E, A) + W[43];
D = ((D << 30) | (D >>> -30));
A += ((B << 5) | (B >>> -5)) + f3(C, D, E) + W[44];
C = ((C << 30) | (C >>> -30));
E += ((A << 5) | (A >>> -5)) + f3(B, C, D) + W[45];
B = ((B << 30) | (B >>> -30));
D += ((E << 5) | (E >>> -5)) + f3(A, B, C) + W[46];
A = ((A << 30) | (A >>> -30));
C += ((D << 5) | (D >>> -5)) + f3(E, A, B) + W[47];
E = ((E << 30) | (E >>> -30));
B += ((C << 5) | (C >>> -5)) + f3(D, E, A) + W[48];
D = ((D << 30) | (D >>> -30));
A += ((B << 5) | (B >>> -5)) + f3(C, D, E) + W[49];
C = ((C << 30) | (C >>> -30));
E += ((A << 5) | (A >>> -5)) + f3(B, C, D) + W[50];
B = ((B << 30) | (B >>> -30));
D += ((E << 5) | (E >>> -5)) + f3(A, B, C) + W[51];
A = ((A << 30) | (A >>> -30));
C += ((D << 5) | (D >>> -5)) + f3(E, A, B) + W[52];
E = ((E << 30) | (E >>> -30));
B += ((C << 5) | (C >>> -5)) + f3(D, E, A) + W[53];
D = ((D << 30) | (D >>> -30));
A += ((B << 5) | (B >>> -5)) + f3(C, D, E) + W[54];
C = ((C << 30) | (C >>> -30));
E += ((A << 5) | (A >>> -5)) + f3(B, C, D) + W[55];
B = ((B << 30) | (B >>> -30));
D += ((E << 5) | (E >>> -5)) + f3(A, B, C) + W[56];
A = ((A << 30) | (A >>> -30));
C += ((D << 5) | (D >>> -5)) + f3(E, A, B) + W[57];
E = ((E << 30) | (E >>> -30));
B += ((C << 5) | (C >>> -5)) + f3(D, E, A) + W[58];
D = ((D << 30) | (D >>> -30));
A += ((B << 5) | (B >>> -5)) + f3(C, D, E) + W[59];
C = ((C << 30) | (C >>> -30));
E += ((A << 5) | (A >>> -5)) + f4(B, C, D) + W[60];
B = ((B << 30) | (B >>> -30));
D += ((E << 5) | (E >>> -5)) + f4(A, B, C) + W[61];
A = ((A << 30) | (A >>> -30));
C += ((D << 5) | (D >>> -5)) + f4(E, A, B) + W[62];
E = ((E << 30) | (E >>> -30));
B += ((C << 5) | (C >>> -5)) + f4(D, E, A) + W[63];
D = ((D << 30) | (D >>> -30));
A += ((B << 5) | (B >>> -5)) + f4(C, D, E) + W[64];
C = ((C << 30) | (C >>> -30));
E += ((A << 5) | (A >>> -5)) + f4(B, C, D) + W[65];
B = ((B << 30) | (B >>> -30));
D += ((E << 5) | (E >>> -5)) + f4(A, B, C) + W[66];
A = ((A << 30) | (A >>> -30));
C += ((D << 5) | (D >>> -5)) + f4(E, A, B) + W[67];
E = ((E << 30) | (E >>> -30));
B += ((C << 5) | (C >>> -5)) + f4(D, E, A) + W[68];
D = ((D << 30) | (D >>> -30));
A += ((B << 5) | (B >>> -5)) + f4(C, D, E) + W[69];
C = ((C << 30) | (C >>> -30));
E += ((A << 5) | (A >>> -5)) + f4(B, C, D) + W[70];
B = ((B << 30) | (B >>> -30));
D += ((E << 5) | (E >>> -5)) + f4(A, B, C) + W[71];
A = ((A << 30) | (A >>> -30));
C += ((D << 5) | (D >>> -5)) + f4(E, A, B) + W[72];
E = ((E << 30) | (E >>> -30));
B += ((C << 5) | (C >>> -5)) + f4(D, E, A) + W[73];
D = ((D << 30) | (D >>> -30));
A += ((B << 5) | (B >>> -5)) + f4(C, D, E) + W[74];
C = ((C << 30) | (C >>> -30));
E += ((A << 5) | (A >>> -5)) + f4(B, C, D) + W[75];
B = ((B << 30) | (B >>> -30));
D += ((E << 5) | (E >>> -5)) + f4(A, B, C) + W[76];
A = ((A << 30) | (A >>> -30));
C += ((D << 5) | (D >>> -5)) + f4(E, A, B) + W[77];
E = ((E << 30) | (E >>> -30));
B += ((C << 5) | (C >>> -5)) + f4(D, E, A) + W[78];
D = ((D << 30) | (D >>> -30));
A += ((B << 5) | (B >>> -5)) + f4(C, D, E) + W[79];
C = ((C << 30) | (C >>> -30));
digest[0] += A;
digest[1] += B;
digest[2] += C;
digest[3] += D;
digest[4] += E;
}
// why was this public?
// Note: parameter order changed to be consistent with System.arraycopy.
private static void byte2int(byte[] src, int srcOffset, int[] dst, int dstOffset, int length) {
while (length-- > 0) {
// Big endian
dst[dstOffset++] = (src[srcOffset++] << 24) | ((src[srcOffset++] & 0xFF) << 16)
| ((src[srcOffset++] & 0xFF) << 8) | (src[srcOffset++] & 0xFF);
}
}
public static PyString __doc__update = new PyString("Update this hashing object's state with the provided string.");
/**
* Add an array of bytes to the digest.
*/
public synchronized void update(byte input[]) {
engineUpdate(input, 0, input.length);
}
public static PyString __doc__copy = new PyString("Return a copy of the hashing object.");
/**
* Add an array of bytes to the digest.
*/
public SHA1 copy() {
return new SHA1(this);
}
public static PyString __doc__hexdigest = new PyString("Return the digest value as a string of hexadecimal digits.");
/**
* Print out the digest in a form that can be easily compared
* to the test vectors.
*/
public String hexdigest() {
byte[] digestBits = engineDigest();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 20; i++) {
char c1, c2;
c1 = (char) ((digestBits[i] >>> 4) & 0xf);
c2 = (char) (digestBits[i] & 0xf);
c1 = (char) ((c1 > 9) ? 'a' + (c1 - 10) : '0' + c1);
c2 = (char) ((c2 > 9) ? 'a' + (c2 - 10) : '0' + c2);
sb.append(c1);
sb.append(c2);
}
return sb.toString();
}
public static PyString __doc__digest = new PyString("Return the digest value as a string of binary data.");
public String digest() {
return PyString.from_bytes(engineDigest());
}
// XXX should become PyObject and use Py.idstr?
public String toString() {
return "<SHA object at" + System.identityHashCode(this) + ">";
}
}