ch.ethz.ssh2.crypto.digest.SHA1 Maven / Gradle / Ivy
package ch.ethz.ssh2.crypto.digest;
/**
*
* SHA-1 implementation based on FIPS PUB 180-1.
*
* (http://www.itl.nist.gov/fipspubs/fip180-1.htm)
*
* @author Christian Plattner, [email protected]
* @version $Id: SHA1.java,v 1.4 2006/02/02 09:11:03 cplattne Exp $
*/
public final class SHA1 implements Digest
{
private int H0, H1, H2, H3, H4;
private final byte msg[] = new byte[64];
private final int[] w = new int[80];
private int currentPos;
private long currentLen;
public SHA1()
{
reset();
}
public final int getDigestLength()
{
return 20;
}
public final void reset()
{
H0 = 0x67452301;
H1 = 0xEFCDAB89;
H2 = 0x98BADCFE;
H3 = 0x10325476;
H4 = 0xC3D2E1F0;
currentPos = 0;
currentLen = 0;
}
public final void update(byte b[], int off, int len)
{
for (int i = off; i < (off + len); i++)
update(b[i]);
}
public final void update(byte b[])
{
for (int i = 0; i < b.length; i++)
update(b[i]);
}
public final void update(byte b)
{
// System.out.println(pos + "->" + b);
msg[currentPos++] = b;
currentLen += 8;
if (currentPos == 64)
{
perform();
currentPos = 0;
}
}
private static final String toHexString(byte[] b)
{
final String hexChar = "0123456789ABCDEF";
StringBuffer sb = new StringBuffer();
for (int i = 0; i < b.length; i++)
{
sb.append(hexChar.charAt((b[i] >> 4) & 0x0f));
sb.append(hexChar.charAt(b[i] & 0x0f));
}
return sb.toString();
}
private final void putInt(byte[] b, int pos, int val)
{
b[pos] = (byte) (val >> 24);
b[pos + 1] = (byte) (val >> 16);
b[pos + 2] = (byte) (val >> 8);
b[pos + 3] = (byte) val;
}
public final void digest(byte[] out)
{
digest(out, 0);
}
public final void digest(byte[] out, int off)
{
long l = currentLen;
update((byte) 0x80);
// padding could be done more efficiently...
while (currentPos != 56)
update((byte) 0);
update((byte) (l >> 56));
update((byte) (l >> 48));
update((byte) (l >> 40));
update((byte) (l >> 32));
update((byte) (l >> 24));
update((byte) (l >> 16));
update((byte) (l >> 8));
update((byte) (l));
// debug(80, H0, H1, H2, H3, H4);
putInt(out, off, H0);
putInt(out, off + 4, H1);
putInt(out, off + 8, H2);
putInt(out, off + 12, H3);
putInt(out, off + 16, H4);
reset();
}
/*
* private void debug(int t, int A, int B, int C, int D, int E) {
* System.out.println(t + ": " + Integer.toHexString(A).toUpperCase() + ", " +
* Integer.toHexString(B).toUpperCase() + ", " +
* Integer.toHexString(C).toUpperCase() + "," +
* Integer.toHexString(D).toUpperCase() + ", " +
* Integer.toHexString(E).toUpperCase()); }
*/
private final void perform()
{
for (int i = 0; i < 16; i++)
w[i] = ((msg[i * 4] & 0xff) << 24) | ((msg[i * 4 + 1] & 0xff) << 16) | ((msg[i * 4 + 2] & 0xff) << 8)
| ((msg[i * 4 + 3] & 0xff));
for (int t = 16; t < 80; t++)
{
int x = w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16];
w[t] = ((x << 1) | (x >>> 31));
}
int A = H0;
int B = H1;
int C = H2;
int D = H3;
int E = H4;
int T;
for (int t = 0; t <= 19; t++)
{
T = ((A << 5) | (A >>> 27)) + ((B & C) | ((~B) & D)) + E + w[t] + 0x5A827999;
E = D;
D = C;
C = ((B << 30) | (B >>> 2));
B = A;
A = T;
// debug(t, A, B, C, D, E);
}
for (int t = 20; t <= 39; t++)
{
T = ((A << 5) | (A >>> 27)) + (B ^ C ^ D) + E + w[t] + 0x6ED9EBA1;
E = D;
D = C;
C = ((B << 30) | (B >>> 2));
B = A;
A = T;
// debug(t, A, B, C, D, E);
}
for (int t = 40; t <= 59; t++)
{
T = ((A << 5) | (A >>> 27)) + ((B & C) | (B & D) | (C & D)) + E + w[t] + 0x8F1BBCDC;
E = D;
D = C;
C = ((B << 30) | (B >>> 2));
B = A;
A = T;
// debug(t, A, B, C, D, E);
}
for (int t = 60; t <= 79; t++)
{
T = ((A << 5) | (A >>> 27)) + (B ^ C ^ D) + E + w[t] + 0xCA62C1D6;
E = D;
D = C;
C = ((B << 30) | (B >>> 2));
B = A;
A = T;
// debug(t, A, B, C, D, E);
}
H0 = H0 + A;
H1 = H1 + B;
H2 = H2 + C;
H3 = H3 + D;
H4 = H4 + E;
// debug(80, H0, H1, H2, H3, H4);
}
public static void main(String[] args)
{
SHA1 sha = new SHA1();
byte[] dig1 = new byte[20];
byte[] dig2 = new byte[20];
byte[] dig3 = new byte[20];
/*
* We do not specify a charset name for getBytes(), since we assume that
* the JVM's default encoder maps the _used_ ASCII characters exactly as
* getBytes("US-ASCII") would do. (Ah, yes, too lazy to catch the
* exception that can be thrown by getBytes("US-ASCII")). Note: This has
* no effect on the SHA-1 implementation, this is just for the following
* test code.
*/
sha.update("abc".getBytes());
sha.digest(dig1);
sha.update("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq".getBytes());
sha.digest(dig2);
for (int i = 0; i < 1000000; i++)
sha.update((byte) 'a');
sha.digest(dig3);
String dig1_res = toHexString(dig1);
String dig2_res = toHexString(dig2);
String dig3_res = toHexString(dig3);
String dig1_ref = "A9993E364706816ABA3E25717850C26C9CD0D89D";
String dig2_ref = "84983E441C3BD26EBAAE4AA1F95129E5E54670F1";
String dig3_ref = "34AA973CD4C4DAA4F61EEB2BDBAD27316534016F";
if (dig1_res.equals(dig1_ref))
System.out.println("SHA-1 Test 1 OK.");
else
System.out.println("SHA-1 Test 1 FAILED.");
if (dig2_res.equals(dig2_ref))
System.out.println("SHA-1 Test 2 OK.");
else
System.out.println("SHA-1 Test 2 FAILED.");
if (dig3_res.equals(dig3_ref))
System.out.println("SHA-1 Test 3 OK.");
else
System.out.println("SHA-1 Test 3 FAILED.");
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy