Author: nextgens
Date: 2006-02-12 16:12:44 +0000 (Sun, 12 Feb 2006)
New Revision: 8024
Added:
trunk/apps/installer/src/
trunk/apps/installer/src/Sha1Test.java
trunk/apps/installer/src/freenet/
trunk/apps/installer/src/freenet/crypt/
trunk/apps/installer/src/freenet/crypt/SHA1.java
trunk/apps/installer/src/freenet/support/
trunk/apps/installer/src/freenet/support/HexUtil.java
Modified:
trunk/apps/installer/build-installer.xml
Log:
Antinstaller : Integrity checking of downloaded files
Modified: trunk/apps/installer/build-installer.xml
===================================================================
--- trunk/apps/installer/build-installer.xml 2006-02-12 13:57:03 UTC (rev
8023)
+++ trunk/apps/installer/build-installer.xml 2006-02-12 16:12:44 UTC (rev
8024)
@@ -14,7 +14,7 @@
classname="org.tp23.antinstaller.taskdefs.Installer"
classpathref="taskdef.cp"/>
- <target name="selfextract">
+ <target name="selfextract" depends="jar_sha1test">
<echo message="Building INSTALLER SELFEXTRACT"/>
<installer file="./selfextractpack.jar" compress="true"
extractType="SelfExtractor"
@@ -27,6 +27,21 @@
<fileset dir="installclasspath"
includes="resources/*"/>
<fileset dir="installclasspath"
includes="bin/*"/>
<fileset dir="installclasspath"
includes="config/*"/>
+ <fileset dir="build" includes="**/*"/>
</installer>
</target>
+
+ <target name="compile_sha1test">
+ <!-- Create the time stamp -->
+ <tstamp/>
+ <!-- Create the build directory structure used by compile -->
+
+ <javac srcdir="./src" destdir="./build" optimize="on" source="1.4">
+ <include name="freenet/crypt/SHA1.java"/>
+ <include name="freenet/support/HexUtil"/>
+ <include name="Sha1Test.java"/>
+ </javac>
+ </target>
+
+
</project>
Added: trunk/apps/installer/src/Sha1Test.java
===================================================================
--- trunk/apps/installer/src/Sha1Test.java 2006-02-12 13:57:03 UTC (rev
8023)
+++ trunk/apps/installer/src/Sha1Test.java 2006-02-12 16:12:44 UTC (rev
8024)
@@ -0,0 +1,83 @@
+import freenet.crypt.SHA1;
+import freenet.support.HexUtil;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.BufferedInputStream;
+
+public class Sha1Test {
+ protected static int BUFFERSIZE=8192;
+
+ /**
+ * @param file1: File to checkum
+ * @param file2: File with the checksum
+ *
+ * @return 0 if it matches
+ * @return 1 if it doesn't
+ * @return 2 if an error occured
+ */
+ public static void main(String[] args) {
+ SHA1 hash=new SHA1();
+ if(args.length != 1) System.exit(2);
+
+ try{
+ FileInputStream fis = null;
+ File file = null;
+ BufferedInputStream bis = null;
+ long lengthBackup=0;
+ String result=new String();
+
+ // We compute the hash
+ // http://java.sun.com/developer/TechTips/1998/tt0915.html#tip2
+ try {
+ fis = new FileInputStream(args[0]);
+ file = new File(args[0]);
+ bis = new BufferedInputStream(fis);
+ lengthBackup=file.length();
+ int len = 0;
+ byte[] buffer = new byte[BUFFERSIZE];
+ while ((len = bis.read(buffer)) > -1) {
+ hash.update(buffer,0,len);
+ }
+ } finally {
+ if (bis != null) bis.close();
+ if (fis != null) fis.close();
+ }
+
+ // We read the hash-file
+ try {
+ fis = new FileInputStream(args[0]+".sha1");
+ file = new File(args[0]+".sha1");
+ bis = new BufferedInputStream(fis);
+ lengthBackup=file.length();
+ int len = 0;
+ byte[] buffer = new byte[BUFFERSIZE];
+ while ((len = bis.read(buffer)) > -1) {
+ result=new String(buffer,0,len);
+ }
+ } finally {
+ if (bis != null) bis.close();
+ if (fis != null) fis.close();
+ }
+
+
+ int i=result.trim().indexOf(' ');
+ result=result.substring(0,i);
+ System.out.println(HexUtil.bytesToHex(hash.digest()));
+ System.out.println(result);
+
System.out.println(result.equalsIgnoreCase(HexUtil.bytesToHex(hash.digest())));
+
+ // now we compare
+ if(result.equalsIgnoreCase(HexUtil.bytesToHex(hash.digest())+"
"+args[0])){
+ System.exit(0);
+ }else {
+ System.exit(1);
+ }
+
+ }catch (Exception e){
+ System.out.println(e);
+ System.exit(2);
+ }
+ }
+
+}
Added: trunk/apps/installer/src/freenet/crypt/SHA1.java
===================================================================
--- trunk/apps/installer/src/freenet/crypt/SHA1.java 2006-02-12 13:57:03 UTC
(rev 8023)
+++ trunk/apps/installer/src/freenet/crypt/SHA1.java 2006-02-12 16:12:44 UTC
(rev 8024)
@@ -0,0 +1,504 @@
+/**<PRE>
+ * SHA1.java - An implementation of the SHA-1 Algorithm
+ * This version integrated into Freenet by Ian Clarke (02-02-2000)
+ * (i.clarke at dynamicblue.com) from a previous public domain version by
+ * Chuck McManis (cmcmanis at netcom.com) which was public domain
+ * Tweaked by Mr.Tines<tines at windsong.demon.co.uk> for pegwit, June 1997
+ * - added method 'frob()' which wipes the contents, so as to match
+ * the bizarre behaviour of Pegwit's double barreled hashing.
+ *
+ * Based on the C code that Steve Reid wrote his header
+ * was :
+ * SHA-1 in C
+ * By Steve Reid <steve at edmweb.com>
+ * 100% Public Domain
+ *
+ * Test Vectors (from FIPS PUB 180-1)
+ * "abc"
+ * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+ * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+ * A million repetitions of "a"
+ * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+ </pre>*/
+package freenet.crypt;
+import java.util.Random;
+
+import freenet.support.HexUtil;
+
+/**
+ * This is a simple port of Steve Reid's SHA-1 code into Java.
+ * I've run his test vectors through the code and they all pass.
+ */
+public final class SHA1 implements Digest {
+
+ protected static boolean alwaysThisOne = false;
+
+ public static Digest getInstance(boolean needProgressive) {
+ if(alwaysThisOne) needProgressive = true;
+ if(needProgressive) return new SHA1();
+ else try {
+ return new JavaSHA1();
+ } catch (java.security.NoSuchAlgorithmException e) {
+ alwaysThisOne = true;
+ return new SHA1();
+ } catch (Exception e) {
+ return new SHA1();
+ }
+ }
+
+ public static Digest getInstance() {
+ return getInstance(false);
+ }
+
+ public final int digestSize() {
+ return 160;
+ }
+
+
+ private int state[] = new int[5];
+ private long count;
+ private boolean digestValid = false;
+ private byte[] digestBits;
+ private boolean NSA = true;
+
+ /**
+ * Retrieves the value of a hash.
+ * @param digest int[] into which to place 5 elements
+ * @param offset index of first of the 5 elements
+ */
+ public final void extract(int[] digest, int offset) {
+ for(int i=0; i<5; ++i) {
+ digest[i+offset] =
+ ((digestBits[4*i+0]<<24) & 0xFF000000) |
+ ((digestBits[4*i+1]<<16) & 0x00FF0000) |
+ ((digestBits[4*i+2]<< 8) & 0x0000FF00) |
+ ((digestBits[4*i+3] ) & 0x000000FF);
+ }
+ }
+
+ /**
+ * Variant constructor
+ * @param b true for SHA-1, false for the original SHA-0
+ */
+ public SHA1(boolean b) {
+ count = 0;
+ digestValid = false;
+ NSA = b;
+ init();
+ }
+
+ /**
+ * Simple constructor for SHA-1
+ */
+ public SHA1() {
+ this(true);
+ }
+
+ /*
+ * The following array forms the basis for the transform
+ * buffer. Update puts bytes into this buffer and then
+ * transform adds it into the state of the digest.
+ */
+ private int block[] = new int[16];
+ private int blockIndex;
+
+ /*
+ * These functions are taken out of #defines in Steve's
+ * code. Java doesn't have a preprocessor so the first
+ * step is to just promote them to real methods.
+ * Later we can optimize them out into inline code,
+ * note that by making them final some compilers will
+ * inline them when given the -O flag.
+ */
+ private final int rol(int value, int bits) {
+ int q = (value << bits) | (value >>> (32 - bits));
+ return q;
+ }
+
+ private final int blk0(int i) {
+ block[i] = (rol(block[i],24)&0xFF00FF00) |
+ (rol(block[i],8)&0x00FF00FF);
+ return block[i];
+ }
+
+ private final int blk(int i) {
+ block[i&15] = block[(i+13)&15]^block[(i+8)&15]^
+ block[(i+2)&15]^block[i&15];
+ if(NSA)
+ { // this makes it SHA-1
+ block[i&15] = rol(block[i&15], 1);
+ }
+ return (block[i&15]);
+ }
+
+ private final void R0(int data[], int v, int w, int x , int y, int z, int
i) {
+ data[z] += ((data[w] & (data[x] ^ data[y] )) ^ data[y]) +
+ blk0(i) + 0x5A827999 + rol(data[v] ,5);
+ data[w] = rol(data[w], 30);
+ }
+
+ private final void R1(int data[], int v, int w, int x, int y, int z, int
i) {
+ data[z] += ((data[w] & (data[x] ^ data[y])) ^ data[y]) +
+ blk(i) + 0x5A827999 + rol(data[v] ,5);
+ data[w] = rol(data[w], 30);
+ }
+
+ private final void R2(int data[], int v, int w, int x, int y, int z, int
i) {
+ data[z] += (data[w] ^ data[x] ^ data[y]) +
+ blk(i) + 0x6ED9EBA1 + rol(data[v] ,5);
+ data[w] = rol(data[w], 30);
+ }
+
+ private final void R3(int data[], int v, int w, int x, int y, int z, int
i) {
+ data[z] += (((data[w] | data[x]) & data[y]) | (data[w] & data[x])) +
+ blk(i) + 0x8F1BBCDC + rol(data[v] ,5);
+ data[w] = rol(data[w], 30);
+ }
+
+ private final void R4(int data[], int v, int w, int x, int y, int z, int
i) {
+ data[z] += (data[w] ^ data[x] ^ data[y]) +
+ blk(i) + 0xCA62C1D6 + rol(data[v] ,5);
+ data[w] = rol(data[w], 30);
+ }
+
+
+ /*
+ * Steve's original code and comments :
+ *
+ * blk0() and blk() perform the initial expand.
+ * I got the idea of expanding during the round function from SSLeay
+ *
+ * #define blk0(i) block->l[i]
+ * #define blk(i) (block->l[i&15] =
rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+ * ^block->l[(i+2)&15]^block->l[i&15],1))
+ *
+ * (R0+R1), R2, R3, R4 are the different operations used in SHA1
+ * #define R0(v,w,x,y,z,i)
z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+ * #define R1(v,w,x,y,z,i)
z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+ * #define R2(v,w,x,y,z,i)
z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+ * #define R3(v,w,x,y,z,i)
z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+ * #define R4(v,w,x,y,z,i)
z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+ */
+
+ private int dd[] = new int[5];
+
+ /**
+ * Hash a single 512-bit block. This is the core of the algorithm.
+ *
+ * Note that working with arrays is very inefficent in Java as it
+ * does a class cast check each time you store into the array.
+ *
+ */
+
+ private final void transform() {
+
+ /* Copy context->state[] to working vars */
+ dd[0] = state[0];
+ dd[1] = state[1];
+ dd[2] = state[2];
+ dd[3] = state[3];
+ dd[4] = state[4];
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(dd,0,1,2,3,4, 0); R0(dd,4,0,1,2,3, 1); R0(dd,3,4,0,1,2, 2);
R0(dd,2,3,4,0,1, 3);
+ R0(dd,1,2,3,4,0, 4); R0(dd,0,1,2,3,4, 5); R0(dd,4,0,1,2,3, 6);
R0(dd,3,4,0,1,2, 7);
+ R0(dd,2,3,4,0,1, 8); R0(dd,1,2,3,4,0, 9); R0(dd,0,1,2,3,4,10);
R0(dd,4,0,1,2,3,11);
+ R0(dd,3,4,0,1,2,12); R0(dd,2,3,4,0,1,13); R0(dd,1,2,3,4,0,14);
R0(dd,0,1,2,3,4,15);
+ R1(dd,4,0,1,2,3,16); R1(dd,3,4,0,1,2,17); R1(dd,2,3,4,0,1,18);
R1(dd,1,2,3,4,0,19);
+ R2(dd,0,1,2,3,4,20); R2(dd,4,0,1,2,3,21); R2(dd,3,4,0,1,2,22);
R2(dd,2,3,4,0,1,23);
+ R2(dd,1,2,3,4,0,24); R2(dd,0,1,2,3,4,25); R2(dd,4,0,1,2,3,26);
R2(dd,3,4,0,1,2,27);
+ R2(dd,2,3,4,0,1,28); R2(dd,1,2,3,4,0,29); R2(dd,0,1,2,3,4,30);
R2(dd,4,0,1,2,3,31);
+ R2(dd,3,4,0,1,2,32); R2(dd,2,3,4,0,1,33); R2(dd,1,2,3,4,0,34);
R2(dd,0,1,2,3,4,35);
+ R2(dd,4,0,1,2,3,36); R2(dd,3,4,0,1,2,37); R2(dd,2,3,4,0,1,38);
R2(dd,1,2,3,4,0,39);
+ R3(dd,0,1,2,3,4,40); R3(dd,4,0,1,2,3,41); R3(dd,3,4,0,1,2,42);
R3(dd,2,3,4,0,1,43);
+ R3(dd,1,2,3,4,0,44); R3(dd,0,1,2,3,4,45); R3(dd,4,0,1,2,3,46);
R3(dd,3,4,0,1,2,47);
+ R3(dd,2,3,4,0,1,48); R3(dd,1,2,3,4,0,49); R3(dd,0,1,2,3,4,50);
R3(dd,4,0,1,2,3,51);
+ R3(dd,3,4,0,1,2,52); R3(dd,2,3,4,0,1,53); R3(dd,1,2,3,4,0,54);
R3(dd,0,1,2,3,4,55);
+ R3(dd,4,0,1,2,3,56); R3(dd,3,4,0,1,2,57); R3(dd,2,3,4,0,1,58);
R3(dd,1,2,3,4,0,59);
+ R4(dd,0,1,2,3,4,60); R4(dd,4,0,1,2,3,61); R4(dd,3,4,0,1,2,62);
R4(dd,2,3,4,0,1,63);
+ R4(dd,1,2,3,4,0,64); R4(dd,0,1,2,3,4,65); R4(dd,4,0,1,2,3,66);
R4(dd,3,4,0,1,2,67);
+ R4(dd,2,3,4,0,1,68); R4(dd,1,2,3,4,0,69); R4(dd,0,1,2,3,4,70);
R4(dd,4,0,1,2,3,71);
+ R4(dd,3,4,0,1,2,72); R4(dd,2,3,4,0,1,73); R4(dd,1,2,3,4,0,74);
R4(dd,0,1,2,3,4,75);
+ R4(dd,4,0,1,2,3,76); R4(dd,3,4,0,1,2,77); R4(dd,2,3,4,0,1,78);
R4(dd,1,2,3,4,0,79);
+ /* Add the working vars back into context.state[] */
+ state[0] += dd[0];
+ state[1] += dd[1];
+ state[2] += dd[2];
+ state[3] += dd[3];
+ state[4] += dd[4];
+ }
+
+ /**
+ * zero the count and state arrays; used to support
+ * Pegwit's anomalous 2-barrel hashing
+ */
+ public final void frob() { // Pegwit's little anomaly
+ count=0;
+ state[0] = state[1] = state[2] = state[3] = state[4] = 0;
+ }
+
+ /**
+ *
+ * Initializes new context
+ */
+ protected final void init() {
+ /* SHA1 initialization constants */
+ state[0] = 0x67452301;
+ state[1] = 0xEFCDAB89;
+ state[2] = 0x98BADCFE;
+ state[3] = 0x10325476;
+ state[4] = 0xC3D2E1F0;
+ count = 0;
+ digestBits = new byte[20];
+ digestValid = false;
+ blockIndex = 0;
+ }
+
+ /**
+ * Add one byte to the digest. When this is implemented
+ * all of the abstract class methods end up calling
+ * this method for types other than bytes.
+ * @param b byte to add
+ */
+ public final void update(byte b) {
+ int mask = (blockIndex & 3) << 3;
+ count += 8;
+ block[blockIndex >> 2] &= ~(0xff << mask);
+ block[blockIndex >> 2] |= (b & 0xff) << mask;
+ blockIndex++;
+ if (blockIndex == 64) {
+ transform();
+ blockIndex = 0;
+ }
+ }
+
+ /**
+ * Add many bytes to the digest.
+ * @param data byte data to add
+ * @param offset start byte
+ * @param length number of bytes to hash
+ */
+ public final void update(byte[] data, int offset, int length) {
+ for (int i=0; i<length; ++i)
+ update(data[offset+i]);
+ }
+
+ public final void update(byte[] data) {
+ update(data, 0, data.length);
+ }
+
+ /**
+ * Write completed digest into the given buffer.
+ * @param reset If true, the hash function is reinitialized
+ */
+ public final void digest(boolean reset, byte[] buffer, int offset) {
+ finish();
+ System.arraycopy(digestBits, 0, buffer, offset, digestBits.length);
+ if (reset)
+ init();
+ }
+
+ /**
+ * Return completed digest.
+ * @return the byte array result
+ * @param reset If true, the hash function is reinitialized
+ */
+ public final byte[] digest(boolean reset) {
+ byte[] out = new byte[20];
+ digest(reset, out, 0);
+ return out;
+ }
+
+ /**
+ * Return completed digest.
+ * @return the byte array result
+ */
+ public final byte[] digest() {
+ return digest(true);
+ }
+
+ /**
+ * Complete processing on the message digest.
+ */
+ protected final void finish() {
+ byte bits[] = new byte[8];
+ int i, j;
+ for (i = 0; i < 8; i++) {
+ bits[i] = (byte)((count >>> (((7 - i) << 3))) & 0xff);
+ }
+
+ update((byte) 128);
+ while (blockIndex != 56)
+ update((byte) 0);
+ // This should cause a transform to happen.
+ for(i=0; i<8; ++i) update(bits[i]);
+ for (i = 0; i < 20; i++) {
+ digestBits[i] = (byte)
+ ((state[i>>2] >>> ((3-(i & 3)) << 3) ) & 0xff);
+ }
+ digestValid = true;
+ }
+
+ /**
+ * Print out the digest in a form that can be easily compared
+ * to the test vectors.
+ */
+ protected String digout() {
+ 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();
+ }
+
+
+ /**
+ * test driver
+ */
+ public static void main(String[] args) {
+ SHAselfTest();
+ SHAbenchTest();
+ }
+
+ public static void SHAbenchTest() {
+ try {
+ JavaSHA1 s = new JavaSHA1();
+ genericBenchTest(s);
+ try {
+ JavaSHA1 s1 = (JavaSHA1)(s.clone());
+ System.err.println("Cloned successfully");
+ genericBenchTest(s1);
+ } catch (CloneNotSupportedException e) {
+ System.err.println("Couldn't clone");
+ }
+ } catch (Exception e) {
+ System.err.println("Couldn't run benchmark for JavaSHA1");
+ }
+ SHA1 sha1 = new SHA1(true);
+ genericBenchTest(sha1);
+ }
+
+ public static void genericBenchTest(Digest sha1) {
+ System.out.println("\nBegin benchmark");
+ long size = 4096;
+ long count = 100000;
+ byte data[] = createDummyData((int)size);
+ long startSameUpdate = System.currentTimeMillis();
+ for (int i = 0; i < count; i++)
+ sha1.update(data);
+ long endSameUpdate = System.currentTimeMillis();
+ byte digested[] = sha1.digest();
+ long afterDigested = System.currentTimeMillis();
+ long updateTime = endSameUpdate - startSameUpdate;
+ long speed = 0;
+ long eachTime = 0;
+ if (updateTime > 0) {
+ speed = size*count*1000 / updateTime;
+ eachTime = count / updateTime;
+ }
+ System.out.println("SHA update " + count + " times for the same data
block of size " + size + " bytes:");
+ System.out.println(updateTime + "ms [" + speed + "bytes/second, " +
eachTime + "updates/ms]\n");
+
+ count = 1000;
+ byte data2[][] = new byte[(int)count][];
+ for (int i = 0; i < count; i++)
+ data2[i] = createDummyData((int)size);
+ long differentStartTime = System.currentTimeMillis();
+ for (int i = 0; i < count; i++)
+ sha1.update(data2[i]);
+ long endDifferentUpdate = System.currentTimeMillis();
+ digested = sha1.digest();
+ afterDigested = System.currentTimeMillis();
+ updateTime = endDifferentUpdate - differentStartTime;
+ speed = 0;
+ eachTime = 0;
+ if (updateTime > 0) {
+ speed = size*count*1000 / updateTime;
+ eachTime = count / updateTime;
+ }
+ System.out.println("SHA update " + count + " times for different data
blocks of size " + size + " bytes:");
+ System.out.println(updateTime + "ms [" + speed + "bytes/second, " +
eachTime + "ms/update]");
+
+ System.out.println("\nEnd benchmark");
+ }
+
+ private static byte[] createDummyData(int size) {
+ Random rand = new Random();
+ byte buf[] = new byte[size];
+ rand.nextBytes(buf);
+ return buf;
+ }
+
+ public static void SHAselfTest() {
+ System.err.println("Testing JavaSHA1:");
+ try {
+ JavaSHA1 js = new JavaSHA1();
+ SHAselfTest(js);
+ } catch (Exception e) {
+ System.err.println("Caught exception "+e+
+ " trying to test JavaSHA1");
+ }
+ System.err.println("Testing SHA1:");
+ SHA1 s = new SHA1(true);
+ SHAselfTest(s);
+ }
+
+ /**
+ * perfoms a self-test - spits out the test vector outputs on System.out
+ */
+ public static void SHAselfTest(Digest s) {
+ int i, j;
+ // This line may be safely deleted, its to make it easy to see
+ // the output of the program.
+ System.out.println("SHA-1 Test PROGRAM.");
+ System.out.println("This code runs the test vectors through the
code.");
+
+/* "abc"
+ A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D */
+
+ System.out.println("First test is 'abc'");
+ String z = "abc";
+ //s.init();
+ s.update((byte) 'a');
+ s.update((byte) 'b');
+ s.update((byte) 'c');
+ System.out.println(HexUtil.bytesToHex(s.digest()).toUpperCase());
+ System.out.println("A9993E364706816ABA3E25717850C26C9CD0D89D");
+
+/* "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 */
+
+ System.out.println("Next Test is
'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'");
+ z = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
+ //s.init(); - initted by digest above
+ for (i=0; i<z.length(); ++i) {
+ s.update((byte) z.charAt(i));
+ }
+ System.out.println(HexUtil.bytesToHex(s.digest()).toUpperCase());
+ System.out.println("84983E441C3BD26EBAAE4AA1F95129E5E54670F1");
+
+ /* A million repetitions of "a"
+ 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F */
+ long startTime = 0 - System.currentTimeMillis();
+
+ System.out.println("Last test is 1 million 'a' characters.");
+ //s.init(); - initted by digest above
+ for (i = 0; i < 1000000; i++)
+ s.update((byte) 'a');
+ //s.finish(); - digest() finishes
+ System.out.println(HexUtil.bytesToHex(s.digest()).toUpperCase());
+ System.out.println("34AA973CD4C4DAA4F61EEB2BDBAD27316534016F");
+ startTime += System.currentTimeMillis();
+ double d = startTime/1000.0;
+ System.out.println(" done, elapsed time = "+d);
+ }
+}
+
+
Added: trunk/apps/installer/src/freenet/support/HexUtil.java
===================================================================
--- trunk/apps/installer/src/freenet/support/HexUtil.java 2006-02-12
13:57:03 UTC (rev 8023)
+++ trunk/apps/installer/src/freenet/support/HexUtil.java 2006-02-12
16:12:44 UTC (rev 8024)
@@ -0,0 +1,221 @@
+package freenet.support;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.BitSet;
+
+/**
+ * Number in hexadecimal format are used throughout Freenet.
+ *
+ * <p>Unless otherwise stated, the conventions follow the rules outlined in
the
+ * Java Language Specification.</p>
+ *
+ * @author syoung
+ */
+public class HexUtil {
+ private static boolean logDEBUG
=Logger.logger.instanceShouldLog(Logger.DEBUG,HexUtil.class);
+ private HexUtil() {
+ }
+
+
+ /**
+ * Converts a byte array into a string of upper case hex chars.
+ *
+ * @param bs
+ * A byte array
+ * @param off
+ * The index of the first byte to read
+ * @param length
+ * The number of bytes to read.
+ * @return the string of hex chars.
+ */
+ public static final String bytesToHex(byte[] bs, int off, int length) {
+ StringBuffer sb = new StringBuffer(length * 2);
+ bytesToHexAppend(bs, off, length, sb);
+ return sb.toString();
+ }
+
+ public static final void bytesToHexAppend(
+ byte[] bs,
+ int off,
+ int length,
+ StringBuffer sb) {
+ sb.ensureCapacity(sb.length() + length * 2);
+ for (int i = off; i < (off + length) && i < bs.length; i++) {
+ sb.append(Character.forDigit((bs[i] >>> 4) & 0xf, 16));
+ sb.append(Character.forDigit(bs[i] & 0xf, 16));
+ }
+ }
+
+ public static final String bytesToHex(byte[] bs) {
+ return bytesToHex(bs, 0, bs.length);
+ }
+
+ public static final byte[] hexToBytes(String s) {
+ return hexToBytes(s, 0);
+ }
+
+ public static final byte[] hexToBytes(String s, int off) {
+ byte[] bs = new byte[off + (1 + s.length()) / 2];
+ hexToBytes(s, bs, off);
+ return bs;
+ }
+
+ /**
+ * Converts a String of hex characters into an array of bytes.
+ *
+ * @param s
+ * A string of hex characters (upper case or lower) of even
+ * length.
+ * @param out
+ * A byte array of length at least s.length()/2 + off
+ * @param off
+ * The first byte to write of the array
+ */
+ public static final void hexToBytes(String s, byte[] out, int off)
+ throws NumberFormatException, IndexOutOfBoundsException {
+ int slen = s.length();
+ if ((slen % 2) != 0) {
+ s = '0' + s;
+ }
+
+ if (out.length < off + slen / 2) {
+ throw new IndexOutOfBoundsException(
+ "Output buffer too small for input ("
+ + out.length
+ + "<"
+ + off
+ + slen / 2
+ + ")");
+ }
+
+ // Safe to assume the string is even length
+ byte b1, b2;
+ for (int i = 0; i < slen; i += 2) {
+ b1 = (byte) Character.digit(s.charAt(i), 16);
+ b2 = (byte) Character.digit(s.charAt(i + 1), 16);
+ if (b1 < 0 || b2 < 0) {
+ throw new NumberFormatException();
+ }
+ out[off + i / 2] = (byte) (b1 << 4 | b2);
+ }
+ }
+
+ /**
+ * Pack the bits in ba into a byte[].
+ */
+ public final static byte[] bitsToBytes(BitSet ba, int size) {
+ int bytesAlloc = countBytesForBits(size);
+ byte[] b = new byte[bytesAlloc];
+ StringBuffer sb =null;
+ if(logDEBUG) sb = new StringBuffer(8*bytesAlloc); //TODO:
Should it be 2*8*bytesAlloc here?
+ for(int i=0;i<b.length;i++) {
+ short s = 0;
+ for(int j=0;j<8;j++) {
+ int idx = i*8+j;
+ boolean val =
+ idx > size ? false :
+ ba.get(idx);
+ s |= val ? (1<<j) : 0;
+ if(sb != null) sb.append(val ? '1' : '0');
+ }
+ if(s > 255) throw new IllegalStateException("WTF? s =
"+s);
+ b[i] = (byte)s;
+ }
+ if(logDEBUG) Logger.debug(HexUtil.class, "bytes: "+bytesAlloc+"
returned from bitsToBytes("
+ +ba+","+size+"): "+bytesToHex(b)+" for
"+sb.toString());
+ return b;
+ }
+
+ /**
+ * Pack the bits in ba into a byte[] then convert that
+ * to a hex string and return it.
+ */
+ public final static String bitsToHexString(BitSet ba, int size) {
+ return bytesToHex(bitsToBytes(ba, size));
+ }
+
+
+ /**
+ * @return the number of bytes required to represent the
+ * bitset
+ */
+ public static int countBytesForBits(int size) {
+ // Brackets matter here! == takes precedence over the rest
+ return (size/8) + ((size % 8) == 0 ? 0:1);
+ }
+
+
+ /**
+ * Read bits from a byte array into a bitset
+ * @param b the byte[] to read from
+ * @param ba the bitset to write to
+ */
+ public static void bytesToBits(byte[] b, BitSet ba, int maxSize) {
+ if(logDEBUG) Logger.debug(HexUtil.class,
"bytesToBits("+bytesToHex(b)+",ba,"+maxSize);
+ int x = 0;
+ for(int i=0;i<b.length;i++) {
+ for(int j=0;j<8;j++) {
+ if(x > maxSize) break;
+ int mask = 1 << j;
+ boolean value = (mask & b[i]) != 0;
+ ba.set(x, value);
+ x++;
+ }
+ }
+ }
+
+
+ /**
+ * Read a hex string of bits and write it into a bitset
+ * @param s hex string of the stored bits
+ * @param ba the bitset to store the bits in
+ * @param length the maximum number of bits to store
+ */
+ public static void hexToBits(String s, BitSet ba, int length) {
+ byte[] b = hexToBytes(s);
+ bytesToBits(b, ba, length);
+ }
+
+ /**
+ * Write a (reasonably short) BigInteger to a stream.
+ * @param integer the BigInteger to write
+ * @param out the stream to write it to
+ */
+ public static void writeBigInteger(BigInteger integer, DataOutputStream
out) throws IOException {
+ if(integer.signum() == -1) {
+ //dump("Negative BigInteger", Logger.ERROR, true);
+ throw new IllegalStateException("Negative BigInteger!");
+ }
+ byte[] buf = integer.toByteArray();
+ if(buf.length > Short.MAX_VALUE)
+ throw new IllegalStateException("Too long: "+buf.length);
+ out.writeShort((short)buf.length);
+ out.write(buf);
+ }
+
+ /**
+ * Read a (reasonably short) BigInteger from a DataInputStream
+ * @param dis the stream to read from
+ * @return a BigInteger
+ */
+ public static BigInteger readBigInteger(DataInputStream dis) throws
IOException {
+ short i = dis.readShort();
+ if(i < 0) throw new IOException("Invalid BigInteger length: "+i);
+ byte[] buf = new byte[i];
+ dis.readFully(buf);
+ return new BigInteger(1,buf);
+ }
+
+
+ /**
+ * Turn a BigInteger into a hex string.
+ * BigInteger.toString(16) NPEs on Sun JDK 1.4.2_05. :<
+ * The bugs in their Big* are getting seriously irritating...
+ */
+ public static String biToHex(BigInteger bi) {
+ return bytesToHex(bi.toByteArray());
+ }
+}