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());
+    }
+}


Reply via email to