|
|
package net.rete_db.rete_db.utils;
/**
* This class calculates an SHA-1 hashsum.
* The code is similar to the one presented in
* "Kryptographie, Dietmar Waetjen, Spektrum Verlag, 2004"
* and has neither performace optimizations nor stream support
*
* @author Andreas Warnke
*
*/
/*
* Status: released
* Open Points:
* History:
* 2008-01-27 getInstance(): removed; Singleton design pattern does not make sense here.
* 2005-06-15 hash: modulo on negative values replaced by bitwise-and; Point 1) solved.
* 2005-06-14 Review by A. Warnke; Findings:
* 1) possibly(?) wrong result if calculating modulo on negative values
* 2004-10-31 Singleton: is never null
* 2004-05-07 comments updated, code review by A. Warnke, 2 tests of doSHA1()
* 2004-05-06 class created
*/
/*
* RETE-DB (formerly ACCS) Access controlling database web-frontend
* Copyright (C) 2004-2008 Andreas Warnke
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* How to contact the author:
* Write a mail to RETE-DB at andreaswarnke.de
*/
public final class SHA1 {
/**
* this function converts a plain string to a hash string.
* The unicode string is converted to a byte array in
* big-endian order; the SHA1 is then executed.
* @param plain the original message
* @return hexadecimal number as string, 40 characters
*/
public static String hash ( String plain) {
// do the precalculation:
int bit_length = plain.length() * 16; // 16 is the unicode char bitlength
int total_bit_length = ( bit_length + 1 + 64 + 511 ) & -512; // int d = ( 447 - bit_length) % 512;
int msg_length = total_bit_length/32; // ( bit_length + 1 + d + 64 ) / 32; // number of 32 bit integers
int[] Message = new int[ msg_length]; // should be initialized with zeros
// fill the Message integers:
for ( int pos = 0; pos < msg_length; pos ++ ) {
// higher 16 bits:
if ( pos*32 < bit_length) {
int unicode = (int) plain.charAt( pos*2);
Message[pos] = ( unicode << 16);
}
else if ( pos*32 == bit_length)
Message[pos] = 0x80000000;
// lower 16 bits
if ( (pos*32+16) < bit_length) {
int unicode2 = (int) plain.charAt( pos*2+1);
Message[pos] = Message[pos] | ( unicode2 & 0x0000ffff);
}
else if ( (pos*32+16) == bit_length)
Message[pos] = Message[pos] | 0x00008000;
}
Message[msg_length-1] = bit_length;
// test code:
//int[] test = new int [16];
//test[0]=0x61626380; // abc
//test[15]=0x00000018; // length = 24 bit = 0x18;
//if ( 1==1) return doSHA1( test);
// "abc" ->
// A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
//String tests="abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; // 56 chars
//int[] test = new int [32]; // 56/4=14
//for ( int pos = 0; pos < 14; pos ++)
// for ( int i = 0; i < 4; i ++ )
// test[pos]|=(((int)tests.charAt(pos*4+i))&0xff)<<((3-i)*8);
//test[14]=0x80000000;
//test[31]=56*8; // length = 56*8 bit;
//if ( 1==1) return doSHA1( test);
// "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" ->
// 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
// digest:
return doSHA1( Message);
}
// required constants:
private static final int h1 = 0x67452301;
private static final int h2 = 0xefcdab89;
private static final int h3 = 0x98badcfe;
private static final int h4 = 0x10325476;
private static final int h5 = 0xc3d2e1f0;
private static final int y1 = 0x5a827999;
private static final int y2 = 0x6ed9eba1;
private static final int y3 = 0x8f1bbcdc;
private static final int y4 = 0xca62c1d6;
/** rotate left */
private static int rol ( int x, int shift ) {
return (( x << shift ) | ( x >>> ( 32-shift )));
}
/**
* this method calculates the SHA1 digest
*
* @param Message precalculated array on 32 bit values;
* the length is a multiple of 16, the bit after
* the last message bit is set, the last 64 bits
* represent the message length in big endian order
* @return hexadecimal representation of the result, 40 characters
*/
private static String doSHA1 ( int[] Message ) {
int H1 = SHA1.h1;
int H2 = SHA1.h2;
int H3 = SHA1.h3;
int H4 = SHA1.h4;
int H5 = SHA1.h5;
int integer_count = Message.length;
int[] X = new int[80];
int j;
for ( int block_start = 0; block_start < integer_count; block_start += 16 ) {
// init X:
for ( j = 0; j < 16; j ++ )
X[j] = Message[block_start+j];
for ( j = 16; j < 80; j ++ )
X[j] = rol(X[j-3]^X[j-8]^X[j-14]^X[j-16],1);
// calculate A,B,C,D,E:
int A=H1; int B=H2; int C=H3; int D=H4; int E=H5; int t;
for ( j = 0; j < 20; j ++ ) {
t = rol(A,5)+((B&C)|((~B)&D))+E+X[j]+y1;
E=D; D=C; C=rol(B,30); B=A; A=t;
}
for ( j = 20; j < 40; j ++ ) {
t = rol(A,5)+(B^C^D)+E+X[j]+y2;
E=D; D=C; C=rol(B,30); B=A; A=t;
}
for ( j = 40; j < 60; j ++ ) {
t = rol(A,5)+((B&C)|(B&D)|(C&D))+E+X[j]+y3;
E=D; D=C; C=rol(B,30); B=A; A=t;
}
for ( j = 60; j < 80; j ++ ) {
t = rol(A,5)+(B^C^D)+E+X[j]+y4;
E=D; D=C; C=rol(B,30); B=A; A=t;
}
H1+=A; H2+=B; H3+=C; H4+=D; H5+=E;
}
// convert result to hexadecimal string:
StringBuffer result = new StringBuffer ( 40);
Convert.intToHex( H1, result);
Convert.intToHex( H2, result);
Convert.intToHex( H3, result);
Convert.intToHex( H4, result);
Convert.intToHex( H5, result);
return result.toString();
}
}
|