Quadcap Embeddable Database

com/quadcap/crypto/SHA1Digest.java

Go to the documentation of this file.
00001 /* Copyright 2003 Quadcap Software. All rights reserved. 00002 * 00003 * This software is distributed under the Quadcap Free Software License. 00004 * This software may be used or modified for any purpose, personal or 00005 * commercial. Open Source redistributions are permitted. Commercial 00006 * redistribution of larger works derived from, or works which bundle 00007 * this software requires a "Commercial Redistribution License"; see 00008 * http://www.quadcap.com/purchase. 00009 * 00010 * Redistributions qualify as "Open Source" under one of the following terms: 00011 * 00012 * Redistributions are made at no charge beyond the reasonable cost of 00013 * materials and delivery. 00014 * 00015 * Redistributions are accompanied by a copy of the Source Code or by an 00016 * irrevocable offer to provide a copy of the Source Code for up to three 00017 * years at the cost of materials and delivery. Such redistributions 00018 * must allow further use, modification, and redistribution of the Source 00019 * Code under substantially the same terms as this license. 00020 * 00021 * Redistributions of source code must retain the copyright notices as they 00022 * appear in each source code file, these license terms, and the 00023 * disclaimer/limitation of liability set forth as paragraph 6 below. 00024 * 00025 * Redistributions in binary form must reproduce this Copyright Notice, 00026 * these license terms, and the disclaimer/limitation of liability set 00027 * forth as paragraph 6 below, in the documentation and/or other materials 00028 * provided with the distribution. 00029 * 00030 * The Software is provided on an "AS IS" basis. No warranty is 00031 * provided that the Software is free of defects, or fit for a 00032 * particular purpose. 00033 * 00034 * Limitation of Liability. Quadcap Software shall not be liable 00035 * for any damages suffered by the Licensee or any third party resulting 00036 * from use of the Software. 00037 */ 00038 00039 package com.quadcap.crypto; 00040 00041 /* 00042 * Public domain SHA implementation. 00043 * 00044 **/ 00045 00046 // ---- Following is original comment from Chuck McManis's version: 00047 // package util.crypt; 00048 /* 00049 * SHA1.java - An implementation of the SHA-1 Algorithm 00050 * 00051 * This version by Chuck McManis (cmcmanis@netcom.com) and 00052 * still public domain. 00053 * 00054 * Based on the C code that Steve Reid wrote his header 00055 * was : 00056 * SHA-1 in C 00057 * By Steve Reid <steve@edmweb.com> 00058 * 100% Public Domain 00059 * 00060 * Test Vectors (from FIPS PUB 180-1) 00061 * "abc" 00062 * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D 00063 * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" 00064 * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 00065 * A million repetitions of "a" 00066 * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F 00067 */ 00068 00069 import java.util.Random; 00070 00071 /** 00072 * This is a simple port of Steve Reid's SHA-1 code into Java. 00073 * I've run his test vectors through the code and they all pass. 00074 * 00075 */ 00076 public final class SHA1Digest implements Digest { 00077 private byte[] digest = null; 00078 private boolean digestValid = false; 00079 private int[] state = new int[5]; 00080 private long count = 0; 00081 00082 /* 00083 * The following array forms the basis for the transform 00084 * buffer. Update puts bytes into this buffer and then 00085 * transform adds it into the state of the digest. 00086 */ 00087 private int[] block = new int[16]; 00088 private int blockIndex; 00089 00090 /** 00091 * Default constructor 00092 */ 00093 public SHA1Digest() { 00094 init(); 00095 } 00096 00097 /** 00098 * 00099 * SHA1Init - Initialize new context 00100 */ 00101 public void init() { 00102 /* SHA1 initialization constants */ 00103 state[0] = 0x67452301; 00104 state[1] = 0xEFCDAB89; 00105 state[2] = 0x98BADCFE; 00106 state[3] = 0x10325476; 00107 state[4] = 0xC3D2E1F0; 00108 count = 0; 00109 digest = new byte[20]; 00110 digestValid = false; 00111 blockIndex = 0; 00112 } 00113 00114 /** 00115 * Add one byte to the digest. When this is implemented 00116 * all of the abstract class methods end up calling 00117 * this method for types other than bytes. 00118 */ 00119 public void update(byte b) { 00120 int mask = (8 * (blockIndex & 3)); 00121 count += 8; 00122 block[blockIndex >> 2] &= ~(0xff << mask); 00123 block[blockIndex >> 2] |= (b & 0xff) << mask; 00124 blockIndex++; 00125 if (blockIndex == 64) { 00126 transform(); 00127 blockIndex = 0; 00128 } 00129 } 00130 00131 /** 00132 * Implementation for arrays just wraps the primitive byte operation 00133 */ 00134 public void update(byte[] b, int off, int len) { 00135 for (int i = 0; i < len; i++) update(b[off+i]); 00136 } 00137 00138 /** 00139 * And the full-array implementation is just a degenerate case of the 00140 * array-subset implementation: 00141 */ 00142 public void update(byte[] buf) { update(buf, 0, buf.length); } 00143 00144 /** 00145 * Return the message digest for the accumulated bytes 00146 */ 00147 public byte[] digest() { 00148 byte[] ret = null; 00149 if (!digestValid) { 00150 finish(); 00151 ret = digest; 00152 init(); 00153 } 00154 return ret; 00155 } 00156 00157 /** 00158 * Complete processing on the message digest. 00159 */ 00160 private final void finish() { 00161 byte bits[] = new byte[8]; 00162 int i, j; 00163 00164 for (i = 0; i < 8; i++) { 00165 bits[i] = (byte)((count >>> (((7 - i) * 8))) & 0xff); 00166 } 00167 00168 update((byte) 128); 00169 while (blockIndex != 56) 00170 update((byte) 0); 00171 // This should cause a transform to happen. 00172 update(bits); 00173 for (i = 0; i < 20; i++) { 00174 digest[i] = (byte) 00175 ((state[i>>2] >> ((3-(i & 3)) * 8) ) & 0xff); 00176 } 00177 digestValid = true; 00178 } 00179 00180 /** Return a string that identifies this algorithm */ 00181 public String getAlg() { return "SHA1"; } 00182 00183 // ------------------------------------------------------------------ 00184 // private stuff 00185 00186 00187 /* 00188 * These functions are taken out of #defines in Steve's 00189 * code. Java doesn't have a preprocessor so the first 00190 * step is to just promote them to real methods. 00191 * Later we can optimize them out into inline code, 00192 * note that by making them final some compilers will 00193 * inline them when given the -O flag. 00194 */ 00195 final int rol(int value, int bits) { 00196 int q = (value << bits) | (value >>> (32 - bits)); 00197 return q; 00198 } 00199 00200 final int blk0(int i) { 00201 block[i] = (rol(block[i],24)&0xFF00FF00) | 00202 (rol(block[i],8)&0x00FF00FF); 00203 return block[i]; 00204 } 00205 00206 final int blk(int i) { 00207 block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15]^ 00208 block[(i+2)&15]^block[i&15], 1); 00209 return (block[i&15]); 00210 } 00211 00212 final void R0(int data[], int v, int w, int x , int y, int z, int i) { 00213 data[z] += ((data[w] & (data[x] ^ data[y] )) ^ data[y]) + 00214 blk0(i) + 0x5A827999 + rol(data[v] ,5); 00215 data[w] = rol(data[w], 30); 00216 } 00217 00218 final void R1(int data[], int v, int w, int x, int y, int z, int i) { 00219 data[z] += ((data[w] & (data[x] ^ data[y])) ^ data[y]) + 00220 blk(i) + 0x5A827999 + rol(data[v] ,5); 00221 data[w] = rol(data[w], 30); 00222 } 00223 00224 final void R2(int data[], int v, int w, int x, int y, int z, int i) { 00225 data[z] += (data[w] ^ data[x] ^ data[y]) + 00226 blk(i) + 0x6ED9EBA1 + rol(data[v] ,5); 00227 data[w] = rol(data[w], 30); 00228 } 00229 00230 final void R3(int data[], int v, int w, int x, int y, int z, int i) { 00231 data[z] += (((data[w] | data[x]) & data[y]) | (data[w] & 00232 data[x])) + 00233 blk(i) + 0x8F1BBCDC + rol(data[v] ,5); 00234 data[w] = rol(data[w], 30); 00235 } 00236 00237 final void R4(int data[], int v, int w, int x, int y, int z, int i) { 00238 data[z] += (data[w] ^ data[x] ^ data[y]) + 00239 blk(i) + 0xCA62C1D6 + rol(data[v] ,5); 00240 data[w] = rol(data[w], 30); 00241 } 00242 00243 00244 /* 00245 * Steve's original code and comments : 00246 * 00247 * blk0() and blk() perform the initial expand. 00248 * I got the idea of expanding during the round function from SSLeay 00249 * 00250 * #define blk0(i) block->l[i] 00251 * #define blk(i) (block->l[i&15] = 00252 rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ 00253 * ^block->l[(i+2)&15]^block->l[i&15],1)) 00254 * 00255 * (R0+R1), R2, R3, R4 are the different operations used in SHA1 00256 * #define R0(v,w,x,y,z,i) 00257 z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); 00258 * #define R1(v,w,x,y,z,i) 00259 z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); 00260 * #define R2(v,w,x,y,z,i) 00261 z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); 00262 * #define R3(v,w,x,y,z,i) 00263 z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); 00264 * #define R4(v,w,x,y,z,i) 00265 z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); 00266 */ 00267 00268 int dd[] = new int[5]; 00269 00270 /** 00271 * Hash a single 512-bit block. This is the core of the algorithm. 00272 * 00273 * Note that working with arrays is very inefficent in Java as it 00274 * does a class cast check each time you store into the array. 00275 * 00276 */ 00277 00278 void transform() { 00279 /* Copy context->state[] to working vars */ 00280 dd[0] = state[0]; 00281 dd[1] = state[1]; 00282 dd[2] = state[2]; 00283 dd[3] = state[3]; 00284 dd[4] = state[4]; 00285 /* 4 rounds of 20 operations each. Loop unrolled. */ 00286 R0(dd,0,1,2,3,4, 0); R0(dd,4,0,1,2,3, 1); R0(dd,3,4,0,1,2, 2); 00287 R0(dd,2,3,4,0,1, 3); 00288 R0(dd,1,2,3,4,0, 4); R0(dd,0,1,2,3,4, 5); R0(dd,4,0,1,2,3, 6); 00289 R0(dd,3,4,0,1,2, 7); 00290 R0(dd,2,3,4,0,1, 8); R0(dd,1,2,3,4,0, 9); R0(dd,0,1,2,3,4,10); 00291 R0(dd,4,0,1,2,3,11); 00292 R0(dd,3,4,0,1,2,12); R0(dd,2,3,4,0,1,13); R0(dd,1,2,3,4,0,14); 00293 R0(dd,0,1,2,3,4,15); 00294 R1(dd,4,0,1,2,3,16); R1(dd,3,4,0,1,2,17); R1(dd,2,3,4,0,1,18); 00295 R1(dd,1,2,3,4,0,19); 00296 R2(dd,0,1,2,3,4,20); R2(dd,4,0,1,2,3,21); R2(dd,3,4,0,1,2,22); 00297 R2(dd,2,3,4,0,1,23); 00298 R2(dd,1,2,3,4,0,24); R2(dd,0,1,2,3,4,25); R2(dd,4,0,1,2,3,26); 00299 R2(dd,3,4,0,1,2,27); 00300 R2(dd,2,3,4,0,1,28); R2(dd,1,2,3,4,0,29); R2(dd,0,1,2,3,4,30); 00301 R2(dd,4,0,1,2,3,31); 00302 R2(dd,3,4,0,1,2,32); R2(dd,2,3,4,0,1,33); R2(dd,1,2,3,4,0,34); 00303 R2(dd,0,1,2,3,4,35); 00304 R2(dd,4,0,1,2,3,36); R2(dd,3,4,0,1,2,37); R2(dd,2,3,4,0,1,38); 00305 R2(dd,1,2,3,4,0,39); 00306 R3(dd,0,1,2,3,4,40); R3(dd,4,0,1,2,3,41); R3(dd,3,4,0,1,2,42); 00307 R3(dd,2,3,4,0,1,43); 00308 R3(dd,1,2,3,4,0,44); R3(dd,0,1,2,3,4,45); R3(dd,4,0,1,2,3,46); 00309 R3(dd,3,4,0,1,2,47); 00310 R3(dd,2,3,4,0,1,48); R3(dd,1,2,3,4,0,49); R3(dd,0,1,2,3,4,50); 00311 R3(dd,4,0,1,2,3,51); 00312 R3(dd,3,4,0,1,2,52); R3(dd,2,3,4,0,1,53); R3(dd,1,2,3,4,0,54); 00313 R3(dd,0,1,2,3,4,55); 00314 R3(dd,4,0,1,2,3,56); R3(dd,3,4,0,1,2,57); R3(dd,2,3,4,0,1,58); 00315 R3(dd,1,2,3,4,0,59); 00316 R4(dd,0,1,2,3,4,60); R4(dd,4,0,1,2,3,61); R4(dd,3,4,0,1,2,62); 00317 R4(dd,2,3,4,0,1,63); 00318 R4(dd,1,2,3,4,0,64); R4(dd,0,1,2,3,4,65); R4(dd,4,0,1,2,3,66); 00319 R4(dd,3,4,0,1,2,67); 00320 R4(dd,2,3,4,0,1,68); R4(dd,1,2,3,4,0,69); R4(dd,0,1,2,3,4,70); 00321 R4(dd,4,0,1,2,3,71); 00322 R4(dd,3,4,0,1,2,72); R4(dd,2,3,4,0,1,73); R4(dd,1,2,3,4,0,74); 00323 R4(dd,0,1,2,3,4,75); 00324 R4(dd,4,0,1,2,3,76); R4(dd,3,4,0,1,2,77); R4(dd,2,3,4,0,1,78); 00325 R4(dd,1,2,3,4,0,79); 00326 /* Add the working vars back into context.state[] */ 00327 state[0] += dd[0]; 00328 state[1] += dd[1]; 00329 state[2] += dd[2]; 00330 state[3] += dd[3]; 00331 state[4] += dd[4]; 00332 } 00333 00334 //#ifdef DEBUG 00335 /** 00336 * Print out the digest in a form that can be easily compared 00337 * to the test vectors. 00338 */ 00339 private String digout() { 00340 StringBuffer sb = new StringBuffer(); 00341 for (int i = 0; i < 20; i++) { 00342 char c1, c2; 00343 00344 c1 = (char) ((digest[i] >>> 4) & 0xf); 00345 c2 = (char) (digest[i] & 0xf); 00346 c1 = (char) ((c1 > 9) ? 'A' + (c1 - 10) : '0' + c1); 00347 c2 = (char) ((c2 > 9) ? 'A' + (c2 - 10) : '0' + c2); 00348 sb.append(c1); 00349 sb.append(c2); 00350 if (((i+1) % 4) == 0) 00351 sb.append(' '); 00352 } 00353 return sb.toString(); 00354 } 00355 00356 00357 /** 00358 * This is a test program for the SHA1 algorithm. It puts 00359 * the three test vectors through the algorithm and prints 00360 * out the results (they should match.) Then it runs the 00361 * MessageDigest benchmark method to see how fast it is. 00362 * on my P133 its about 110 - 120K bytes/second. 00363 * 00364 * It then compares it to MD5, which is about 150K bytes/second. 00365 * 00366 */ 00367 public static void main(String args[]) { 00368 SHA1Digest s = new SHA1Digest(); 00369 00370 System.out.println("SHA-1 Test PROGRAM."); 00371 System.out.println("This code runs the test vectors through the code."); 00372 00373 /* "abc" 00374 A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D */ 00375 00376 System.out.println("First test is 'abc'"); 00377 String z = "abc"; 00378 s.init(); 00379 s.update((byte) 'a'); 00380 s.update((byte) 'b'); 00381 s.update((byte) 'c'); 00382 s.finish(); 00383 System.out.println(s.digout()); 00384 System.out.println("A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D"); 00385 00386 00387 /* "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" 00388 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 */ 00389 00390 System.out.println("Next Test is 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'"); 00391 z = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; 00392 s.init(); 00393 for (int j = 0; j < z.length(); j++) s.update((byte)z.charAt(j)); 00394 s.finish(); 00395 System.out.println(s.digout()); 00396 System.out.println("84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1"); 00397 00398 /* A million repetitions of "a" 00399 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F */ 00400 00401 System.out.println("Last test is 1 million 'a' characters."); 00402 s.init(); 00403 for (int i = 0; i < 1000000; i++) 00404 s.update((byte) 'a'); 00405 s.finish(); 00406 System.out.println(s.digout()); 00407 System.out.println("34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F"); 00408 //MessageDigest.benchmark(s); 00409 //MD5 mm = new MD5(); 00410 //MessageDigest.benchmark(mm); 00411 } 00412 //#endif 00413 }