Skip to content

Commit

Permalink
Added Policy file checks to JceLoader. Updates HashResult and HashTyp…
Browse files Browse the repository at this point in the history
…e. Added Hash class
  • Loading branch information
unixninja92 committed Mar 22, 2015
1 parent f67effe commit 3fbcc84
Show file tree
Hide file tree
Showing 5 changed files with 688 additions and 12 deletions.
204 changes: 204 additions & 0 deletions src/freenet/crypt/Hash.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
/* This code is part of Freenet. It is distributed under the GNU General
* Public License, version 2 (or at your option any later version). See
* http://www.gnu.org/ for further details of the GPL. */
package freenet.crypt;

import java.nio.ByteBuffer;
import java.security.MessageDigest;

import net.i2p.util.NativeBigInteger;
import freenet.support.HexUtil;

/**
* The Hash class will generate the hash value of a given set of bytes and also verify that
* a hash matches a given set of bytes. The addBytes methods can be used to pass data into
* a buffer that will be used to generate a hash. Once a hash is generated, the buffer is
* cleared or reset.
* @author unixninja92
* Suggested HashType to use: SHA256
*/
public final class Hash{
private final HashType type;
private MessageDigest digest;

/**
* Creates an instance of Hash using the specified hashing algorithm.
* @param type The hashing algorithm to use.
*/
public Hash(HashType type){
this.type = type;
digest = type.get();
}

/**
* Generates the hash of all the bytes in the buffer added with the
* addBytes methods. The buffer is then cleared after the hash has been
* generated.
* @return The generated hash of all the bytes added since last reset.
*/
public final byte[] genHash(){
byte[] result = digest.digest();
if(type == HashType.ED2K){
//ED2K does not reset after generating a digest. Work around this issue
digest.reset();
}else if(type == HashType.TTH){
//TTH's .reset method is broken or isn't implemented. Work around this bug
digest = type.get();
}
return result;
}

/**
* Generates the hash of only the specified bytes. The buffer is cleared before
* processing the input to ensure that no extra data is included. Once the hash
* has been generated, the buffer is cleared again.
* @param input The bytes to hash
* @return The generated hash of the data
*/
public final byte[] genHash(byte[]... input) {
digest.reset();
addBytes(input);
return genHash();
}

/**
* Generates the HashResult of all the bytes in the buffer added with the
* addBytes methods. The buffer is then cleared after the hash has been
* generated.
* @return The generated hash as a HashResult of all the bytes added
* since last reset.
*/
public final HashResult genHashResult() {
return new HashResult(type, genHash());
}

/**
* Generates the hash as a HashResult string of only the specified bytes.
* The buffer is cleared before processing the input to ensure that no
* extra data is included. Once the hash has been generated, the buffer
* is cleared again.
* @param input The bytes to hash
* @return The generated hash as a HashResult of the data
*/
public final HashResult genHashResult(byte[]... input){
digest.reset();
addBytes(input);
return genHashResult();
}

/**
* Generates the hash as a hex string of all the bytes in the buffer added
* with the addBytes methods. The buffer is then cleared after the hash
* has been generated.
* @return The generated hash as a hex string of all the bytes added since
* last reset.
*/
public final String genHexHash() {
return HexUtil.bytesToHex(genHash());
}

/**
* Generates the hash as a NativeBigInteger of all the bytes in the buffer
* added with the addBytes methods. The buffer is then cleared after the hash
* has been generated.
* @return The generated hash as a NativeBigInteger of all the bytes added
* since last reset.
*/
public final NativeBigInteger genNativeBigIntegerHash(){
return new NativeBigInteger(1, genHash());
}

/**
* Generates the hash as a NativeBigInteger string of only the specified
* bytes. The buffer is cleared before processing the input to ensure that
* no extra data is included. Once the hash has been generated, the buffer
* is cleared again.
* @param input The bytes to hash
* @return The generated hash as a NativeBigInteger of the data
*/
public final NativeBigInteger genNativeBigIntegerHash(byte[]... data){
digest.reset();
addBytes(data);
return genNativeBigIntegerHash();
}

/**
* Adds the specified byte to the buffer of bytes to be hashed.
* @param input Byte to be added to hash
*/
public final void addByte(byte input){
digest.update(input);
}

/**
* Adds the specified byte arrays to the buffer of bytes to be hashed.
* @param input The byte[]s to add
*/
public final void addBytes(byte[]... input){
for(byte[] b: input){
digest.update(b);
}
}

/**
* Adds the remaining bytes from a ByteBuffer to the buffer of bytes
* to be hashed. The bytes read from the ByteBuffer will be from
* input.position() to input.remaining(). Upon return, the ByteBuffer's
* .position() will be equal to .remaining() and .remaining() will
* stay unchanged.
* @param input The ByteBuffer to be hashed
*/
public final void addBytes(ByteBuffer input){
digest.update(input);
}

/**
* Adds the specified portion of the byte[] passed in to the buffer
* of bytes to be hashed.
* @param input The array containing bytes to be hashed
* @param offset Where the first byte to hash is
* @param len How many bytes after the offset to add to hash.
*/
public final void addBytes(byte[] input, int offset, int len){
digest.update(input, offset, len);
}

/**
* Generates the hash of the byte arrays provided and checks to see if that hash
* is the same as the one passed in. The buffer is cleared before processing the
* input to ensure that no extra data is included. Once the hash has been
* generated, the buffer is cleared again.
* @param hash The hash to be verified
* @param data The data to be hashed
* @return Returns true if the generated hash matches the passed in hash.
* Otherwise returns false.
*/
public final boolean verify(byte[] hash, byte[]... data){
return MessageDigest.isEqual(hash, genHash(data));
}

/**
* Checks to see if the HashResults passed in are equivalent. Does a simple byte
* compare and type compare.
* @param hash1 The first hash to be compared
* @param hash2 The second hash to be compared
* @return Returns true if the hashes are the same. Otherwise returns false.
*/
public final static boolean verify(HashResult hash1, HashResult hash2){
return hash1.equals(hash2);
}

/**
* Generates the hash of the byte arrays provided as a HashResult and checks to
* see if that hash is the same as the one passed in.
* @param hash The HashResult to verify
* @param input The data to check against the HashResult
* @return Returns true if HashResult matches the generated HashResult of the data.
*/
public final static boolean verify(HashResult hash, byte[]... input){
HashType type = hash.type;
Hash h = new Hash(type);
return verify(hash, new HashResult(type, h.genHash(input)));
}

}
28 changes: 28 additions & 0 deletions src/freenet/crypt/HashResult.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
/* This code is part of Freenet. It is distributed under the GNU General
* Public License, version 2 (or at your option any later version). See
* http://www.gnu.org/ for further details of the GPL. */
package freenet.crypt;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.util.Arrays;

import com.db4o.ObjectContainer;
Expand Down Expand Up @@ -145,5 +149,29 @@ public HashResult clone() {
public String hashAsHex() {
return HexUtil.bytesToHex(result);
}

@Override
public boolean equals(Object otherObject){
if(!(otherObject instanceof HashResult)){
return false;
}

HashResult otherHash = (HashResult) otherObject;
if(type != otherHash.type){
return false;
}

return MessageDigest.isEqual(result, otherHash.result);
}

@Override
public int hashCode(){
int hash = 1;

hash *= 31 + type.hashCode();
hash *= 31 + result.hashCode();

return hash;
}

}
25 changes: 16 additions & 9 deletions src/freenet/crypt/HashType.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
/**
*
*/
/* This code is part of Freenet. It is distributed under the GNU General
* Public License, version 2 (or at your option any later version). See
* http://www.gnu.org/ for further details of the GPL. */
package freenet.crypt;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import org.bitpedia.util.TigerTree;

import freenet.support.Logger;

public enum HashType {
// warning: keep in sync with Util.mdProviders!
SHA1(1, 20),
Expand All @@ -24,34 +26,39 @@ public enum HashType {
public final String javaName;
public final int hashLength;

HashType(int bitmask, int hashLength) {
private HashType(int bitmask, int hashLength) {
this.bitmask = bitmask;
this.javaName = super.name();
this.hashLength = hashLength;
}

HashType(int bitmask, String name, int hashLength) {
private HashType(int bitmask, String name, int hashLength) {
this.bitmask = bitmask;
this.javaName = name;
this.hashLength = hashLength;
}

public MessageDigest get() throws NoSuchAlgorithmException {
public final MessageDigest get() {
if(javaName == null) {
if(this.name().equals("ED2K"))
return new Ed2MessageDigest();
if(this.name().equals("TTH"))
return new TigerTree();
}
if(name().equals("SHA256")) {
// User the pool
// Use the pool
return freenet.crypt.SHA256.getMessageDigest();
} else {
return MessageDigest.getInstance(javaName, Util.mdProviders.get(javaName));
try {
return MessageDigest.getInstance(javaName, Util.mdProviders.get(javaName));
} catch (NoSuchAlgorithmException e) {
Logger.error(HashType.class, "Internal error; please report:", e);
}
return null;
}
}

public void recycle(MessageDigest md) {
public final void recycle(MessageDigest md) {
if(this.equals(SHA256)) {
freenet.crypt.SHA256.returnMessageDigest(md);
} // Else no pooling.
Expand Down
32 changes: 29 additions & 3 deletions src/freenet/crypt/JceLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.lang.reflect.Constructor;
import java.security.GeneralSecurityException;
import java.security.Provider;
import java.security.Security;
import java.security.Signature;

import javax.crypto.KeyAgreement;
import javax.crypto.KeyGenerator;

import freenet.support.Logger;
import freenet.support.io.Closer;
Expand All @@ -35,9 +37,20 @@ static private boolean checkUse(String prop, String def)
if (checkUse("use.NSS","false")) {
try {
p = (new NSSLoader()).load(checkUse("prefer.NSS"));
try{
KeyGenerator kgen = KeyGenerator.getInstance("AES", "SunPKCS11-NSS");
kgen.init(256);
} catch (GeneralSecurityException e) {
final String msg = "Error with SunPKCS11-NSS. "
+ "Unlimited policy file not installed.";
Logger.warning(NSSLoader.class, msg, e);
System.out.println(msg);
}
} catch(Throwable e) {
// FIXME what about Windows/MacOSX/etc?
final String msg = "Unable to load SunPKCS11-NSScrypto provider. This is NOT fatal error, Freenet will work, but some performance degradation possible. Consider installing libnss3 package.";
final String msg = "Unable to load SunPKCS11-NSScrypto provider. "
+ "This is NOT fatal error, Freenet will work, but some performance "
+ "degradation possible. Consider installing libnss3 package.";
Logger.warning(NSSLoader.class, msg, e);
}
}
Expand All @@ -55,16 +68,29 @@ static private boolean checkUse(String prop, String def)
}
BouncyCastle = p;
// optional
if (checkUse("use.SunJCE")) {
try{
KeyGenerator kgen = KeyGenerator.getInstance("AES", "SunJCE");
kgen.init(256);
}
catch(Throwable e) {
final String msg = "Error with SunJCE. Unlimited policy file not installed.";
Logger.warning(NSSLoader.class, msg, e);
}
SunJCE = Security.getProvider("SunJCE");
}
else SunJCE = null;

SUN = checkUse("use.SUN") ? Security.getProvider("SUN") : null;
SunJCE = checkUse("use.SunJCE") ? Security.getProvider("SunJCE") : null;
}
static private class BouncyCastleLoader {
private BouncyCastleLoader() {}
private Provider load() throws Throwable {
Provider p = Security.getProvider("BC");
if (p == null) {
try {
Class<?> c = Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider");
Class<?> c =
Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider");
p = (Provider)c.newInstance();
Security.addProvider(p);
} catch(Throwable e) {
Expand Down
Loading

0 comments on commit 3fbcc84

Please sign in to comment.