From: Gordon M. <go...@us...> - 2003-04-13 03:45:10
|
Update of /cvsroot/bitcollider/jbitprint/src/com/bitzi/util In directory sc8-pr-cvs1:/tmp/cvs-serv18284/src/com/bitzi/util Added Files: HashUrns.java Base32.java TigerTree.java Bitprint.java Log Message: refactoring/simplification under com.bitzi.util --- NEW FILE: HashUrns.java --- /* (PD) 2003 The Bitzi Corporation * Please see http://bitzi.com/publicdomain for more info. * * $Id: HashUrns.java,v 1.1 2003/04/13 03:45:05 gojomo Exp $ */ package com.bitzi.util; import java.io.FileInputStream; import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** * Display several hash-based URNs (sha1, tigertree, bitprint) for given file. * */ public class HashUrns { public static void main(String[] args) throws IOException, NoSuchAlgorithmException { if(args.length<1) { System.out.println("You must supply a filename."); return; } MessageDigest tt = new TigerTree(); MessageDigest sha1 = MessageDigest.getInstance("SHA"); FileInputStream fis; for(int i=0;i<args.length;i++) { fis = new FileInputStream(args[i]); int read; byte[] in = new byte[1024]; while((read = fis.read(in)) > -1) { tt.update(in,0,read); sha1.update(in,0,read); } fis.close(); byte[] ttdigest = tt.digest(); byte[] sha1digest = sha1.digest(); System.out.println("urn:sha1:"+Base32.encode(sha1digest)); System.out.println("urn:tree:tiger/:"+Base32.encode(ttdigest)); System.out.println("urn:bitprint:"+Base32.encode(sha1digest)+"."+Base32.encode(ttdigest)); } } } --- NEW FILE: Base32.java --- /* (PD) 2003 The Bitzi Corporation * Please see http://bitzi.com/publicdomain for more info. * * Base32.java * */ package com.bitzi.util; /** * Base32 - encodes and decodes 'Canonical' Base32 * (see * http://www.ietf.org/internet-drafts/draft-josefsson-base-encoding-04.txt * or http://josefsson.org/ to find a later copy, when the IETF breaks that link) * * @author Robert Kaye & Gordon Mohr */ public class Base32 { private static final String base32Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; private static final int[] base32Lookup = { 0xFF,0xFF,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F, // '0', '1', '2', '3', '4', '5', '6', '7' 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, // '8', '9', ':', ';', '<', '=', '>', '?' 0xFF,0x00,0x01,0x02,0x03,0x04,0x05,0x06, // '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G' 0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E, // 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O' 0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16, // 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W' 0x17,0x18,0x19,0xFF,0xFF,0xFF,0xFF,0xFF, // 'X', 'Y', 'Z', '[', '\', ']', '^', '_' 0xFF,0x00,0x01,0x02,0x03,0x04,0x05,0x06, // '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g' 0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E, // 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o' 0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16, // 'p', 'q', 'r', 's', 't', 'u', 'v', 'w' 0x17,0x18,0x19,0xFF,0xFF,0xFF,0xFF,0xFF // 'x', 'y', 'z', '{', '|', '}', '~', 'DEL' }; /** * * @param bytes * @return */ static public String encode(final byte[] bytes) { int i =0, index = 0, digit = 0; int currByte, nextByte; StringBuffer base32 = new StringBuffer((bytes.length+7)*8/5); while(i < bytes.length) { currByte = (bytes[i]>=0) ? bytes[i] : (bytes[i]+256); // unsign /* Is the current digit going to span a byte boundary? */ if (index > 3) { if ((i+1)<bytes.length) nextByte = (bytes[i+1]>=0) ? bytes[i+1] : (bytes[i+1]+256); else nextByte = 0; digit = currByte & (0xFF >> index); index = (index + 5) % 8; digit <<= index; digit |= nextByte >> (8 - index); i++; } else { digit = (currByte >> (8 - (index + 5))) & 0x1F; index = (index + 5) % 8; if (index == 0) i++; } base32.append(base32Chars.charAt(digit)); } return base32.toString(); } /** * @param base32 * @return */ static public byte[] decode(final String base32) { int i, index, lookup, offset, digit; byte[] bytes = new byte[base32.length()*5/8]; for(i = 0, index = 0, offset = 0; i < base32.length(); i++) { lookup = base32.charAt(i) - '0'; /* Skip chars outside the lookup table */ if ( lookup < 0 || lookup >= base32Lookup.length) continue; digit = base32Lookup[lookup]; /* If this digit is not in the table, ignore it */ if (digit == 0xFF) continue; if (index <= 3) { index = (index + 5) % 8; if (index == 0) { bytes[offset] |= digit; offset++; if(offset>=bytes.length) break; } else bytes[offset] |= digit << (8 - index); } else { index = (index + 5) % 8; bytes[offset] |= (digit >>> index); offset++; if(offset>=bytes.length) break; bytes[offset] |= digit << (8 - index); } } return bytes; } /** For testing, take a command-line argument in Base32, decode, print in hex, * encode, print */ static public void main(String[] args) { if (args.length==0) { System.out.println("Supply a Base32-encoded argument."); return; } System.out.println(" Original: "+args[0]); byte[] decoded = Base32.decode(args[0]); System.out.print (" Hex: "); for(int i = 0; i < decoded.length ; i++) { int b = decoded[i]; if (b<0) b+=256; System.out.print((Integer.toHexString(b+256)).substring(1)); } System.out.println(); System.out.println("Reencoded: "+Base32.encode(decoded)); } } --- NEW FILE: TigerTree.java --- /* (PD) 2003 The Bitzi Corporation * Please see http://bitzi.com/publicdomain for more info. * * $Id: TigerTree.java,v 1.1 2003/04/13 03:45:05 gojomo Exp $ */ package com.bitzi.util; import java.io.FileInputStream; import java.io.IOException; import java.math.BigInteger; import java.security.DigestException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.util.Enumeration; import java.util.Vector; /** * Implementation of THEX tree hash algorithm, with Tiger * as the internal algorithm (using the approach as revised * in December 2002, to add unique prefixes to leaf and node * operations) * * For simplicity, calculates one entire generation before * starting on the next. A more space-efficient approach * would use a stack, and calculate each node as soon as * its children ara available. */ public class TigerTree extends MessageDigest { private static final int BLOCKSIZE = 1024; private static final int HASHSIZE = 24; /** 1024 byte buffer */ private final byte[] buffer; /** Buffer offset */ private int bufferOffset; /** Number of bytes hashed until now. */ private long byteCount; /** Internal Tiger MD instance */ private MessageDigest tiger; /** Interim tree node hash values */ private Vector nodes; /** * Constructor */ public TigerTree() throws NoSuchAlgorithmException { super("TigerTree"); buffer = new byte[BLOCKSIZE]; bufferOffset = 0; byteCount = 0; try { java.security.Security.addProvider(new cryptix.jce.provider. CryptixCrypto()); tiger = MessageDigest.getInstance("Tiger", "CryptixCrypto"); } catch(NoSuchProviderException e) { System.out.println("Provider Cryptix not found"); System.exit(0); } nodes = new Vector(); } protected int engineGetDigestLength() { return HASHSIZE; } protected void engineUpdate(byte in) { byteCount += 1; buffer[bufferOffset++] = in; if( bufferOffset==BLOCKSIZE ) { blockUpdate(); bufferOffset = 0; } } protected void engineUpdate(byte[] in, int offset, int length) { byteCount += length; int remaining; while( length >= (remaining = BLOCKSIZE - bufferOffset) ) { System.arraycopy(in, offset, buffer, bufferOffset, remaining); bufferOffset += remaining; blockUpdate(); length -= remaining; offset += remaining; bufferOffset = 0; } System.arraycopy(in, offset, buffer, bufferOffset, length); bufferOffset += length; } protected byte[] engineDigest() { byte[] hash = new byte[HASHSIZE]; try { engineDigest(hash, 0, HASHSIZE); } catch (DigestException e) { return null; } return hash; } protected int engineDigest(byte[] buf, int offset, int len) throws DigestException { if(len<HASHSIZE) throw new DigestException(); // hash any remaining fragments blockUpdate(); // composite neighboring nodes together up to top value while (nodes.size() > 1) { Vector newNodes = new Vector(); Enumeration iter = nodes.elements(); while (iter.hasMoreElements()) { byte[] left = (byte[])iter.nextElement(); if(iter.hasMoreElements()) { byte[] right = (byte[])iter.nextElement(); tiger.reset(); tiger.update((byte)1); // node prefix tiger.update(left); tiger.update(right); newNodes.addElement((Object)tiger.digest()); } else { newNodes.addElement((Object)left); } } nodes = newNodes; } System.arraycopy(nodes.elementAt(0), 0, buf, offset, HASHSIZE); engineReset(); return HASHSIZE; } protected void engineReset() { bufferOffset = 0; byteCount = 0; nodes = new Vector(); tiger.reset(); } public Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } /** * Update the internal state with a single block of size 1024 * (or less, in final block) from the internal buffer. */ protected void blockUpdate() { tiger.reset(); tiger.update((byte)0); // leaf prefix tiger.update(buffer,0,bufferOffset); if((bufferOffset==0)&(nodes.size()>0)) return; // don't remember a zero-size hash except at very beginning nodes.addElement((Object)tiger.digest()); } public static void main(String[] args) throws IOException, NoSuchAlgorithmException { if(args.length<1) { System.out.println("You must supply a filename."); return; } MessageDigest tt = new TigerTree(); FileInputStream fis; for(int i=0;i<args.length;i++) { fis = new FileInputStream(args[i]); int read; byte[] in = new byte[1024]; while((read = fis.read(in)) > -1) { tt.update(in,0,read); } fis.close(); byte[] digest = tt.digest(); String hash = new BigInteger(1,digest).toString(16); while(hash.length()<48) { hash = "0"+hash; } System.out.println("hex:"+hash); System.out.println("b32:"+Base32.encode(digest)); tt.reset(); } } } --- NEW FILE: Bitprint.java --- /* (PD) 2001 The Bitzi Corporation * Please see http://bitzi.com/publicdomain for more info. * * $Id: Bitprint.java,v 1.1 2003/04/13 03:45:05 gojomo Exp $ */ package com.bitzi.util; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.security.DigestException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class Bitprint extends MessageDigest { private MessageDigest tigertree, sha; public Bitprint() throws NoSuchAlgorithmException { super("Bitprint"); sha = MessageDigest.getInstance("SHA"); tigertree = new TigerTree(); } public int engineGetDigestLength() { return sha.getDigestLength() + tigertree.getDigestLength(); } public void engineUpdate(byte in) { tigertree.update(in); sha.update(in); } public void engineUpdate(byte[] in, int offset, int length) { tigertree.update(in, offset, length); sha.update(in, offset, length); } public byte[] engineDigest() { byte[] digest; digest = new byte[engineGetDigestLength()]; try { sha.digest(digest); tigertree.digest( digest, sha.getDigestLength(), tigertree.getDigestLength()); } catch (DigestException e) { return null; } engineReset(); return digest; } public int engineDigest(byte[] buf, int offset, int len) throws DigestException { byte[] digest; int digestLen; digest = new byte[engineGetDigestLength()]; digestLen = engineGetDigestLength(); if (len < digestLen) throw new DigestException(); digest = engineDigest(); System.arraycopy(digest, 0, buf, offset, digestLen); return digestLen; } public void engineReset() { sha.reset(); tigertree.reset(); } public Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } // private void hashCheck() // throws NoSuchAlgorithmException // { // BitprintUtils utils = new BitprintUtils(); // Base32 base32 = new Base32(); // String hash; // // hash = new BigInteger(1,tigerTree.digest()).toString(16); // tigerTree.reset(); // // if (!hash.equals(hashEmpty)) // throw new NoSuchAlgorithmException( // "TigerTree internal check failed. (empty)"); // // tigerTree.update((byte)49); // hash = new BigInteger(1,tigerTree.digest()).toString(16); // tigerTree.reset(); // // if (!hash.equals(hashOne)) // throw new NoSuchAlgorithmException( // "TigerTree internal check failed. (one byte)"); // // byte[] oneK = new byte[1026]; // java.util.Arrays.fill(oneK, 0, 1025, (byte)97); // tigerTree.update(oneK, 0, 1025); // hash = new BigInteger(1,tigerTree.digest()).toString(16); // tigerTree.reset(); // // if (!hash.equals(hashOneK)) // throw new NoSuchAlgorithmException( // "TigerTree internal check failed. (1025 bytes)"); // } public static byte[] bitprintFile(String fileName) throws FileNotFoundException { FileInputStream stream = new FileInputStream(fileName); byte[] digest; return bitprintStream(stream); } public static byte[] bitprintStream(InputStream stream) { try { MessageDigest bitprint = new Bitprint(); int read; byte[] in = new byte[4096]; while ((read = stream.read(in)) > -1) { bitprint.update(in, 0, read); } return bitprint.digest(); } catch (IOException e) { return null; } catch (NoSuchAlgorithmException e) { return null; } } public static byte[] bitprintBuffer(byte[] buffer, int offset, int len) { try { MessageDigest bitprint = new Bitprint(); bitprint.update(buffer, offset, len); return bitprint.digest(); } catch (NoSuchAlgorithmException e) { return null; } } public static byte[] bitprintBuffer(byte[] buffer) { return bitprintBuffer(buffer, 0, buffer.length); } // static void main(String[] args) // throws IOException, NoSuchAlgorithmException , NoSuchProviderException // { // if(args.length<1) { // System.out.println("You must supply a filename."); // return; // } // // BitprintUtils utils = new BitprintUtils(); // // //byte[] digest = utils.bitprintFile(args[0]); // byte[] digest = null; // byte[] buffer = new byte[1]; // buffer[0] = 97; // try // { // digest = utils.bitprintBuffer(buffer, 0, 1); // } // catch(BitprintException e) // { // System.out.println("BitprintException: " + e.getMessage()); // System.exit(0); // } // // String hash = new BigInteger(1,digest).toString(16); // while(hash.length()<48) // { // hash = "0"+hash; // } // System.out.println(hash); // } } |