Skip to content

Commit 3fbcc84

Browse files
committed
Added Policy file checks to JceLoader. Updates HashResult and HashType. Added Hash class
1 parent f67effe commit 3fbcc84

File tree

5 files changed

+688
-12
lines changed

5 files changed

+688
-12
lines changed

src/freenet/crypt/Hash.java

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
/* This code is part of Freenet. It is distributed under the GNU General
2+
* Public License, version 2 (or at your option any later version). See
3+
* http://www.gnu.org/ for further details of the GPL. */
4+
package freenet.crypt;
5+
6+
import java.nio.ByteBuffer;
7+
import java.security.MessageDigest;
8+
9+
import net.i2p.util.NativeBigInteger;
10+
import freenet.support.HexUtil;
11+
12+
/**
13+
* The Hash class will generate the hash value of a given set of bytes and also verify that
14+
* a hash matches a given set of bytes. The addBytes methods can be used to pass data into
15+
* a buffer that will be used to generate a hash. Once a hash is generated, the buffer is
16+
* cleared or reset.
17+
* @author unixninja92
18+
* Suggested HashType to use: SHA256
19+
*/
20+
public final class Hash{
21+
private final HashType type;
22+
private MessageDigest digest;
23+
24+
/**
25+
* Creates an instance of Hash using the specified hashing algorithm.
26+
* @param type The hashing algorithm to use.
27+
*/
28+
public Hash(HashType type){
29+
this.type = type;
30+
digest = type.get();
31+
}
32+
33+
/**
34+
* Generates the hash of all the bytes in the buffer added with the
35+
* addBytes methods. The buffer is then cleared after the hash has been
36+
* generated.
37+
* @return The generated hash of all the bytes added since last reset.
38+
*/
39+
public final byte[] genHash(){
40+
byte[] result = digest.digest();
41+
if(type == HashType.ED2K){
42+
//ED2K does not reset after generating a digest. Work around this issue
43+
digest.reset();
44+
}else if(type == HashType.TTH){
45+
//TTH's .reset method is broken or isn't implemented. Work around this bug
46+
digest = type.get();
47+
}
48+
return result;
49+
}
50+
51+
/**
52+
* Generates the hash of only the specified bytes. The buffer is cleared before
53+
* processing the input to ensure that no extra data is included. Once the hash
54+
* has been generated, the buffer is cleared again.
55+
* @param input The bytes to hash
56+
* @return The generated hash of the data
57+
*/
58+
public final byte[] genHash(byte[]... input) {
59+
digest.reset();
60+
addBytes(input);
61+
return genHash();
62+
}
63+
64+
/**
65+
* Generates the HashResult of all the bytes in the buffer added with the
66+
* addBytes methods. The buffer is then cleared after the hash has been
67+
* generated.
68+
* @return The generated hash as a HashResult of all the bytes added
69+
* since last reset.
70+
*/
71+
public final HashResult genHashResult() {
72+
return new HashResult(type, genHash());
73+
}
74+
75+
/**
76+
* Generates the hash as a HashResult string of only the specified bytes.
77+
* The buffer is cleared before processing the input to ensure that no
78+
* extra data is included. Once the hash has been generated, the buffer
79+
* is cleared again.
80+
* @param input The bytes to hash
81+
* @return The generated hash as a HashResult of the data
82+
*/
83+
public final HashResult genHashResult(byte[]... input){
84+
digest.reset();
85+
addBytes(input);
86+
return genHashResult();
87+
}
88+
89+
/**
90+
* Generates the hash as a hex string of all the bytes in the buffer added
91+
* with the addBytes methods. The buffer is then cleared after the hash
92+
* has been generated.
93+
* @return The generated hash as a hex string of all the bytes added since
94+
* last reset.
95+
*/
96+
public final String genHexHash() {
97+
return HexUtil.bytesToHex(genHash());
98+
}
99+
100+
/**
101+
* Generates the hash as a NativeBigInteger of all the bytes in the buffer
102+
* added with the addBytes methods. The buffer is then cleared after the hash
103+
* has been generated.
104+
* @return The generated hash as a NativeBigInteger of all the bytes added
105+
* since last reset.
106+
*/
107+
public final NativeBigInteger genNativeBigIntegerHash(){
108+
return new NativeBigInteger(1, genHash());
109+
}
110+
111+
/**
112+
* Generates the hash as a NativeBigInteger string of only the specified
113+
* bytes. The buffer is cleared before processing the input to ensure that
114+
* no extra data is included. Once the hash has been generated, the buffer
115+
* is cleared again.
116+
* @param input The bytes to hash
117+
* @return The generated hash as a NativeBigInteger of the data
118+
*/
119+
public final NativeBigInteger genNativeBigIntegerHash(byte[]... data){
120+
digest.reset();
121+
addBytes(data);
122+
return genNativeBigIntegerHash();
123+
}
124+
125+
/**
126+
* Adds the specified byte to the buffer of bytes to be hashed.
127+
* @param input Byte to be added to hash
128+
*/
129+
public final void addByte(byte input){
130+
digest.update(input);
131+
}
132+
133+
/**
134+
* Adds the specified byte arrays to the buffer of bytes to be hashed.
135+
* @param input The byte[]s to add
136+
*/
137+
public final void addBytes(byte[]... input){
138+
for(byte[] b: input){
139+
digest.update(b);
140+
}
141+
}
142+
143+
/**
144+
* Adds the remaining bytes from a ByteBuffer to the buffer of bytes
145+
* to be hashed. The bytes read from the ByteBuffer will be from
146+
* input.position() to input.remaining(). Upon return, the ByteBuffer's
147+
* .position() will be equal to .remaining() and .remaining() will
148+
* stay unchanged.
149+
* @param input The ByteBuffer to be hashed
150+
*/
151+
public final void addBytes(ByteBuffer input){
152+
digest.update(input);
153+
}
154+
155+
/**
156+
* Adds the specified portion of the byte[] passed in to the buffer
157+
* of bytes to be hashed.
158+
* @param input The array containing bytes to be hashed
159+
* @param offset Where the first byte to hash is
160+
* @param len How many bytes after the offset to add to hash.
161+
*/
162+
public final void addBytes(byte[] input, int offset, int len){
163+
digest.update(input, offset, len);
164+
}
165+
166+
/**
167+
* Generates the hash of the byte arrays provided and checks to see if that hash
168+
* is the same as the one passed in. The buffer is cleared before processing the
169+
* input to ensure that no extra data is included. Once the hash has been
170+
* generated, the buffer is cleared again.
171+
* @param hash The hash to be verified
172+
* @param data The data to be hashed
173+
* @return Returns true if the generated hash matches the passed in hash.
174+
* Otherwise returns false.
175+
*/
176+
public final boolean verify(byte[] hash, byte[]... data){
177+
return MessageDigest.isEqual(hash, genHash(data));
178+
}
179+
180+
/**
181+
* Checks to see if the HashResults passed in are equivalent. Does a simple byte
182+
* compare and type compare.
183+
* @param hash1 The first hash to be compared
184+
* @param hash2 The second hash to be compared
185+
* @return Returns true if the hashes are the same. Otherwise returns false.
186+
*/
187+
public final static boolean verify(HashResult hash1, HashResult hash2){
188+
return hash1.equals(hash2);
189+
}
190+
191+
/**
192+
* Generates the hash of the byte arrays provided as a HashResult and checks to
193+
* see if that hash is the same as the one passed in.
194+
* @param hash The HashResult to verify
195+
* @param input The data to check against the HashResult
196+
* @return Returns true if HashResult matches the generated HashResult of the data.
197+
*/
198+
public final static boolean verify(HashResult hash, byte[]... input){
199+
HashType type = hash.type;
200+
Hash h = new Hash(type);
201+
return verify(hash, new HashResult(type, h.genHash(input)));
202+
}
203+
204+
}

src/freenet/crypt/HashResult.java

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

36
import java.io.DataInputStream;
47
import java.io.DataOutputStream;
58
import java.io.IOException;
9+
import java.security.MessageDigest;
610
import java.util.Arrays;
711

812
import com.db4o.ObjectContainer;
@@ -145,5 +149,29 @@ public HashResult clone() {
145149
public String hashAsHex() {
146150
return HexUtil.bytesToHex(result);
147151
}
152+
153+
@Override
154+
public boolean equals(Object otherObject){
155+
if(!(otherObject instanceof HashResult)){
156+
return false;
157+
}
158+
159+
HashResult otherHash = (HashResult) otherObject;
160+
if(type != otherHash.type){
161+
return false;
162+
}
163+
164+
return MessageDigest.isEqual(result, otherHash.result);
165+
}
166+
167+
@Override
168+
public int hashCode(){
169+
int hash = 1;
170+
171+
hash *= 31 + type.hashCode();
172+
hash *= 31 + result.hashCode();
173+
174+
return hash;
175+
}
148176

149177
}

src/freenet/crypt/HashType.java

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

66
import java.security.MessageDigest;
77
import java.security.NoSuchAlgorithmException;
88

99
import org.bitpedia.util.TigerTree;
1010

11+
import freenet.support.Logger;
12+
1113
public enum HashType {
1214
// warning: keep in sync with Util.mdProviders!
1315
SHA1(1, 20),
@@ -24,34 +26,39 @@ public enum HashType {
2426
public final String javaName;
2527
public final int hashLength;
2628

27-
HashType(int bitmask, int hashLength) {
29+
private HashType(int bitmask, int hashLength) {
2830
this.bitmask = bitmask;
2931
this.javaName = super.name();
3032
this.hashLength = hashLength;
3133
}
3234

33-
HashType(int bitmask, String name, int hashLength) {
35+
private HashType(int bitmask, String name, int hashLength) {
3436
this.bitmask = bitmask;
3537
this.javaName = name;
3638
this.hashLength = hashLength;
3739
}
3840

39-
public MessageDigest get() throws NoSuchAlgorithmException {
41+
public final MessageDigest get() {
4042
if(javaName == null) {
4143
if(this.name().equals("ED2K"))
4244
return new Ed2MessageDigest();
4345
if(this.name().equals("TTH"))
4446
return new TigerTree();
4547
}
4648
if(name().equals("SHA256")) {
47-
// User the pool
49+
// Use the pool
4850
return freenet.crypt.SHA256.getMessageDigest();
4951
} else {
50-
return MessageDigest.getInstance(javaName, Util.mdProviders.get(javaName));
52+
try {
53+
return MessageDigest.getInstance(javaName, Util.mdProviders.get(javaName));
54+
} catch (NoSuchAlgorithmException e) {
55+
Logger.error(HashType.class, "Internal error; please report:", e);
56+
}
57+
return null;
5158
}
5259
}
5360

54-
public void recycle(MessageDigest md) {
61+
public final void recycle(MessageDigest md) {
5562
if(this.equals(SHA256)) {
5663
freenet.crypt.SHA256.returnMessageDigest(md);
5764
} // Else no pooling.

src/freenet/crypt/JceLoader.java

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@
66
import java.io.OutputStream;
77
import java.io.OutputStreamWriter;
88
import java.lang.reflect.Constructor;
9+
import java.security.GeneralSecurityException;
910
import java.security.Provider;
1011
import java.security.Security;
1112
import java.security.Signature;
1213

1314
import javax.crypto.KeyAgreement;
15+
import javax.crypto.KeyGenerator;
1416

1517
import freenet.support.Logger;
1618
import freenet.support.io.Closer;
@@ -35,9 +37,20 @@ static private boolean checkUse(String prop, String def)
3537
if (checkUse("use.NSS","false")) {
3638
try {
3739
p = (new NSSLoader()).load(checkUse("prefer.NSS"));
40+
try{
41+
KeyGenerator kgen = KeyGenerator.getInstance("AES", "SunPKCS11-NSS");
42+
kgen.init(256);
43+
} catch (GeneralSecurityException e) {
44+
final String msg = "Error with SunPKCS11-NSS. "
45+
+ "Unlimited policy file not installed.";
46+
Logger.warning(NSSLoader.class, msg, e);
47+
System.out.println(msg);
48+
}
3849
} catch(Throwable e) {
3950
// FIXME what about Windows/MacOSX/etc?
40-
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.";
51+
final String msg = "Unable to load SunPKCS11-NSScrypto provider. "
52+
+ "This is NOT fatal error, Freenet will work, but some performance "
53+
+ "degradation possible. Consider installing libnss3 package.";
4154
Logger.warning(NSSLoader.class, msg, e);
4255
}
4356
}
@@ -55,16 +68,29 @@ static private boolean checkUse(String prop, String def)
5568
}
5669
BouncyCastle = p;
5770
// optional
71+
if (checkUse("use.SunJCE")) {
72+
try{
73+
KeyGenerator kgen = KeyGenerator.getInstance("AES", "SunJCE");
74+
kgen.init(256);
75+
}
76+
catch(Throwable e) {
77+
final String msg = "Error with SunJCE. Unlimited policy file not installed.";
78+
Logger.warning(NSSLoader.class, msg, e);
79+
}
80+
SunJCE = Security.getProvider("SunJCE");
81+
}
82+
else SunJCE = null;
83+
5884
SUN = checkUse("use.SUN") ? Security.getProvider("SUN") : null;
59-
SunJCE = checkUse("use.SunJCE") ? Security.getProvider("SunJCE") : null;
6085
}
6186
static private class BouncyCastleLoader {
6287
private BouncyCastleLoader() {}
6388
private Provider load() throws Throwable {
6489
Provider p = Security.getProvider("BC");
6590
if (p == null) {
6691
try {
67-
Class<?> c = Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider");
92+
Class<?> c =
93+
Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider");
6894
p = (Provider)c.newInstance();
6995
Security.addProvider(p);
7096
} catch(Throwable e) {

0 commit comments

Comments
 (0)