Replaced SHA-256 with SHAd-256 to prevent length extension attacks.

This commit is contained in:
akwizgran
2011-11-15 11:11:31 +00:00
parent effa5c9d8e
commit cf49a28c95
24 changed files with 140 additions and 38 deletions

View File

@@ -1,7 +1,6 @@
package net.sf.briar.api.crypto;
import java.security.KeyPair;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.security.Signature;

View File

@@ -0,0 +1,29 @@
package net.sf.briar.api.crypto;
/** An interface that allows a java.security.MessageDigest to be wrapped. */
public interface MessageDigest {
/** @see {@link java.security.MessageDigest#digest()} */
byte[] digest();
/** @see {@link java.security.MessageDigest#digest(byte[])} */
byte[] digest(byte[] input);
/** @see {@link java.security.MessageDigest#digest(byte[], int, int)} */
int digest(byte[] buf, int offset, int len);
/** @see {@link java.security.MessageDigest#getDigestLength()} */
int getDigestLength();
/** @see {@link java.security.MessageDigest#reset()} */
void reset();
/** @see {@link java.security.MessageDigest#update(byte)} */
void update(byte input);
/** @see {@link java.security.MessageDigest#update(byte[])} */
void update(byte[] input);
/** @see {@link java.security.MessageDigest#update(byte[], int, int)} */
void update(byte[] input, int offset, int len);
}

View File

@@ -1,16 +1,14 @@
package net.sf.briar.protocol;
package net.sf.briar.api.serial;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import net.sf.briar.api.serial.Consumer;
/** A consumer that makes a copy of the bytes consumed. */
class CopyingConsumer implements Consumer {
public class CopyingConsumer implements Consumer {
private final ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] getCopy() {
public byte[] getCopy() {
return out.toByteArray();
}

View File

@@ -1,24 +1,23 @@
package net.sf.briar.protocol;
package net.sf.briar.api.serial;
import java.io.IOException;
import net.sf.briar.api.FormatException;
import net.sf.briar.api.serial.Consumer;
/**
* A consumer that counts the number of bytes consumed and throws a
* FormatException if the count exceeds a given limit.
*/
class CountingConsumer implements Consumer {
public class CountingConsumer implements Consumer {
private final long limit;
private long count = 0L;
CountingConsumer(long limit) {
public CountingConsumer(long limit) {
this.limit = limit;
}
long getCount() {
public long getCount() {
return count;
}

View File

@@ -1,15 +1,13 @@
package net.sf.briar.protocol;
package net.sf.briar.api.serial;
import java.security.MessageDigest;
import net.sf.briar.api.serial.Consumer;
import net.sf.briar.api.crypto.MessageDigest;
/** A consumer that passes its input through a message digest. */
class DigestingConsumer implements Consumer {
public class DigestingConsumer implements Consumer {
private final MessageDigest messageDigest;
DigestingConsumer(MessageDigest messageDigest) {
public DigestingConsumer(MessageDigest messageDigest) {
this.messageDigest = messageDigest;
}

View File

@@ -1,17 +1,15 @@
package net.sf.briar.protocol;
package net.sf.briar.api.serial;
import java.io.IOException;
import java.security.Signature;
import java.security.SignatureException;
import net.sf.briar.api.serial.Consumer;
/** A consumer that passes its input through a signature. */
class SigningConsumer implements Consumer {
public class SigningConsumer implements Consumer {
private final Signature signature;
SigningConsumer(Signature signature) {
public SigningConsumer(Signature signature) {
this.signature = signature;
}

View File

@@ -5,7 +5,6 @@ import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
@@ -25,6 +24,7 @@ import javax.crypto.spec.SecretKeySpec;
import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.crypto.KeyParser;
import net.sf.briar.api.crypto.MessageDigest;
import net.sf.briar.api.crypto.SecretStorageKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
@@ -198,7 +198,8 @@ class CryptoComponentImpl implements CryptoComponent {
public MessageDigest getMessageDigest() {
try {
return MessageDigest.getInstance(DIGEST_ALGO, PROVIDER);
return new DoubleDigest(java.security.MessageDigest.getInstance(
DIGEST_ALGO, PROVIDER));
} catch(NoSuchAlgorithmException e) {
throw new RuntimeException(e);
} catch(NoSuchProviderException e) {

View File

@@ -0,0 +1,59 @@
package net.sf.briar.crypto;
import net.sf.briar.api.crypto.MessageDigest;
/**
* A message digest that prevents length extension attacks - see Ferguson and
* Schneier, <i>Practical Cryptography</i>, chapter 6.
* <p>
* "Let h be an interative hash function. The hash function h<sub>d</sub> is
* defined by h<sub>d</sub> := h(h(m)), and has a claimed security level of
* min(k, n/2) where k is the security level of h and n is the size of the hash
* result."
*/
class DoubleDigest implements MessageDigest {
private final java.security.MessageDigest delegate;
DoubleDigest(java.security.MessageDigest delegate) {
this.delegate = delegate;
}
public byte[] digest() {
byte[] digest = delegate.digest(); // h(m)
delegate.update(digest);
return delegate.digest(); // h(h(m))
}
public byte[] digest(byte[] input) {
delegate.update(input);
return digest();
}
public int digest(byte[] buf, int offset, int len) {
byte[] digest = digest();
len = Math.min(len, digest.length);
System.arraycopy(digest, 0, buf, offset, len);
return len;
}
public int getDigestLength() {
return delegate.getDigestLength();
}
public void reset() {
delegate.reset();
}
public void update(byte input) {
delegate.update(input);
}
public void update(byte[] input) {
delegate.update(input);
}
public void update(byte[] input, int offset, int len) {
delegate.update(input, offset, len);
}
}

View File

@@ -8,6 +8,7 @@ import net.sf.briar.api.protocol.BatchId;
import net.sf.briar.api.protocol.ProtocolConstants;
import net.sf.briar.api.protocol.Types;
import net.sf.briar.api.serial.Consumer;
import net.sf.briar.api.serial.CountingConsumer;
import net.sf.briar.api.serial.ObjectReader;
import net.sf.briar.api.serial.Reader;

View File

@@ -2,9 +2,9 @@ package net.sf.briar.protocol;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.MessageDigest;
import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.crypto.MessageDigest;
import net.sf.briar.api.protocol.Author;
import net.sf.briar.api.protocol.AuthorFactory;
import net.sf.briar.api.protocol.AuthorId;

View File

@@ -1,14 +1,15 @@
package net.sf.briar.protocol;
import java.io.IOException;
import java.security.MessageDigest;
import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.crypto.MessageDigest;
import net.sf.briar.api.protocol.Author;
import net.sf.briar.api.protocol.AuthorFactory;
import net.sf.briar.api.protocol.AuthorId;
import net.sf.briar.api.protocol.ProtocolConstants;
import net.sf.briar.api.protocol.Types;
import net.sf.briar.api.serial.DigestingConsumer;
import net.sf.briar.api.serial.ObjectReader;
import net.sf.briar.api.serial.Reader;

View File

@@ -1,16 +1,18 @@
package net.sf.briar.protocol;
import java.io.IOException;
import java.security.MessageDigest;
import java.util.List;
import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.crypto.MessageDigest;
import net.sf.briar.api.protocol.Batch;
import net.sf.briar.api.protocol.BatchId;
import net.sf.briar.api.protocol.Message;
import net.sf.briar.api.protocol.ProtocolConstants;
import net.sf.briar.api.protocol.Types;
import net.sf.briar.api.serial.Consumer;
import net.sf.briar.api.serial.CountingConsumer;
import net.sf.briar.api.serial.DigestingConsumer;
import net.sf.briar.api.serial.ObjectReader;
import net.sf.briar.api.serial.Reader;

View File

@@ -2,9 +2,9 @@ package net.sf.briar.protocol;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.MessageDigest;
import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.crypto.MessageDigest;
import net.sf.briar.api.protocol.Group;
import net.sf.briar.api.protocol.GroupFactory;
import net.sf.briar.api.protocol.GroupId;

View File

@@ -1,14 +1,15 @@
package net.sf.briar.protocol;
import java.io.IOException;
import java.security.MessageDigest;
import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.crypto.MessageDigest;
import net.sf.briar.api.protocol.Group;
import net.sf.briar.api.protocol.GroupFactory;
import net.sf.briar.api.protocol.GroupId;
import net.sf.briar.api.protocol.ProtocolConstants;
import net.sf.briar.api.protocol.Types;
import net.sf.briar.api.serial.DigestingConsumer;
import net.sf.briar.api.serial.ObjectReader;
import net.sf.briar.api.serial.Reader;

View File

@@ -3,12 +3,12 @@ package net.sf.briar.protocol;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.Signature;
import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.crypto.MessageDigest;
import net.sf.briar.api.protocol.Author;
import net.sf.briar.api.protocol.AuthorId;
import net.sf.briar.api.protocol.Group;
@@ -19,6 +19,9 @@ import net.sf.briar.api.protocol.MessageId;
import net.sf.briar.api.protocol.ProtocolConstants;
import net.sf.briar.api.protocol.Types;
import net.sf.briar.api.serial.Consumer;
import net.sf.briar.api.serial.CountingConsumer;
import net.sf.briar.api.serial.DigestingConsumer;
import net.sf.briar.api.serial.SigningConsumer;
import net.sf.briar.api.serial.Writer;
import net.sf.briar.api.serial.WriterFactory;

View File

@@ -2,13 +2,13 @@ package net.sf.briar.protocol;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.PublicKey;
import java.security.Signature;
import net.sf.briar.api.FormatException;
import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.crypto.KeyParser;
import net.sf.briar.api.crypto.MessageDigest;
import net.sf.briar.api.protocol.Author;
import net.sf.briar.api.protocol.AuthorId;
import net.sf.briar.api.protocol.Group;
@@ -17,6 +17,8 @@ import net.sf.briar.api.protocol.Message;
import net.sf.briar.api.protocol.MessageId;
import net.sf.briar.api.protocol.ProtocolConstants;
import net.sf.briar.api.protocol.Types;
import net.sf.briar.api.serial.CopyingConsumer;
import net.sf.briar.api.serial.CountingConsumer;
import net.sf.briar.api.serial.ObjectReader;
import net.sf.briar.api.serial.Reader;

View File

@@ -8,6 +8,7 @@ import net.sf.briar.api.protocol.Offer;
import net.sf.briar.api.protocol.ProtocolConstants;
import net.sf.briar.api.protocol.Types;
import net.sf.briar.api.serial.Consumer;
import net.sf.briar.api.serial.CountingConsumer;
import net.sf.briar.api.serial.ObjectReader;
import net.sf.briar.api.serial.Reader;

View File

@@ -7,6 +7,7 @@ import net.sf.briar.api.protocol.ProtocolConstants;
import net.sf.briar.api.protocol.Request;
import net.sf.briar.api.protocol.Types;
import net.sf.briar.api.serial.Consumer;
import net.sf.briar.api.serial.CountingConsumer;
import net.sf.briar.api.serial.ObjectReader;
import net.sf.briar.api.serial.Reader;

View File

@@ -9,6 +9,7 @@ import net.sf.briar.api.protocol.ProtocolConstants;
import net.sf.briar.api.protocol.SubscriptionUpdate;
import net.sf.briar.api.protocol.Types;
import net.sf.briar.api.serial.Consumer;
import net.sf.briar.api.serial.CountingConsumer;
import net.sf.briar.api.serial.ObjectReader;
import net.sf.briar.api.serial.Reader;

View File

@@ -15,6 +15,7 @@ import net.sf.briar.api.protocol.TransportUpdate;
import net.sf.briar.api.protocol.Types;
import net.sf.briar.api.protocol.UniqueId;
import net.sf.briar.api.serial.Consumer;
import net.sf.briar.api.serial.CountingConsumer;
import net.sf.briar.api.serial.ObjectReader;
import net.sf.briar.api.serial.Reader;

View File

@@ -2,23 +2,24 @@ package net.sf.briar.protocol.writers;
import java.io.IOException;
import java.io.OutputStream;
import java.security.DigestOutputStream;
import java.security.MessageDigest;
import net.sf.briar.api.crypto.MessageDigest;
import net.sf.briar.api.protocol.BatchId;
import net.sf.briar.api.protocol.ProtocolConstants;
import net.sf.briar.api.protocol.Types;
import net.sf.briar.api.protocol.writers.BatchWriter;
import net.sf.briar.api.serial.DigestingConsumer;
import net.sf.briar.api.serial.SerialComponent;
import net.sf.briar.api.serial.Writer;
import net.sf.briar.api.serial.WriterFactory;
class BatchWriterImpl implements BatchWriter {
private final DigestOutputStream out;
private final OutputStream out;
private final int headerLength, footerLength;
private final Writer w;
private final MessageDigest messageDigest;
private final DigestingConsumer digestingConsumer;
private boolean started = false;
private int capacity = ProtocolConstants.MAX_PACKET_LENGTH;
@@ -26,12 +27,13 @@ class BatchWriterImpl implements BatchWriter {
BatchWriterImpl(OutputStream out, SerialComponent serial,
WriterFactory writerFactory, MessageDigest messageDigest) {
this.out = new DigestOutputStream(out, messageDigest);
this.out = out;
headerLength = serial.getSerialisedUserDefinedIdLength(Types.BATCH)
+ serial.getSerialisedListStartLength();
footerLength = serial.getSerialisedListEndLength();
w = writerFactory.createWriter(this.out);
this.messageDigest = messageDigest;
digestingConsumer = new DigestingConsumer(messageDigest);
}
public int getCapacity() {
@@ -58,6 +60,7 @@ class BatchWriterImpl implements BatchWriter {
public BatchId finish() throws IOException {
if(!started) start();
w.writeListEnd();
w.removeConsumer(digestingConsumer);
out.flush();
remaining = capacity = ProtocolConstants.MAX_PACKET_LENGTH;
started = false;
@@ -66,6 +69,7 @@ class BatchWriterImpl implements BatchWriter {
private void start() throws IOException {
messageDigest.reset();
w.addConsumer(digestingConsumer);
w.writeUserDefinedId(Types.BATCH);
w.writeListStart();
remaining -= headerLength;

View File

@@ -1,9 +1,9 @@
package net.sf.briar.protocol.writers;
import java.io.OutputStream;
import java.security.MessageDigest;
import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.crypto.MessageDigest;
import net.sf.briar.api.protocol.writers.AckWriter;
import net.sf.briar.api.protocol.writers.BatchWriter;
import net.sf.briar.api.protocol.writers.OfferWriter;

View File

@@ -3,12 +3,12 @@ package net.sf.briar.protocol;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.util.Collections;
import junit.framework.TestCase;
import net.sf.briar.api.FormatException;
import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.crypto.MessageDigest;
import net.sf.briar.api.protocol.Batch;
import net.sf.briar.api.protocol.BatchId;
import net.sf.briar.api.protocol.Message;

View File

@@ -2,12 +2,15 @@ package net.sf.briar.protocol;
import static org.junit.Assert.assertArrayEquals;
import java.security.MessageDigest;
import java.util.Random;
import junit.framework.TestCase;
import net.sf.briar.api.FormatException;
import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.crypto.MessageDigest;
import net.sf.briar.api.serial.CopyingConsumer;
import net.sf.briar.api.serial.CountingConsumer;
import net.sf.briar.api.serial.DigestingConsumer;
import net.sf.briar.crypto.CryptoModule;
import org.junit.Before;