package uc.crypto; import helpers.GH; import java.util.Arrays; /** * * A HashValue represents the digest of a Tiger hash * most times used with TigetTreeHash * * @author Quicksilver * */ public abstract class HashValue implements Comparable<HashValue> { /** * the data.. */ private final byte[] hashValue; /** * parses a base 32 string into a hashvalue object * @param base32value * @return */ public static HashValue createHash(String base32value) { if (base32value.length() < 20) { throw new IllegalStateException(); // too small for a hash } if (base32value.substring(0, 4).equalsIgnoreCase("TTH/")) { base32value = base32value.substring(4); return new TigerHashValue(base32value); } if (base32value.length() == TigerHashValue.serializedDigestLength) { return new TigerHashValue(base32value); } if (base32value.substring(0, 7).equalsIgnoreCase("sha256/")) { base32value = base32value.substring(7); return new SHA256HashValue(base32value); } if (base32value.length() == SHA256HashValue.serializedDigestLength) { return new SHA256HashValue(base32value); } throw new IllegalStateException("hash not parseable: len "+base32value.length()); } public static HashValue createHash(byte[] data,String alg) { if (alg.equalsIgnoreCase("sha256") || alg.equalsIgnoreCase("sha-256")) { return SHA256HashValue.hashData(data); } if (alg.equalsIgnoreCase("tiger") || alg.equalsIgnoreCase("tigr")) { return Tiger.tigerOfBytes(data); } throw new IllegalStateException("unknown alg"); } public static boolean isHash(String base32Value) { if (base32Value == null) { return false; } return TigerHashValue.isTTH(base32Value) || SHA256HashValue.isSHA256HashValue(base32Value); } public static boolean isHash(byte[] hashBytes) { return hashBytes != null && (hashBytes.length == TigerHashValue.digestlength || hashBytes.length == SHA256HashValue.digestlength); } public static HashValue createHash(byte[] bytes) { if (bytes.length == TigerHashValue.digestlength) { return new TigerHashValue(bytes); } throw new IllegalStateException(); } /** * creates the same hash from a base32 encoded String * * @param base32value */ protected HashValue(String base32value){ hashValue = BASE32Encoder.decode(base32value); } /** * * @param value - a HashValue as an array of length 24 (24*8 = 192Bit) */ protected HashValue(byte[] value){ hashValue = value; } public HashValue copy() { byte[] retval = new byte[hashValue.length]; System.arraycopy(hashValue, 0, retval, 0, hashValue.length); return createHash(retval); } /** * @return a base32 encoded String of the HashValue */ public String toString(){ return BASE32Encoder.encode(hashValue); } /** * * @return a string name for magnet links * * i.e. "tiger" for Tiger hash * so urn:tree:tiger: */ public abstract String magnetString(); /** * * @return the array containing the hash in raw form * no copy.. * so changing this will change the hashvalue */ public byte[] getRaw() { return hashValue; } @Override public int hashCode() { return (hashValue[0] & 0xff) | ((hashValue[1] & 0xff) << 8) | ((hashValue[2] & 0xff) << 16) | ((hashValue[3] & 0xff) << 24) ; } /** * @return hash of this hash * hashofHash(h(x)) = h(h(x)) */ public abstract HashValue hashOfHash(); public abstract HashValue internalHash(HashValue rightChild); @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof HashValue)) return false; final HashValue other = (HashValue) obj; if (!Arrays.equals(getRaw(), other.getRaw())) return false; return true; } /** * comparing against other for sorting... */ public int compareTo(HashValue arg0) { for (int i=0; i < hashValue.length; i++) { if (hashValue[i] != arg0.hashValue[i]) { return GH.compareTo(hashValue[i] & 0xff , arg0.hashValue[i] & 0xff); } } return 0; } }