mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-20 14:49:53 +01:00
Renamed "encrypted IVs" as "tags" (actual crypto changes to follow).
This commit is contained in:
@@ -11,7 +11,7 @@ public interface CryptoComponent {
|
|||||||
|
|
||||||
ErasableKey deriveFrameKey(byte[] secret, boolean initiator);
|
ErasableKey deriveFrameKey(byte[] secret, boolean initiator);
|
||||||
|
|
||||||
ErasableKey deriveIvKey(byte[] secret, boolean initiator);
|
ErasableKey deriveTagKey(byte[] secret, boolean initiator);
|
||||||
|
|
||||||
ErasableKey deriveMacKey(byte[] secret, boolean initiator);
|
ErasableKey deriveMacKey(byte[] secret, boolean initiator);
|
||||||
|
|
||||||
@@ -23,8 +23,6 @@ public interface CryptoComponent {
|
|||||||
|
|
||||||
Cipher getFrameCipher();
|
Cipher getFrameCipher();
|
||||||
|
|
||||||
Cipher getIvCipher();
|
|
||||||
|
|
||||||
KeyParser getKeyParser();
|
KeyParser getKeyParser();
|
||||||
|
|
||||||
Mac getMac();
|
Mac getMac();
|
||||||
@@ -34,4 +32,6 @@ public interface CryptoComponent {
|
|||||||
SecureRandom getSecureRandom();
|
SecureRandom getSecureRandom();
|
||||||
|
|
||||||
Signature getSignature();
|
Signature getSignature();
|
||||||
|
|
||||||
|
Cipher getTagCipher();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import net.sf.briar.api.protocol.TransportIndex;
|
|||||||
public interface BatchConnectionFactory {
|
public interface BatchConnectionFactory {
|
||||||
|
|
||||||
void createIncomingConnection(ConnectionContext ctx,
|
void createIncomingConnection(ConnectionContext ctx,
|
||||||
BatchTransportReader r, byte[] encryptedIv);
|
BatchTransportReader r, byte[] tag);
|
||||||
|
|
||||||
void createOutgoingConnection(ContactId c, TransportIndex i,
|
void createOutgoingConnection(ContactId c, TransportIndex i,
|
||||||
BatchTransportWriter w);
|
BatchTransportWriter w);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ public interface ConnectionReaderFactory {
|
|||||||
* initiator's side of a stream-mode connection.
|
* initiator's side of a stream-mode connection.
|
||||||
*/
|
*/
|
||||||
ConnectionReader createConnectionReader(InputStream in,
|
ConnectionReader createConnectionReader(InputStream in,
|
||||||
ConnectionContext ctx, byte[] encryptedIv);
|
ConnectionContext ctx, byte[] tag);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a connection reader for the responder's side of a stream-mode
|
* Creates a connection reader for the responder's side of a stream-mode
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ public interface ConnectionRecogniser {
|
|||||||
* Asynchronously calls one of the callback's connectionAccepted(),
|
* Asynchronously calls one of the callback's connectionAccepted(),
|
||||||
* connectionRejected() or handleException() methods.
|
* connectionRejected() or handleException() methods.
|
||||||
*/
|
*/
|
||||||
void acceptConnection(TransportId t, byte[] encryptedIv,
|
void acceptConnection(TransportId t, byte[] tag, Callback c);
|
||||||
Callback c);
|
|
||||||
|
|
||||||
interface Callback {
|
interface Callback {
|
||||||
|
|
||||||
|
|||||||
@@ -16,5 +16,5 @@ public interface ConnectionWriterFactory {
|
|||||||
* connection.
|
* connection.
|
||||||
*/
|
*/
|
||||||
ConnectionWriter createConnectionWriter(OutputStream out, long capacity,
|
ConnectionWriter createConnectionWriter(OutputStream out, long capacity,
|
||||||
ConnectionContext ctx, byte[] encryptedIv);
|
ConnectionContext ctx, byte[] tag);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import net.sf.briar.api.protocol.TransportIndex;
|
|||||||
public interface StreamConnectionFactory {
|
public interface StreamConnectionFactory {
|
||||||
|
|
||||||
void createIncomingConnection(ConnectionContext ctx,
|
void createIncomingConnection(ConnectionContext ctx,
|
||||||
StreamTransportConnection s, byte[] encryptedIv);
|
StreamTransportConnection s, byte[] tag);
|
||||||
|
|
||||||
void createOutgoingConnection(ContactId c, TransportIndex i,
|
void createOutgoingConnection(ContactId c, TransportIndex i,
|
||||||
StreamTransportConnection s);
|
StreamTransportConnection s);
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ public interface TransportConstants {
|
|||||||
static final int MAX_FRAME_LENGTH = 65536; // 2^16, 64 KiB
|
static final int MAX_FRAME_LENGTH = 65536; // 2^16, 64 KiB
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The length in bytes of the encrypted IV that uniquely identifies a
|
* The length in bytes of the pseudo-random tag that uniquely identifies a
|
||||||
* connection.
|
* connection.
|
||||||
*/
|
*/
|
||||||
static final int IV_LENGTH = 16;
|
static final int TAG_LENGTH = 16;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The minimum connection length in bytes that all transport plugins must
|
* The minimum connection length in bytes that all transport plugins must
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
private static final String FRAME_CIPHER_ALGO = "AES/CTR/NoPadding";
|
private static final String FRAME_CIPHER_ALGO = "AES/CTR/NoPadding";
|
||||||
private static final String SECRET_KEY_ALGO = "AES";
|
private static final String SECRET_KEY_ALGO = "AES";
|
||||||
private static final int SECRET_KEY_BYTES = 32; // 256 bits
|
private static final int SECRET_KEY_BYTES = 32; // 256 bits
|
||||||
private static final String IV_CIPHER_ALGO = "AES/ECB/NoPadding";
|
private static final String TAG_CIPHER_ALGO = "AES/ECB/NoPadding";
|
||||||
private static final String MAC_ALGO = "HMacSHA256";
|
private static final String MAC_ALGO = "HMacSHA256";
|
||||||
private static final String SIGNATURE_ALGO = "ECDSA";
|
private static final String SIGNATURE_ALGO = "ECDSA";
|
||||||
private static final String KEY_DERIVATION_ALGO = "AES/CTR/NoPadding";
|
private static final String KEY_DERIVATION_ALGO = "AES/CTR/NoPadding";
|
||||||
@@ -38,7 +38,7 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
|
|
||||||
// Labels for key derivation, null-terminated
|
// Labels for key derivation, null-terminated
|
||||||
private static final byte[] FRAME = { 'F', 'R', 'A', 'M', 'E', 0 };
|
private static final byte[] FRAME = { 'F', 'R', 'A', 'M', 'E', 0 };
|
||||||
private static final byte[] IV = { 'I', 'V', 0 };
|
private static final byte[] TAG = { 'T', 'A', 'G', 0 };
|
||||||
private static final byte[] MAC = { 'M', 'A', 'C', 0 };
|
private static final byte[] MAC = { 'M', 'A', 'C', 0 };
|
||||||
private static final byte[] NEXT = { 'N', 'E', 'X', 'T', 0 };
|
private static final byte[] NEXT = { 'N', 'E', 'X', 'T', 0 };
|
||||||
// Context strings for key derivation
|
// Context strings for key derivation
|
||||||
@@ -71,9 +71,9 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
else return deriveKey(secret, FRAME, RESPONDER);
|
else return deriveKey(secret, FRAME, RESPONDER);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ErasableKey deriveIvKey(byte[] secret, boolean initiator) {
|
public ErasableKey deriveTagKey(byte[] secret, boolean initiator) {
|
||||||
if(initiator) return deriveKey(secret, IV, INITIATOR);
|
if(initiator) return deriveKey(secret, TAG, INITIATOR);
|
||||||
else return deriveKey(secret, IV, RESPONDER);
|
else return deriveKey(secret, TAG, RESPONDER);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ErasableKey deriveMacKey(byte[] secret, boolean initiator) {
|
public ErasableKey deriveMacKey(byte[] secret, boolean initiator) {
|
||||||
@@ -143,14 +143,6 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Cipher getIvCipher() {
|
|
||||||
try {
|
|
||||||
return Cipher.getInstance(IV_CIPHER_ALGO, PROVIDER);
|
|
||||||
} catch(GeneralSecurityException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public KeyParser getKeyParser() {
|
public KeyParser getKeyParser() {
|
||||||
return keyParser;
|
return keyParser;
|
||||||
}
|
}
|
||||||
@@ -183,4 +175,12 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Cipher getTagCipher() {
|
||||||
|
try {
|
||||||
|
return Cipher.getInstance(TAG_CIPHER_ALGO, PROVIDER);
|
||||||
|
} catch(GeneralSecurityException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package net.sf.briar.transport;
|
package net.sf.briar.transport;
|
||||||
|
|
||||||
import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
|
import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
||||||
|
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
@@ -31,11 +31,11 @@ implements ConnectionDecrypter {
|
|||||||
ConnectionDecrypterImpl(InputStream in, byte[] iv, Cipher frameCipher,
|
ConnectionDecrypterImpl(InputStream in, byte[] iv, Cipher frameCipher,
|
||||||
ErasableKey frameKey) {
|
ErasableKey frameKey) {
|
||||||
super(in);
|
super(in);
|
||||||
if(iv.length != IV_LENGTH) throw new IllegalArgumentException();
|
if(iv.length != TAG_LENGTH) throw new IllegalArgumentException();
|
||||||
this.iv = iv;
|
this.iv = iv;
|
||||||
this.frameCipher = frameCipher;
|
this.frameCipher = frameCipher;
|
||||||
this.frameKey = frameKey;
|
this.frameKey = frameKey;
|
||||||
buf = new byte[IV_LENGTH];
|
buf = new byte[TAG_LENGTH];
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputStream getInputStream() {
|
public InputStream getInputStream() {
|
||||||
|
|||||||
@@ -41,20 +41,20 @@ class ConnectionDispatcherImpl implements ConnectionDispatcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void dispatchReader(TransportId t, final BatchTransportReader r) {
|
public void dispatchReader(TransportId t, final BatchTransportReader r) {
|
||||||
// Read the encrypted IV
|
// Read the tag
|
||||||
final byte[] encryptedIv;
|
final byte[] tag;
|
||||||
try {
|
try {
|
||||||
encryptedIv = readIv(r.getInputStream());
|
tag = readTag(r.getInputStream());
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
|
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
|
||||||
r.dispose(false);
|
r.dispose(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Get the connection context asynchronously
|
// Get the connection context asynchronously
|
||||||
recogniser.acceptConnection(t, encryptedIv, new Callback() {
|
recogniser.acceptConnection(t, tag, new Callback() {
|
||||||
|
|
||||||
public void connectionAccepted(ConnectionContext ctx) {
|
public void connectionAccepted(ConnectionContext ctx) {
|
||||||
batchConnFactory.createIncomingConnection(ctx, r, encryptedIv);
|
batchConnFactory.createIncomingConnection(ctx, r, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void connectionRejected() {
|
public void connectionRejected() {
|
||||||
@@ -68,8 +68,8 @@ class ConnectionDispatcherImpl implements ConnectionDispatcher {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] readIv(InputStream in) throws IOException {
|
private byte[] readTag(InputStream in) throws IOException {
|
||||||
byte[] b = new byte[TransportConstants.IV_LENGTH];
|
byte[] b = new byte[TransportConstants.TAG_LENGTH];
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
while(offset < b.length) {
|
while(offset < b.length) {
|
||||||
int read = in.read(b, offset, b.length - offset);
|
int read = in.read(b, offset, b.length - offset);
|
||||||
@@ -86,20 +86,20 @@ class ConnectionDispatcherImpl implements ConnectionDispatcher {
|
|||||||
|
|
||||||
public void dispatchIncomingConnection(TransportId t,
|
public void dispatchIncomingConnection(TransportId t,
|
||||||
final StreamTransportConnection s) {
|
final StreamTransportConnection s) {
|
||||||
// Read the encrypted IV
|
// Read the tag
|
||||||
final byte[] encryptedIv;
|
final byte[] tag;
|
||||||
try {
|
try {
|
||||||
encryptedIv = readIv(s.getInputStream());
|
tag = readTag(s.getInputStream());
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
|
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
|
||||||
s.dispose(false);
|
s.dispose(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Get the connection context asynchronously
|
// Get the connection context asynchronously
|
||||||
recogniser.acceptConnection(t, encryptedIv, new Callback() {
|
recogniser.acceptConnection(t, tag, new Callback() {
|
||||||
|
|
||||||
public void connectionAccepted(ConnectionContext ctx) {
|
public void connectionAccepted(ConnectionContext ctx) {
|
||||||
streamConnFactory.createIncomingConnection(ctx, s, encryptedIv);
|
streamConnFactory.createIncomingConnection(ctx, s, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void connectionRejected() {
|
public void connectionRejected() {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package net.sf.briar.transport;
|
package net.sf.briar.transport;
|
||||||
|
|
||||||
import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
|
import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
||||||
|
|
||||||
import java.io.FilterOutputStream;
|
import java.io.FilterOutputStream;
|
||||||
@@ -20,23 +20,23 @@ implements ConnectionEncrypter {
|
|||||||
|
|
||||||
private final Cipher frameCipher;
|
private final Cipher frameCipher;
|
||||||
private final ErasableKey frameKey;
|
private final ErasableKey frameKey;
|
||||||
private final byte[] iv, encryptedIv;
|
private final byte[] iv, tag;
|
||||||
|
|
||||||
private long capacity, frame = 0L;
|
private long capacity, frame = 0L;
|
||||||
private boolean ivWritten = false, betweenFrames = false;
|
private boolean tagWritten = false, betweenFrames = false;
|
||||||
|
|
||||||
ConnectionEncrypterImpl(OutputStream out, long capacity, byte[] iv,
|
ConnectionEncrypterImpl(OutputStream out, long capacity, byte[] iv,
|
||||||
Cipher ivCipher, Cipher frameCipher, ErasableKey ivKey,
|
Cipher tagCipher, Cipher frameCipher, ErasableKey tagKey,
|
||||||
ErasableKey frameKey) {
|
ErasableKey frameKey) {
|
||||||
super(out);
|
super(out);
|
||||||
this.capacity = capacity;
|
this.capacity = capacity;
|
||||||
this.iv = iv;
|
this.iv = iv;
|
||||||
this.frameCipher = frameCipher;
|
this.frameCipher = frameCipher;
|
||||||
this.frameKey = frameKey;
|
this.frameKey = frameKey;
|
||||||
// Encrypt the IV
|
// Encrypt the tag
|
||||||
try {
|
try {
|
||||||
ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
|
tagCipher.init(Cipher.ENCRYPT_MODE, tagKey);
|
||||||
encryptedIv = ivCipher.doFinal(iv);
|
tag = tagCipher.doFinal(iv);
|
||||||
} catch(BadPaddingException badCipher) {
|
} catch(BadPaddingException badCipher) {
|
||||||
throw new IllegalArgumentException(badCipher);
|
throw new IllegalArgumentException(badCipher);
|
||||||
} catch(IllegalBlockSizeException badCipher) {
|
} catch(IllegalBlockSizeException badCipher) {
|
||||||
@@ -44,9 +44,8 @@ implements ConnectionEncrypter {
|
|||||||
} catch(InvalidKeyException badKey) {
|
} catch(InvalidKeyException badKey) {
|
||||||
throw new IllegalArgumentException(badKey);
|
throw new IllegalArgumentException(badKey);
|
||||||
}
|
}
|
||||||
if(encryptedIv.length != IV_LENGTH)
|
if(tag.length != TAG_LENGTH) throw new IllegalArgumentException();
|
||||||
throw new IllegalArgumentException();
|
tagKey.erase();
|
||||||
ivKey.erase();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public OutputStream getOutputStream() {
|
public OutputStream getOutputStream() {
|
||||||
@@ -55,7 +54,7 @@ implements ConnectionEncrypter {
|
|||||||
|
|
||||||
public void writeMac(byte[] mac) throws IOException {
|
public void writeMac(byte[] mac) throws IOException {
|
||||||
try {
|
try {
|
||||||
if(!ivWritten || betweenFrames) throw new IllegalStateException();
|
if(!tagWritten || betweenFrames) throw new IllegalStateException();
|
||||||
try {
|
try {
|
||||||
out.write(frameCipher.doFinal(mac));
|
out.write(frameCipher.doFinal(mac));
|
||||||
} catch(BadPaddingException badCipher) {
|
} catch(BadPaddingException badCipher) {
|
||||||
@@ -78,7 +77,7 @@ implements ConnectionEncrypter {
|
|||||||
@Override
|
@Override
|
||||||
public void write(int b) throws IOException {
|
public void write(int b) throws IOException {
|
||||||
try {
|
try {
|
||||||
if(!ivWritten) writeIv();
|
if(!tagWritten) writeTag();
|
||||||
if(betweenFrames) initialiseCipher();
|
if(betweenFrames) initialiseCipher();
|
||||||
byte[] ciphertext = frameCipher.update(new byte[] {(byte) b});
|
byte[] ciphertext = frameCipher.update(new byte[] {(byte) b});
|
||||||
if(ciphertext != null) out.write(ciphertext);
|
if(ciphertext != null) out.write(ciphertext);
|
||||||
@@ -97,7 +96,7 @@ implements ConnectionEncrypter {
|
|||||||
@Override
|
@Override
|
||||||
public void write(byte[] b, int off, int len) throws IOException {
|
public void write(byte[] b, int off, int len) throws IOException {
|
||||||
try {
|
try {
|
||||||
if(!ivWritten) writeIv();
|
if(!tagWritten) writeTag();
|
||||||
if(betweenFrames) initialiseCipher();
|
if(betweenFrames) initialiseCipher();
|
||||||
byte[] ciphertext = frameCipher.update(b, off, len);
|
byte[] ciphertext = frameCipher.update(b, off, len);
|
||||||
if(ciphertext != null) out.write(ciphertext);
|
if(ciphertext != null) out.write(ciphertext);
|
||||||
@@ -108,17 +107,17 @@ implements ConnectionEncrypter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeIv() throws IOException {
|
private void writeTag() throws IOException {
|
||||||
assert !ivWritten;
|
assert !tagWritten;
|
||||||
assert !betweenFrames;
|
assert !betweenFrames;
|
||||||
out.write(encryptedIv);
|
out.write(tag);
|
||||||
capacity -= encryptedIv.length;
|
capacity -= tag.length;
|
||||||
ivWritten = true;
|
tagWritten = true;
|
||||||
betweenFrames = true;
|
betweenFrames = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initialiseCipher() {
|
private void initialiseCipher() {
|
||||||
assert ivWritten;
|
assert tagWritten;
|
||||||
assert betweenFrames;
|
assert betweenFrames;
|
||||||
if(frame > MAX_32_BIT_UNSIGNED) throw new IllegalStateException();
|
if(frame > MAX_32_BIT_UNSIGNED) throw new IllegalStateException();
|
||||||
IvEncoder.updateIv(iv, frame);
|
IvEncoder.updateIv(iv, frame);
|
||||||
|
|||||||
@@ -27,14 +27,14 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ConnectionReader createConnectionReader(InputStream in,
|
public ConnectionReader createConnectionReader(InputStream in,
|
||||||
ConnectionContext ctx, byte[] encryptedIv) {
|
ConnectionContext ctx, byte[] tag) {
|
||||||
// Decrypt the IV
|
// Decrypt the tag
|
||||||
Cipher ivCipher = crypto.getIvCipher();
|
Cipher tagCipher = crypto.getTagCipher();
|
||||||
ErasableKey ivKey = crypto.deriveIvKey(ctx.getSecret(), true);
|
ErasableKey tagKey = crypto.deriveTagKey(ctx.getSecret(), true);
|
||||||
byte[] iv;
|
byte[] iv;
|
||||||
try {
|
try {
|
||||||
ivCipher.init(Cipher.DECRYPT_MODE, ivKey);
|
tagCipher.init(Cipher.DECRYPT_MODE, tagKey);
|
||||||
iv = ivCipher.doFinal(encryptedIv);
|
iv = tagCipher.doFinal(tag);
|
||||||
} catch(BadPaddingException badCipher) {
|
} catch(BadPaddingException badCipher) {
|
||||||
throw new IllegalArgumentException(badCipher);
|
throw new IllegalArgumentException(badCipher);
|
||||||
} catch(IllegalBlockSizeException badCipher) {
|
} catch(IllegalBlockSizeException badCipher) {
|
||||||
@@ -42,8 +42,8 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory {
|
|||||||
} catch(InvalidKeyException badKey) {
|
} catch(InvalidKeyException badKey) {
|
||||||
throw new IllegalArgumentException(badKey);
|
throw new IllegalArgumentException(badKey);
|
||||||
}
|
}
|
||||||
ivKey.erase();
|
tagKey.erase();
|
||||||
// Validate the IV
|
// Validate the tag
|
||||||
int index = ctx.getTransportIndex().getInt();
|
int index = ctx.getTransportIndex().getInt();
|
||||||
long connection = ctx.getConnectionNumber();
|
long connection = ctx.getConnectionNumber();
|
||||||
if(!IvEncoder.validateIv(iv, index, connection))
|
if(!IvEncoder.validateIv(iv, index, connection))
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package net.sf.briar.transport;
|
package net.sf.briar.transport;
|
||||||
|
|
||||||
import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
|
import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
|
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -50,7 +50,7 @@ DatabaseListener {
|
|||||||
private final CryptoComponent crypto;
|
private final CryptoComponent crypto;
|
||||||
private final DatabaseComponent db;
|
private final DatabaseComponent db;
|
||||||
private final Executor executor;
|
private final Executor executor;
|
||||||
private final Cipher ivCipher; // Locking: this
|
private final Cipher tagCipher; // Locking: this
|
||||||
private final Set<TransportId> localTransportIds; // Locking: this
|
private final Set<TransportId> localTransportIds; // Locking: this
|
||||||
private final Map<Bytes, Context> expected; // Locking: this
|
private final Map<Bytes, Context> expected; // Locking: this
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ DatabaseListener {
|
|||||||
this.crypto = crypto;
|
this.crypto = crypto;
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.executor = executor;
|
this.executor = executor;
|
||||||
ivCipher = crypto.getIvCipher();
|
tagCipher = crypto.getTagCipher();
|
||||||
localTransportIds = new HashSet<TransportId>();
|
localTransportIds = new HashSet<TransportId>();
|
||||||
expected = new HashMap<Bytes, Context>();
|
expected = new HashMap<Bytes, Context>();
|
||||||
}
|
}
|
||||||
@@ -87,7 +87,7 @@ DatabaseListener {
|
|||||||
ConnectionWindow w = db.getConnectionWindow(c, i);
|
ConnectionWindow w = db.getConnectionWindow(c, i);
|
||||||
for(Entry<Long, byte[]> e : w.getUnseen().entrySet()) {
|
for(Entry<Long, byte[]> e : w.getUnseen().entrySet()) {
|
||||||
Context ctx = new Context(c, t, i, e.getKey());
|
Context ctx = new Context(c, t, i, e.getKey());
|
||||||
ivs.put(calculateIv(ctx, e.getValue()), ctx);
|
ivs.put(calculateTag(ctx, e.getValue()), ctx);
|
||||||
}
|
}
|
||||||
w.erase();
|
w.erase();
|
||||||
}
|
}
|
||||||
@@ -102,14 +102,14 @@ DatabaseListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Locking: this
|
// Locking: this
|
||||||
private Bytes calculateIv(Context ctx, byte[] secret) {
|
private Bytes calculateTag(Context ctx, byte[] secret) {
|
||||||
byte[] iv = IvEncoder.encodeIv(ctx.transportIndex.getInt(),
|
byte[] iv = IvEncoder.encodeIv(ctx.transportIndex.getInt(),
|
||||||
ctx.connection);
|
ctx.connection);
|
||||||
ErasableKey ivKey = crypto.deriveIvKey(secret, true);
|
ErasableKey tagKey = crypto.deriveTagKey(secret, true);
|
||||||
try {
|
try {
|
||||||
ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
|
tagCipher.init(Cipher.ENCRYPT_MODE, tagKey);
|
||||||
byte[] encryptedIv = ivCipher.doFinal(iv);
|
byte[] tag = tagCipher.doFinal(iv);
|
||||||
return new Bytes(encryptedIv);
|
return new Bytes(tag);
|
||||||
} catch(BadPaddingException badCipher) {
|
} catch(BadPaddingException badCipher) {
|
||||||
throw new RuntimeException(badCipher);
|
throw new RuntimeException(badCipher);
|
||||||
} catch(IllegalBlockSizeException badCipher) {
|
} catch(IllegalBlockSizeException badCipher) {
|
||||||
@@ -117,16 +117,16 @@ DatabaseListener {
|
|||||||
} catch(InvalidKeyException badKey) {
|
} catch(InvalidKeyException badKey) {
|
||||||
throw new RuntimeException(badKey);
|
throw new RuntimeException(badKey);
|
||||||
} finally {
|
} finally {
|
||||||
ivKey.erase();
|
tagKey.erase();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void acceptConnection(final TransportId t, final byte[] encryptedIv,
|
public void acceptConnection(final TransportId t, final byte[] tag,
|
||||||
final Callback callback) {
|
final Callback callback) {
|
||||||
executor.execute(new Runnable() {
|
executor.execute(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
ConnectionContext ctx = acceptConnection(t, encryptedIv);
|
ConnectionContext ctx = acceptConnection(t, tag);
|
||||||
if(ctx == null) callback.connectionRejected();
|
if(ctx == null) callback.connectionRejected();
|
||||||
else callback.connectionAccepted(ctx);
|
else callback.connectionAccepted(ctx);
|
||||||
} catch(DbException e) {
|
} catch(DbException e) {
|
||||||
@@ -137,13 +137,13 @@ DatabaseListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Package access for testing
|
// Package access for testing
|
||||||
ConnectionContext acceptConnection(TransportId t, byte[] encryptedIv)
|
ConnectionContext acceptConnection(TransportId t, byte[] tag)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
if(encryptedIv.length != IV_LENGTH)
|
if(tag.length != TAG_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
if(!initialised) initialise();
|
if(!initialised) initialise();
|
||||||
Bytes b = new Bytes(encryptedIv);
|
Bytes b = new Bytes(tag);
|
||||||
Context ctx = expected.get(b);
|
Context ctx = expected.get(b);
|
||||||
if(ctx == null || !ctx.transportId.equals(t)) return null;
|
if(ctx == null || !ctx.transportId.equals(t)) return null;
|
||||||
// The IV was expected
|
// The IV was expected
|
||||||
@@ -173,7 +173,7 @@ DatabaseListener {
|
|||||||
}
|
}
|
||||||
for(Entry<Long, byte[]> e : w.getUnseen().entrySet()) {
|
for(Entry<Long, byte[]> e : w.getUnseen().entrySet()) {
|
||||||
Context ctx1 = new Context(c, t, i, e.getKey());
|
Context ctx1 = new Context(c, t, i, e.getKey());
|
||||||
expected.put(calculateIv(ctx1, e.getValue()), ctx1);
|
expected.put(calculateTag(ctx1, e.getValue()), ctx1);
|
||||||
}
|
}
|
||||||
w.erase();
|
w.erase();
|
||||||
return new ConnectionContextImpl(c, i, connection, secret);
|
return new ConnectionContextImpl(c, i, connection, secret);
|
||||||
@@ -227,7 +227,7 @@ DatabaseListener {
|
|||||||
ConnectionWindow w = db.getConnectionWindow(c, i);
|
ConnectionWindow w = db.getConnectionWindow(c, i);
|
||||||
for(Entry<Long, byte[]> e : w.getUnseen().entrySet()) {
|
for(Entry<Long, byte[]> e : w.getUnseen().entrySet()) {
|
||||||
Context ctx = new Context(c, t, i, e.getKey());
|
Context ctx = new Context(c, t, i, e.getKey());
|
||||||
ivs.put(calculateIv(ctx, e.getValue()), ctx);
|
ivs.put(calculateTag(ctx, e.getValue()), ctx);
|
||||||
}
|
}
|
||||||
w.erase();
|
w.erase();
|
||||||
} catch(NoSuchContactException e) {
|
} catch(NoSuchContactException e) {
|
||||||
@@ -256,7 +256,7 @@ DatabaseListener {
|
|||||||
ConnectionWindow w = db.getConnectionWindow(c, i);
|
ConnectionWindow w = db.getConnectionWindow(c, i);
|
||||||
for(Entry<Long, byte[]> e : w.getUnseen().entrySet()) {
|
for(Entry<Long, byte[]> e : w.getUnseen().entrySet()) {
|
||||||
Context ctx = new Context(c, t, i, e.getKey());
|
Context ctx = new Context(c, t, i, e.getKey());
|
||||||
ivs.put(calculateIv(ctx, e.getValue()), ctx);
|
ivs.put(calculateTag(ctx, e.getValue()), ctx);
|
||||||
}
|
}
|
||||||
w.erase();
|
w.erase();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,14 +32,14 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ConnectionWriter createConnectionWriter(OutputStream out,
|
public ConnectionWriter createConnectionWriter(OutputStream out,
|
||||||
long capacity, ConnectionContext ctx, byte[] encryptedIv) {
|
long capacity, ConnectionContext ctx, byte[] tag) {
|
||||||
// Decrypt the IV
|
// Decrypt the tag
|
||||||
Cipher ivCipher = crypto.getIvCipher();
|
Cipher tagCipher = crypto.getTagCipher();
|
||||||
ErasableKey ivKey = crypto.deriveIvKey(ctx.getSecret(), true);
|
ErasableKey tagKey = crypto.deriveTagKey(ctx.getSecret(), true);
|
||||||
byte[] iv;
|
byte[] iv;
|
||||||
try {
|
try {
|
||||||
ivCipher.init(Cipher.DECRYPT_MODE, ivKey);
|
tagCipher.init(Cipher.DECRYPT_MODE, tagKey);
|
||||||
iv = ivCipher.doFinal(encryptedIv);
|
iv = tagCipher.doFinal(tag);
|
||||||
} catch(BadPaddingException badCipher) {
|
} catch(BadPaddingException badCipher) {
|
||||||
throw new RuntimeException(badCipher);
|
throw new RuntimeException(badCipher);
|
||||||
} catch(IllegalBlockSizeException badCipher) {
|
} catch(IllegalBlockSizeException badCipher) {
|
||||||
@@ -47,8 +47,8 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory {
|
|||||||
} catch(InvalidKeyException badKey) {
|
} catch(InvalidKeyException badKey) {
|
||||||
throw new RuntimeException(badKey);
|
throw new RuntimeException(badKey);
|
||||||
}
|
}
|
||||||
ivKey.erase();
|
tagKey.erase();
|
||||||
// Validate the IV
|
// Validate the tag
|
||||||
int index = ctx.getTransportIndex().getInt();
|
int index = ctx.getTransportIndex().getInt();
|
||||||
long connection = ctx.getConnectionNumber();
|
long connection = ctx.getConnectionNumber();
|
||||||
if(!IvEncoder.validateIv(iv, index, connection))
|
if(!IvEncoder.validateIv(iv, index, connection))
|
||||||
@@ -60,7 +60,7 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory {
|
|||||||
long capacity, boolean initiator, ConnectionContext ctx) {
|
long capacity, boolean initiator, ConnectionContext ctx) {
|
||||||
// Derive the keys and erase the secret
|
// Derive the keys and erase the secret
|
||||||
byte[] secret = ctx.getSecret();
|
byte[] secret = ctx.getSecret();
|
||||||
ErasableKey ivKey = crypto.deriveIvKey(secret, initiator);
|
ErasableKey tagKey = crypto.deriveTagKey(secret, initiator);
|
||||||
ErasableKey frameKey = crypto.deriveFrameKey(secret, initiator);
|
ErasableKey frameKey = crypto.deriveFrameKey(secret, initiator);
|
||||||
ErasableKey macKey = crypto.deriveMacKey(secret, initiator);
|
ErasableKey macKey = crypto.deriveMacKey(secret, initiator);
|
||||||
ByteUtils.erase(secret);
|
ByteUtils.erase(secret);
|
||||||
@@ -68,10 +68,10 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory {
|
|||||||
int index = ctx.getTransportIndex().getInt();
|
int index = ctx.getTransportIndex().getInt();
|
||||||
long connection = ctx.getConnectionNumber();
|
long connection = ctx.getConnectionNumber();
|
||||||
byte[] iv = IvEncoder.encodeIv(index, connection);
|
byte[] iv = IvEncoder.encodeIv(index, connection);
|
||||||
Cipher ivCipher = crypto.getIvCipher();
|
Cipher tagCipher = crypto.getTagCipher();
|
||||||
Cipher frameCipher = crypto.getFrameCipher();
|
Cipher frameCipher = crypto.getFrameCipher();
|
||||||
ConnectionEncrypter encrypter = new ConnectionEncrypterImpl(out,
|
ConnectionEncrypter encrypter = new ConnectionEncrypterImpl(out,
|
||||||
capacity, iv, ivCipher, frameCipher, ivKey, frameKey);
|
capacity, iv, tagCipher, frameCipher, tagKey, frameKey);
|
||||||
// Create the writer
|
// Create the writer
|
||||||
Mac mac = crypto.getMac();
|
Mac mac = crypto.getMac();
|
||||||
return new ConnectionWriterImpl(encrypter, mac, macKey);
|
return new ConnectionWriterImpl(encrypter, mac, macKey);
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
package net.sf.briar.transport;
|
package net.sf.briar.transport;
|
||||||
|
|
||||||
import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
|
import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
import net.sf.briar.util.ByteUtils;
|
import net.sf.briar.util.ByteUtils;
|
||||||
|
|
||||||
class IvEncoder {
|
class IvEncoder {
|
||||||
|
|
||||||
static byte[] encodeIv(int index, long connection) {
|
static byte[] encodeIv(int index, long connection) {
|
||||||
byte[] iv = new byte[IV_LENGTH];
|
byte[] iv = new byte[TAG_LENGTH];
|
||||||
// Encode the transport index as an unsigned 16-bit integer
|
// Encode the transport index as an unsigned 16-bit integer
|
||||||
ByteUtils.writeUint16(index, iv, 4);
|
ByteUtils.writeUint16(index, iv, 4);
|
||||||
// Encode the connection number as an unsigned 32-bit integer
|
// Encode the connection number as an unsigned 32-bit integer
|
||||||
@@ -15,13 +15,13 @@ class IvEncoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void updateIv(byte[] iv, long frame) {
|
static void updateIv(byte[] iv, long frame) {
|
||||||
if(iv.length != IV_LENGTH) throw new IllegalArgumentException();
|
if(iv.length != TAG_LENGTH) throw new IllegalArgumentException();
|
||||||
// Encode the frame number as an unsigned 32-bit integer
|
// Encode the frame number as an unsigned 32-bit integer
|
||||||
ByteUtils.writeUint32(frame, iv, 10);
|
ByteUtils.writeUint32(frame, iv, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean validateIv(byte[] iv, int index, long connection) {
|
static boolean validateIv(byte[] iv, int index, long connection) {
|
||||||
if(iv.length != IV_LENGTH) return false;
|
if(iv.length != TAG_LENGTH) return false;
|
||||||
// Check that the reserved bits are all zero
|
// Check that the reserved bits are all zero
|
||||||
for(int i = 0; i < 3; i++) if(iv[i] != 0) return false;
|
for(int i = 0; i < 3; i++) if(iv[i] != 0) return false;
|
||||||
for(int i = 10; i < iv.length; i++) if(iv[i] != 0) return false;
|
for(int i = 10; i < iv.length; i++) if(iv[i] != 0) return false;
|
||||||
@@ -34,12 +34,12 @@ class IvEncoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int getTransportIndex(byte[] iv) {
|
static int getTransportIndex(byte[] iv) {
|
||||||
if(iv.length != IV_LENGTH) throw new IllegalArgumentException();
|
if(iv.length != TAG_LENGTH) throw new IllegalArgumentException();
|
||||||
return ByteUtils.readUint16(iv, 4);
|
return ByteUtils.readUint16(iv, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
static long getConnectionNumber(byte[] iv) {
|
static long getConnectionNumber(byte[] iv) {
|
||||||
if(iv.length != IV_LENGTH) throw new IllegalArgumentException();
|
if(iv.length != TAG_LENGTH) throw new IllegalArgumentException();
|
||||||
return ByteUtils.readUint32(iv, 6);
|
return ByteUtils.readUint32(iv, 6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,9 +35,9 @@ class BatchConnectionFactoryImpl implements BatchConnectionFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void createIncomingConnection(ConnectionContext ctx,
|
public void createIncomingConnection(ConnectionContext ctx,
|
||||||
BatchTransportReader r, byte[] encryptedIv) {
|
BatchTransportReader r, byte[] tag) {
|
||||||
final IncomingBatchConnection conn = new IncomingBatchConnection(
|
final IncomingBatchConnection conn = new IncomingBatchConnection(
|
||||||
connReaderFactory, db, protoReaderFactory, ctx, r, encryptedIv);
|
connReaderFactory, db, protoReaderFactory, ctx, r, tag);
|
||||||
Runnable read = new Runnable() {
|
Runnable read = new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
conn.read();
|
conn.read();
|
||||||
|
|||||||
@@ -29,24 +29,23 @@ class IncomingBatchConnection {
|
|||||||
private final ProtocolReaderFactory protoFactory;
|
private final ProtocolReaderFactory protoFactory;
|
||||||
private final ConnectionContext ctx;
|
private final ConnectionContext ctx;
|
||||||
private final BatchTransportReader reader;
|
private final BatchTransportReader reader;
|
||||||
private final byte[] encryptedIv;
|
private final byte[] tag;
|
||||||
|
|
||||||
IncomingBatchConnection(ConnectionReaderFactory connFactory,
|
IncomingBatchConnection(ConnectionReaderFactory connFactory,
|
||||||
DatabaseComponent db, ProtocolReaderFactory protoFactory,
|
DatabaseComponent db, ProtocolReaderFactory protoFactory,
|
||||||
ConnectionContext ctx, BatchTransportReader reader,
|
ConnectionContext ctx, BatchTransportReader reader, byte[] tag) {
|
||||||
byte[] encryptedIv) {
|
|
||||||
this.connFactory = connFactory;
|
this.connFactory = connFactory;
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.protoFactory = protoFactory;
|
this.protoFactory = protoFactory;
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
this.reader = reader;
|
this.reader = reader;
|
||||||
this.encryptedIv = encryptedIv;
|
this.tag = tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
void read() {
|
void read() {
|
||||||
try {
|
try {
|
||||||
ConnectionReader conn = connFactory.createConnectionReader(
|
ConnectionReader conn = connFactory.createConnectionReader(
|
||||||
reader.getInputStream(), ctx, encryptedIv);
|
reader.getInputStream(), ctx, tag);
|
||||||
ProtocolReader proto = protoFactory.createProtocolReader(
|
ProtocolReader proto = protoFactory.createProtocolReader(
|
||||||
conn.getInputStream());
|
conn.getInputStream());
|
||||||
ContactId c = ctx.getContactId();
|
ContactId c = ctx.getContactId();
|
||||||
|
|||||||
@@ -16,31 +16,31 @@ import net.sf.briar.api.transport.StreamTransportConnection;
|
|||||||
class IncomingStreamConnection extends StreamConnection {
|
class IncomingStreamConnection extends StreamConnection {
|
||||||
|
|
||||||
private final ConnectionContext ctx;
|
private final ConnectionContext ctx;
|
||||||
private final byte[] encryptedIv;
|
private final byte[] tag;
|
||||||
|
|
||||||
IncomingStreamConnection(ConnectionReaderFactory connReaderFactory,
|
IncomingStreamConnection(ConnectionReaderFactory connReaderFactory,
|
||||||
ConnectionWriterFactory connWriterFactory, DatabaseComponent db,
|
ConnectionWriterFactory connWriterFactory, DatabaseComponent db,
|
||||||
ProtocolReaderFactory protoReaderFactory,
|
ProtocolReaderFactory protoReaderFactory,
|
||||||
ProtocolWriterFactory protoWriterFactory,
|
ProtocolWriterFactory protoWriterFactory,
|
||||||
ConnectionContext ctx, StreamTransportConnection connection,
|
ConnectionContext ctx, StreamTransportConnection connection,
|
||||||
byte[] encryptedIv) {
|
byte[] tag) {
|
||||||
super(connReaderFactory, connWriterFactory, db, protoReaderFactory,
|
super(connReaderFactory, connWriterFactory, db, protoReaderFactory,
|
||||||
protoWriterFactory, ctx.getContactId(), connection);
|
protoWriterFactory, ctx.getContactId(), connection);
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
this.encryptedIv = encryptedIv;
|
this.tag = tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ConnectionReader createConnectionReader() throws DbException,
|
protected ConnectionReader createConnectionReader() throws DbException,
|
||||||
IOException {
|
IOException {
|
||||||
return connReaderFactory.createConnectionReader(
|
return connReaderFactory.createConnectionReader(
|
||||||
connection.getInputStream(), ctx, encryptedIv);
|
connection.getInputStream(), ctx, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ConnectionWriter createConnectionWriter() throws DbException,
|
protected ConnectionWriter createConnectionWriter() throws DbException,
|
||||||
IOException {
|
IOException {
|
||||||
return connWriterFactory.createConnectionWriter(
|
return connWriterFactory.createConnectionWriter(
|
||||||
connection.getOutputStream(), Long.MAX_VALUE, ctx, encryptedIv);
|
connection.getOutputStream(), Long.MAX_VALUE, ctx, tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,10 +34,10 @@ class StreamConnectionFactoryImpl implements StreamConnectionFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void createIncomingConnection(ConnectionContext ctx,
|
public void createIncomingConnection(ConnectionContext ctx,
|
||||||
StreamTransportConnection s, byte[] encryptedIv) {
|
StreamTransportConnection s, byte[] tag) {
|
||||||
final StreamConnection conn = new IncomingStreamConnection(
|
final StreamConnection conn = new IncomingStreamConnection(
|
||||||
connReaderFactory, connWriterFactory, db, protoReaderFactory,
|
connReaderFactory, connWriterFactory, db, protoReaderFactory,
|
||||||
protoWriterFactory, ctx, s, encryptedIv);
|
protoWriterFactory, ctx, s, tag);
|
||||||
Runnable write = new Runnable() {
|
Runnable write = new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
conn.write();
|
conn.write();
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ import net.sf.briar.api.transport.ConnectionReader;
|
|||||||
import net.sf.briar.api.transport.ConnectionReaderFactory;
|
import net.sf.briar.api.transport.ConnectionReaderFactory;
|
||||||
import net.sf.briar.api.transport.ConnectionWriter;
|
import net.sf.briar.api.transport.ConnectionWriter;
|
||||||
import net.sf.briar.api.transport.ConnectionWriterFactory;
|
import net.sf.briar.api.transport.ConnectionWriterFactory;
|
||||||
|
import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
import net.sf.briar.crypto.CryptoModule;
|
import net.sf.briar.crypto.CryptoModule;
|
||||||
import net.sf.briar.db.DatabaseModule;
|
import net.sf.briar.db.DatabaseModule;
|
||||||
import net.sf.briar.lifecycle.LifecycleModule;
|
import net.sf.briar.lifecycle.LifecycleModule;
|
||||||
@@ -206,13 +207,13 @@ public class ProtocolIntegrationTest extends TestCase {
|
|||||||
|
|
||||||
private void read(byte[] connectionData) throws Exception {
|
private void read(byte[] connectionData) throws Exception {
|
||||||
InputStream in = new ByteArrayInputStream(connectionData);
|
InputStream in = new ByteArrayInputStream(connectionData);
|
||||||
byte[] encryptedIv = new byte[16];
|
byte[] tag = new byte[TAG_LENGTH];
|
||||||
assertEquals(16, in.read(encryptedIv, 0, 16));
|
assertEquals(TAG_LENGTH, in.read(tag, 0, TAG_LENGTH));
|
||||||
ConnectionContext ctx =
|
ConnectionContext ctx =
|
||||||
connectionContextFactory.createConnectionContext(contactId,
|
connectionContextFactory.createConnectionContext(contactId,
|
||||||
transportIndex, connection, Arrays.clone(secret));
|
transportIndex, connection, Arrays.clone(secret));
|
||||||
ConnectionReader r = connectionReaderFactory.createConnectionReader(in,
|
ConnectionReader r = connectionReaderFactory.createConnectionReader(in,
|
||||||
ctx, encryptedIv);
|
ctx, tag);
|
||||||
in = r.getInputStream();
|
in = r.getInputStream();
|
||||||
ProtocolReader protocolReader =
|
ProtocolReader protocolReader =
|
||||||
protocolReaderFactory.createProtocolReader(in);
|
protocolReaderFactory.createProtocolReader(in);
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ public class KeyDerivationTest extends TestCase {
|
|||||||
List<ErasableKey> keys = new ArrayList<ErasableKey>();
|
List<ErasableKey> keys = new ArrayList<ErasableKey>();
|
||||||
keys.add(crypto.deriveFrameKey(secret, true));
|
keys.add(crypto.deriveFrameKey(secret, true));
|
||||||
keys.add(crypto.deriveFrameKey(secret, false));
|
keys.add(crypto.deriveFrameKey(secret, false));
|
||||||
keys.add(crypto.deriveIvKey(secret, true));
|
keys.add(crypto.deriveTagKey(secret, true));
|
||||||
keys.add(crypto.deriveIvKey(secret, false));
|
keys.add(crypto.deriveTagKey(secret, false));
|
||||||
keys.add(crypto.deriveMacKey(secret, true));
|
keys.add(crypto.deriveMacKey(secret, true));
|
||||||
keys.add(crypto.deriveMacKey(secret, false));
|
keys.add(crypto.deriveMacKey(secret, false));
|
||||||
for(int i = 0; i < 6; i++) {
|
for(int i = 0; i < 6; i++) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package net.sf.briar.transport;
|
package net.sf.briar.transport;
|
||||||
|
|
||||||
import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
|
import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
@@ -25,8 +25,8 @@ public class ConnectionDecrypterImplTest extends TestCase {
|
|||||||
|
|
||||||
private static final int MAC_LENGTH = 32;
|
private static final int MAC_LENGTH = 32;
|
||||||
|
|
||||||
private final Cipher ivCipher, frameCipher;
|
private final Cipher tagCipher, frameCipher;
|
||||||
private final ErasableKey ivKey, frameKey;
|
private final ErasableKey tagKey, frameKey;
|
||||||
private final TransportIndex transportIndex = new TransportIndex(13);
|
private final TransportIndex transportIndex = new TransportIndex(13);
|
||||||
private final long connection = 12345L;
|
private final long connection = 12345L;
|
||||||
|
|
||||||
@@ -34,9 +34,9 @@ public class ConnectionDecrypterImplTest extends TestCase {
|
|||||||
super();
|
super();
|
||||||
Injector i = Guice.createInjector(new CryptoModule());
|
Injector i = Guice.createInjector(new CryptoModule());
|
||||||
CryptoComponent crypto = i.getInstance(CryptoComponent.class);
|
CryptoComponent crypto = i.getInstance(CryptoComponent.class);
|
||||||
ivCipher = crypto.getIvCipher();
|
tagCipher = crypto.getTagCipher();
|
||||||
frameCipher = crypto.getFrameCipher();
|
frameCipher = crypto.getFrameCipher();
|
||||||
ivKey = crypto.generateTestKey();
|
tagKey = crypto.generateTestKey();
|
||||||
frameKey = crypto.generateTestKey();
|
frameKey = crypto.generateTestKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,9 +53,9 @@ public class ConnectionDecrypterImplTest extends TestCase {
|
|||||||
private void testDecryption(boolean initiator) throws Exception {
|
private void testDecryption(boolean initiator) throws Exception {
|
||||||
// Calculate the plaintext and ciphertext for the IV
|
// Calculate the plaintext and ciphertext for the IV
|
||||||
byte[] iv = IvEncoder.encodeIv(transportIndex.getInt(), connection);
|
byte[] iv = IvEncoder.encodeIv(transportIndex.getInt(), connection);
|
||||||
ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
|
tagCipher.init(Cipher.ENCRYPT_MODE, tagKey);
|
||||||
byte[] encryptedIv = ivCipher.doFinal(iv);
|
byte[] tag = tagCipher.doFinal(iv);
|
||||||
assertEquals(IV_LENGTH, encryptedIv.length);
|
assertEquals(TAG_LENGTH, tag.length);
|
||||||
// Calculate the expected plaintext for the first frame
|
// Calculate the expected plaintext for the first frame
|
||||||
byte[] ciphertext = new byte[123];
|
byte[] ciphertext = new byte[123];
|
||||||
byte[] ciphertextMac = new byte[MAC_LENGTH];
|
byte[] ciphertextMac = new byte[MAC_LENGTH];
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package net.sf.briar.transport;
|
package net.sf.briar.transport;
|
||||||
|
|
||||||
import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
|
import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
@@ -23,8 +23,8 @@ public class ConnectionEncrypterImplTest extends TestCase {
|
|||||||
|
|
||||||
private static final int MAC_LENGTH = 32;
|
private static final int MAC_LENGTH = 32;
|
||||||
|
|
||||||
private final Cipher ivCipher, frameCipher;
|
private final Cipher tagCipher, frameCipher;
|
||||||
private final ErasableKey ivKey, frameKey;
|
private final ErasableKey tagKey, frameKey;
|
||||||
private final TransportIndex transportIndex = new TransportIndex(13);
|
private final TransportIndex transportIndex = new TransportIndex(13);
|
||||||
private final long connection = 12345L;
|
private final long connection = 12345L;
|
||||||
|
|
||||||
@@ -32,9 +32,9 @@ public class ConnectionEncrypterImplTest extends TestCase {
|
|||||||
super();
|
super();
|
||||||
Injector i = Guice.createInjector(new CryptoModule());
|
Injector i = Guice.createInjector(new CryptoModule());
|
||||||
CryptoComponent crypto = i.getInstance(CryptoComponent.class);
|
CryptoComponent crypto = i.getInstance(CryptoComponent.class);
|
||||||
ivCipher = crypto.getIvCipher();
|
tagCipher = crypto.getTagCipher();
|
||||||
frameCipher = crypto.getFrameCipher();
|
frameCipher = crypto.getFrameCipher();
|
||||||
ivKey = crypto.generateTestKey();
|
tagKey = crypto.generateTestKey();
|
||||||
frameKey = crypto.generateTestKey();
|
frameKey = crypto.generateTestKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,9 +51,9 @@ public class ConnectionEncrypterImplTest extends TestCase {
|
|||||||
private void testEncryption(boolean initiator) throws Exception {
|
private void testEncryption(boolean initiator) throws Exception {
|
||||||
// Calculate the expected ciphertext for the IV
|
// Calculate the expected ciphertext for the IV
|
||||||
byte[] iv = IvEncoder.encodeIv(transportIndex.getInt(), connection);
|
byte[] iv = IvEncoder.encodeIv(transportIndex.getInt(), connection);
|
||||||
ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
|
tagCipher.init(Cipher.ENCRYPT_MODE, tagKey);
|
||||||
byte[] encryptedIv = ivCipher.doFinal(iv);
|
byte[] tag = tagCipher.doFinal(iv);
|
||||||
assertEquals(IV_LENGTH, encryptedIv.length);
|
assertEquals(TAG_LENGTH, tag.length);
|
||||||
// Calculate the expected ciphertext for the first frame
|
// Calculate the expected ciphertext for the first frame
|
||||||
byte[] plaintext = new byte[123];
|
byte[] plaintext = new byte[123];
|
||||||
byte[] plaintextMac = new byte[MAC_LENGTH];
|
byte[] plaintextMac = new byte[MAC_LENGTH];
|
||||||
@@ -76,7 +76,7 @@ public class ConnectionEncrypterImplTest extends TestCase {
|
|||||||
offset);
|
offset);
|
||||||
// Concatenate the ciphertexts
|
// Concatenate the ciphertexts
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
out.write(encryptedIv);
|
out.write(tag);
|
||||||
out.write(ciphertext);
|
out.write(ciphertext);
|
||||||
out.write(ciphertext1);
|
out.write(ciphertext1);
|
||||||
byte[] expected = out.toByteArray();
|
byte[] expected = out.toByteArray();
|
||||||
@@ -84,7 +84,7 @@ public class ConnectionEncrypterImplTest extends TestCase {
|
|||||||
out.reset();
|
out.reset();
|
||||||
iv = IvEncoder.encodeIv(transportIndex.getInt(), connection);
|
iv = IvEncoder.encodeIv(transportIndex.getInt(), connection);
|
||||||
ConnectionEncrypter e = new ConnectionEncrypterImpl(out, Long.MAX_VALUE,
|
ConnectionEncrypter e = new ConnectionEncrypterImpl(out, Long.MAX_VALUE,
|
||||||
iv, ivCipher, frameCipher, ivKey, frameKey);
|
iv, tagCipher, frameCipher, tagKey, frameKey);
|
||||||
e.getOutputStream().write(plaintext);
|
e.getOutputStream().write(plaintext);
|
||||||
e.writeMac(plaintextMac);
|
e.writeMac(plaintextMac);
|
||||||
e.getOutputStream().write(plaintext1);
|
e.getOutputStream().write(plaintext1);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package net.sf.briar.transport;
|
package net.sf.briar.transport;
|
||||||
|
|
||||||
import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
|
import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -83,7 +83,7 @@ public class ConnectionRecogniserImplTest extends TestCase {
|
|||||||
Executor executor = new ImmediateExecutor();
|
Executor executor = new ImmediateExecutor();
|
||||||
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
||||||
executor);
|
executor);
|
||||||
assertNull(c.acceptConnection(transportId, new byte[IV_LENGTH]));
|
assertNull(c.acceptConnection(transportId, new byte[TAG_LENGTH]));
|
||||||
context.assertIsSatisfied();
|
context.assertIsSatisfied();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,18 +111,18 @@ public class ConnectionRecogniserImplTest extends TestCase {
|
|||||||
Executor executor = new ImmediateExecutor();
|
Executor executor = new ImmediateExecutor();
|
||||||
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
||||||
executor);
|
executor);
|
||||||
byte[] encryptedIv = calculateIv();
|
byte[] tag = calculateTag();
|
||||||
// The IV should not be expected by the wrong transport
|
// The tag should not be expected by the wrong transport
|
||||||
TransportId wrong = new TransportId(TestUtils.getRandomId());
|
TransportId wrong = new TransportId(TestUtils.getRandomId());
|
||||||
assertNull(c.acceptConnection(wrong, encryptedIv));
|
assertNull(c.acceptConnection(wrong, tag));
|
||||||
// The IV should be expected by the right transport
|
// The tag should be expected by the right transport
|
||||||
ConnectionContext ctx = c.acceptConnection(transportId, encryptedIv);
|
ConnectionContext ctx = c.acceptConnection(transportId, tag);
|
||||||
assertNotNull(ctx);
|
assertNotNull(ctx);
|
||||||
assertEquals(contactId, ctx.getContactId());
|
assertEquals(contactId, ctx.getContactId());
|
||||||
assertEquals(remoteIndex, ctx.getTransportIndex());
|
assertEquals(remoteIndex, ctx.getTransportIndex());
|
||||||
assertEquals(3, ctx.getConnectionNumber());
|
assertEquals(3, ctx.getConnectionNumber());
|
||||||
// The IV should no longer be expected
|
// The tag should no longer be expected
|
||||||
assertNull(c.acceptConnection(transportId, encryptedIv));
|
assertNull(c.acceptConnection(transportId, tag));
|
||||||
// The window should have advanced
|
// The window should have advanced
|
||||||
Map<Long, byte[]> unseen = window.getUnseen();
|
Map<Long, byte[]> unseen = window.getUnseen();
|
||||||
assertEquals(19, unseen.size());
|
assertEquals(19, unseen.size());
|
||||||
@@ -152,15 +152,15 @@ public class ConnectionRecogniserImplTest extends TestCase {
|
|||||||
Executor executor = new ImmediateExecutor();
|
Executor executor = new ImmediateExecutor();
|
||||||
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
||||||
executor);
|
executor);
|
||||||
byte[] encryptedIv = calculateIv();
|
byte[] tag = calculateTag();
|
||||||
// Ensure the recogniser is initialised
|
// Ensure the recogniser is initialised
|
||||||
assertFalse(c.isInitialised());
|
assertFalse(c.isInitialised());
|
||||||
assertNull(c.acceptConnection(transportId, new byte[IV_LENGTH]));
|
assertNull(c.acceptConnection(transportId, new byte[TAG_LENGTH]));
|
||||||
assertTrue(c.isInitialised());
|
assertTrue(c.isInitialised());
|
||||||
// Remove the contact
|
// Remove the contact
|
||||||
c.eventOccurred(new ContactRemovedEvent(contactId));
|
c.eventOccurred(new ContactRemovedEvent(contactId));
|
||||||
// The IV should not be expected
|
// The tag should not be expected
|
||||||
assertNull(c.acceptConnection(transportId, encryptedIv));
|
assertNull(c.acceptConnection(transportId, tag));
|
||||||
context.assertIsSatisfied();
|
context.assertIsSatisfied();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,12 +179,12 @@ public class ConnectionRecogniserImplTest extends TestCase {
|
|||||||
Executor executor = new ImmediateExecutor();
|
Executor executor = new ImmediateExecutor();
|
||||||
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
||||||
executor);
|
executor);
|
||||||
byte[] encryptedIv = calculateIv();
|
byte[] tag = calculateTag();
|
||||||
// Remove the contact
|
// Remove the contact
|
||||||
c.eventOccurred(new ContactRemovedEvent(contactId));
|
c.eventOccurred(new ContactRemovedEvent(contactId));
|
||||||
// The IV should not be expected
|
// The tag should not be expected
|
||||||
assertFalse(c.isInitialised());
|
assertFalse(c.isInitialised());
|
||||||
assertNull(c.acceptConnection(transportId, encryptedIv));
|
assertNull(c.acceptConnection(transportId, tag));
|
||||||
assertTrue(c.isInitialised());
|
assertTrue(c.isInitialised());
|
||||||
context.assertIsSatisfied();
|
context.assertIsSatisfied();
|
||||||
}
|
}
|
||||||
@@ -216,21 +216,21 @@ public class ConnectionRecogniserImplTest extends TestCase {
|
|||||||
Executor executor = new ImmediateExecutor();
|
Executor executor = new ImmediateExecutor();
|
||||||
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
||||||
executor);
|
executor);
|
||||||
byte[] encryptedIv = calculateIv();
|
byte[] tag = calculateTag();
|
||||||
// The IV should not be expected
|
// The tag should not be expected
|
||||||
assertFalse(c.isInitialised());
|
assertFalse(c.isInitialised());
|
||||||
assertNull(c.acceptConnection(transportId, encryptedIv));
|
assertNull(c.acceptConnection(transportId, tag));
|
||||||
assertTrue(c.isInitialised());
|
assertTrue(c.isInitialised());
|
||||||
// Add the transport
|
// Add the transport
|
||||||
c.eventOccurred(new TransportAddedEvent(transportId));
|
c.eventOccurred(new TransportAddedEvent(transportId));
|
||||||
// The IV should be expected
|
// The tag should be expected
|
||||||
ConnectionContext ctx = c.acceptConnection(transportId, encryptedIv);
|
ConnectionContext ctx = c.acceptConnection(transportId, tag);
|
||||||
assertNotNull(ctx);
|
assertNotNull(ctx);
|
||||||
assertEquals(contactId, ctx.getContactId());
|
assertEquals(contactId, ctx.getContactId());
|
||||||
assertEquals(remoteIndex, ctx.getTransportIndex());
|
assertEquals(remoteIndex, ctx.getTransportIndex());
|
||||||
assertEquals(3, ctx.getConnectionNumber());
|
assertEquals(3, ctx.getConnectionNumber());
|
||||||
// The IV should no longer be expected
|
// The tag should no longer be expected
|
||||||
assertNull(c.acceptConnection(transportId, encryptedIv));
|
assertNull(c.acceptConnection(transportId, tag));
|
||||||
// The window should have advanced
|
// The window should have advanced
|
||||||
Map<Long, byte[]> unseen = window.getUnseen();
|
Map<Long, byte[]> unseen = window.getUnseen();
|
||||||
assertEquals(19, unseen.size());
|
assertEquals(19, unseen.size());
|
||||||
@@ -264,19 +264,19 @@ public class ConnectionRecogniserImplTest extends TestCase {
|
|||||||
Executor executor = new ImmediateExecutor();
|
Executor executor = new ImmediateExecutor();
|
||||||
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
||||||
executor);
|
executor);
|
||||||
byte[] encryptedIv = calculateIv();
|
byte[] tag = calculateTag();
|
||||||
// Add the transport
|
// Add the transport
|
||||||
c.eventOccurred(new TransportAddedEvent(transportId));
|
c.eventOccurred(new TransportAddedEvent(transportId));
|
||||||
// The IV should be expected
|
// The tag should be expected
|
||||||
assertFalse(c.isInitialised());
|
assertFalse(c.isInitialised());
|
||||||
ConnectionContext ctx = c.acceptConnection(transportId, encryptedIv);
|
ConnectionContext ctx = c.acceptConnection(transportId, tag);
|
||||||
assertTrue(c.isInitialised());
|
assertTrue(c.isInitialised());
|
||||||
assertNotNull(ctx);
|
assertNotNull(ctx);
|
||||||
assertEquals(contactId, ctx.getContactId());
|
assertEquals(contactId, ctx.getContactId());
|
||||||
assertEquals(remoteIndex, ctx.getTransportIndex());
|
assertEquals(remoteIndex, ctx.getTransportIndex());
|
||||||
assertEquals(3, ctx.getConnectionNumber());
|
assertEquals(3, ctx.getConnectionNumber());
|
||||||
// The IV should no longer be expected
|
// The tag should no longer be expected
|
||||||
assertNull(c.acceptConnection(transportId, encryptedIv));
|
assertNull(c.acceptConnection(transportId, tag));
|
||||||
// The window should have advanced
|
// The window should have advanced
|
||||||
Map<Long, byte[]> unseen = window.getUnseen();
|
Map<Long, byte[]> unseen = window.getUnseen();
|
||||||
assertEquals(19, unseen.size());
|
assertEquals(19, unseen.size());
|
||||||
@@ -311,22 +311,22 @@ public class ConnectionRecogniserImplTest extends TestCase {
|
|||||||
Executor executor = new ImmediateExecutor();
|
Executor executor = new ImmediateExecutor();
|
||||||
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
||||||
executor);
|
executor);
|
||||||
byte[] encryptedIv = calculateIv();
|
byte[] tag = calculateTag();
|
||||||
// The IV should not be expected
|
// The tag should not be expected
|
||||||
assertFalse(c.isInitialised());
|
assertFalse(c.isInitialised());
|
||||||
assertNull(c.acceptConnection(transportId, encryptedIv));
|
assertNull(c.acceptConnection(transportId, tag));
|
||||||
assertTrue(c.isInitialised());
|
assertTrue(c.isInitialised());
|
||||||
// Update the contact
|
// Update the contact
|
||||||
c.eventOccurred(new RemoteTransportsUpdatedEvent(contactId,
|
c.eventOccurred(new RemoteTransportsUpdatedEvent(contactId,
|
||||||
remoteTransports));
|
remoteTransports));
|
||||||
// The IV should be expected
|
// The tag should be expected
|
||||||
ConnectionContext ctx = c.acceptConnection(transportId, encryptedIv);
|
ConnectionContext ctx = c.acceptConnection(transportId, tag);
|
||||||
assertNotNull(ctx);
|
assertNotNull(ctx);
|
||||||
assertEquals(contactId, ctx.getContactId());
|
assertEquals(contactId, ctx.getContactId());
|
||||||
assertEquals(remoteIndex, ctx.getTransportIndex());
|
assertEquals(remoteIndex, ctx.getTransportIndex());
|
||||||
assertEquals(3, ctx.getConnectionNumber());
|
assertEquals(3, ctx.getConnectionNumber());
|
||||||
// The IV should no longer be expected
|
// The tag should no longer be expected
|
||||||
assertNull(c.acceptConnection(transportId, encryptedIv));
|
assertNull(c.acceptConnection(transportId, tag));
|
||||||
// The window should have advanced
|
// The window should have advanced
|
||||||
Map<Long, byte[]> unseen = window.getUnseen();
|
Map<Long, byte[]> unseen = window.getUnseen();
|
||||||
assertEquals(19, unseen.size());
|
assertEquals(19, unseen.size());
|
||||||
@@ -360,20 +360,20 @@ public class ConnectionRecogniserImplTest extends TestCase {
|
|||||||
Executor executor = new ImmediateExecutor();
|
Executor executor = new ImmediateExecutor();
|
||||||
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
||||||
executor);
|
executor);
|
||||||
byte[] encryptedIv = calculateIv();
|
byte[] tag = calculateTag();
|
||||||
// Update the contact
|
// Update the contact
|
||||||
c.eventOccurred(new RemoteTransportsUpdatedEvent(contactId,
|
c.eventOccurred(new RemoteTransportsUpdatedEvent(contactId,
|
||||||
remoteTransports));
|
remoteTransports));
|
||||||
// The IV should be expected
|
// The tag should be expected
|
||||||
assertFalse(c.isInitialised());
|
assertFalse(c.isInitialised());
|
||||||
ConnectionContext ctx = c.acceptConnection(transportId, encryptedIv);
|
ConnectionContext ctx = c.acceptConnection(transportId, tag);
|
||||||
assertTrue(c.isInitialised());
|
assertTrue(c.isInitialised());
|
||||||
assertNotNull(ctx);
|
assertNotNull(ctx);
|
||||||
assertEquals(contactId, ctx.getContactId());
|
assertEquals(contactId, ctx.getContactId());
|
||||||
assertEquals(remoteIndex, ctx.getTransportIndex());
|
assertEquals(remoteIndex, ctx.getTransportIndex());
|
||||||
assertEquals(3, ctx.getConnectionNumber());
|
assertEquals(3, ctx.getConnectionNumber());
|
||||||
// The IV should no longer be expected
|
// The tag should no longer be expected
|
||||||
assertNull(c.acceptConnection(transportId, encryptedIv));
|
assertNull(c.acceptConnection(transportId, tag));
|
||||||
// The window should have advanced
|
// The window should have advanced
|
||||||
Map<Long, byte[]> unseen = window.getUnseen();
|
Map<Long, byte[]> unseen = window.getUnseen();
|
||||||
assertEquals(19, unseen.size());
|
assertEquals(19, unseen.size());
|
||||||
@@ -403,16 +403,16 @@ public class ConnectionRecogniserImplTest extends TestCase {
|
|||||||
Executor executor = new ImmediateExecutor();
|
Executor executor = new ImmediateExecutor();
|
||||||
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
||||||
executor);
|
executor);
|
||||||
byte[] encryptedIv = calculateIv();
|
byte[] tag = calculateTag();
|
||||||
// Ensure the recogniser is initialised
|
// Ensure the recogniser is initialised
|
||||||
assertFalse(c.isInitialised());
|
assertFalse(c.isInitialised());
|
||||||
assertNull(c.acceptConnection(transportId, new byte[IV_LENGTH]));
|
assertNull(c.acceptConnection(transportId, new byte[TAG_LENGTH]));
|
||||||
assertTrue(c.isInitialised());
|
assertTrue(c.isInitialised());
|
||||||
// Update the contact
|
// Update the contact
|
||||||
c.eventOccurred(new RemoteTransportsUpdatedEvent(contactId,
|
c.eventOccurred(new RemoteTransportsUpdatedEvent(contactId,
|
||||||
Collections.<Transport>emptyList()));
|
Collections.<Transport>emptyList()));
|
||||||
// The IV should not be expected
|
// The tag should not be expected
|
||||||
assertNull(c.acceptConnection(transportId, encryptedIv));
|
assertNull(c.acceptConnection(transportId, tag));
|
||||||
context.assertIsSatisfied();
|
context.assertIsSatisfied();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -433,13 +433,13 @@ public class ConnectionRecogniserImplTest extends TestCase {
|
|||||||
Executor executor = new ImmediateExecutor();
|
Executor executor = new ImmediateExecutor();
|
||||||
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
||||||
executor);
|
executor);
|
||||||
byte[] encryptedIv = calculateIv();
|
byte[] tag = calculateTag();
|
||||||
// Update the contact
|
// Update the contact
|
||||||
c.eventOccurred(new RemoteTransportsUpdatedEvent(contactId,
|
c.eventOccurred(new RemoteTransportsUpdatedEvent(contactId,
|
||||||
Collections.<Transport>emptyList()));
|
Collections.<Transport>emptyList()));
|
||||||
// The IV should not be expected
|
// The tag should not be expected
|
||||||
assertFalse(c.isInitialised());
|
assertFalse(c.isInitialised());
|
||||||
assertNull(c.acceptConnection(transportId, encryptedIv));
|
assertNull(c.acceptConnection(transportId, tag));
|
||||||
assertTrue(c.isInitialised());
|
assertTrue(c.isInitialised());
|
||||||
context.assertIsSatisfied();
|
context.assertIsSatisfied();
|
||||||
}
|
}
|
||||||
@@ -499,24 +499,24 @@ public class ConnectionRecogniserImplTest extends TestCase {
|
|||||||
Executor executor = new ImmediateExecutor();
|
Executor executor = new ImmediateExecutor();
|
||||||
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
||||||
executor);
|
executor);
|
||||||
byte[] encryptedIv = calculateIv();
|
byte[] tag = calculateTag();
|
||||||
// Ensure the recogniser is initialised
|
// Ensure the recogniser is initialised
|
||||||
assertFalse(c.isInitialised());
|
assertFalse(c.isInitialised());
|
||||||
assertNull(c.acceptConnection(transportId, new byte[IV_LENGTH]));
|
assertNull(c.acceptConnection(transportId, new byte[TAG_LENGTH]));
|
||||||
assertTrue(c.isInitialised());
|
assertTrue(c.isInitialised());
|
||||||
// Update the contact
|
// Update the contact
|
||||||
c.eventOccurred(new RemoteTransportsUpdatedEvent(contactId,
|
c.eventOccurred(new RemoteTransportsUpdatedEvent(contactId,
|
||||||
remoteTransports1));
|
remoteTransports1));
|
||||||
// The IV should not be expected by the old transport
|
// The tag should not be expected by the old transport
|
||||||
assertNull(c.acceptConnection(transportId, encryptedIv));
|
assertNull(c.acceptConnection(transportId, tag));
|
||||||
// The IV should be expected by the new transport
|
// The tag should be expected by the new transport
|
||||||
ConnectionContext ctx = c.acceptConnection(transportId1, encryptedIv);
|
ConnectionContext ctx = c.acceptConnection(transportId1, tag);
|
||||||
assertNotNull(ctx);
|
assertNotNull(ctx);
|
||||||
assertEquals(contactId, ctx.getContactId());
|
assertEquals(contactId, ctx.getContactId());
|
||||||
assertEquals(remoteIndex, ctx.getTransportIndex());
|
assertEquals(remoteIndex, ctx.getTransportIndex());
|
||||||
assertEquals(3, ctx.getConnectionNumber());
|
assertEquals(3, ctx.getConnectionNumber());
|
||||||
// The IV should no longer be expected
|
// The tag should no longer be expected
|
||||||
assertNull(c.acceptConnection(transportId1, encryptedIv));
|
assertNull(c.acceptConnection(transportId1, tag));
|
||||||
// The window should have advanced
|
// The window should have advanced
|
||||||
Map<Long, byte[]> unseen = window.getUnseen();
|
Map<Long, byte[]> unseen = window.getUnseen();
|
||||||
assertEquals(19, unseen.size());
|
assertEquals(19, unseen.size());
|
||||||
@@ -576,22 +576,22 @@ public class ConnectionRecogniserImplTest extends TestCase {
|
|||||||
Executor executor = new ImmediateExecutor();
|
Executor executor = new ImmediateExecutor();
|
||||||
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
||||||
executor);
|
executor);
|
||||||
byte[] encryptedIv = calculateIv();
|
byte[] tag = calculateTag();
|
||||||
// Update the contact
|
// Update the contact
|
||||||
c.eventOccurred(new RemoteTransportsUpdatedEvent(contactId,
|
c.eventOccurred(new RemoteTransportsUpdatedEvent(contactId,
|
||||||
remoteTransports1));
|
remoteTransports1));
|
||||||
// The IV should not be expected by the old transport
|
// The tag should not be expected by the old transport
|
||||||
assertFalse(c.isInitialised());
|
assertFalse(c.isInitialised());
|
||||||
assertNull(c.acceptConnection(transportId, encryptedIv));
|
assertNull(c.acceptConnection(transportId, tag));
|
||||||
assertTrue(c.isInitialised());
|
assertTrue(c.isInitialised());
|
||||||
// The IV should be expected by the new transport
|
// The tag should be expected by the new transport
|
||||||
ConnectionContext ctx = c.acceptConnection(transportId1, encryptedIv);
|
ConnectionContext ctx = c.acceptConnection(transportId1, tag);
|
||||||
assertNotNull(ctx);
|
assertNotNull(ctx);
|
||||||
assertEquals(contactId, ctx.getContactId());
|
assertEquals(contactId, ctx.getContactId());
|
||||||
assertEquals(remoteIndex, ctx.getTransportIndex());
|
assertEquals(remoteIndex, ctx.getTransportIndex());
|
||||||
assertEquals(3, ctx.getConnectionNumber());
|
assertEquals(3, ctx.getConnectionNumber());
|
||||||
// The IV should no longer be expected
|
// The tag should no longer be expected
|
||||||
assertNull(c.acceptConnection(transportId1, encryptedIv));
|
assertNull(c.acceptConnection(transportId1, tag));
|
||||||
// The window should have advanced
|
// The window should have advanced
|
||||||
Map<Long, byte[]> unseen = window.getUnseen();
|
Map<Long, byte[]> unseen = window.getUnseen();
|
||||||
assertEquals(19, unseen.size());
|
assertEquals(19, unseen.size());
|
||||||
@@ -608,17 +608,17 @@ public class ConnectionRecogniserImplTest extends TestCase {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] calculateIv() throws Exception {
|
private byte[] calculateTag() throws Exception {
|
||||||
// Calculate the shared secret for connection number 3
|
// Calculate the shared secret for connection number 3
|
||||||
byte[] secret = inSecret;
|
byte[] secret = inSecret;
|
||||||
for(int i = 0; i < 4; i++) {
|
for(int i = 0; i < 4; i++) {
|
||||||
secret = crypto.deriveNextSecret(secret, remoteIndex.getInt(), i);
|
secret = crypto.deriveNextSecret(secret, remoteIndex.getInt(), i);
|
||||||
}
|
}
|
||||||
// Calculate the expected IV for connection number 3
|
// Calculate the expected tag for connection number 3
|
||||||
ErasableKey ivKey = crypto.deriveIvKey(secret, true);
|
ErasableKey tagKey = crypto.deriveTagKey(secret, true);
|
||||||
Cipher ivCipher = crypto.getIvCipher();
|
Cipher tagCipher = crypto.getTagCipher();
|
||||||
ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
|
tagCipher.init(Cipher.ENCRYPT_MODE, tagKey);
|
||||||
byte[] iv = IvEncoder.encodeIv(remoteIndex.getInt(), 3);
|
byte[] iv = IvEncoder.encodeIv(remoteIndex.getInt(), 3);
|
||||||
return ivCipher.doFinal(iv);
|
return tagCipher.doFinal(iv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package net.sf.briar.transport;
|
package net.sf.briar.transport;
|
||||||
|
|
||||||
import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
|
import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
@@ -28,10 +28,10 @@ import com.google.inject.Injector;
|
|||||||
public class FrameReadWriteTest extends TestCase {
|
public class FrameReadWriteTest extends TestCase {
|
||||||
|
|
||||||
private final CryptoComponent crypto;
|
private final CryptoComponent crypto;
|
||||||
private final Cipher ivCipher, frameCipher;
|
private final Cipher tagCipher, frameCipher;
|
||||||
private final Random random;
|
private final Random random;
|
||||||
private final byte[] outSecret;
|
private final byte[] outSecret;
|
||||||
private final ErasableKey ivKey, frameKey, macKey;
|
private final ErasableKey tagKey, frameKey, macKey;
|
||||||
private final Mac mac;
|
private final Mac mac;
|
||||||
private final TransportIndex transportIndex = new TransportIndex(13);
|
private final TransportIndex transportIndex = new TransportIndex(13);
|
||||||
private final long connection = 12345L;
|
private final long connection = 12345L;
|
||||||
@@ -40,13 +40,13 @@ public class FrameReadWriteTest extends TestCase {
|
|||||||
super();
|
super();
|
||||||
Injector i = Guice.createInjector(new CryptoModule());
|
Injector i = Guice.createInjector(new CryptoModule());
|
||||||
crypto = i.getInstance(CryptoComponent.class);
|
crypto = i.getInstance(CryptoComponent.class);
|
||||||
ivCipher = crypto.getIvCipher();
|
tagCipher = crypto.getTagCipher();
|
||||||
frameCipher = crypto.getFrameCipher();
|
frameCipher = crypto.getFrameCipher();
|
||||||
random = new Random();
|
random = new Random();
|
||||||
// Since we're sending frames to ourselves, we only need outgoing keys
|
// Since we're sending frames to ourselves, we only need outgoing keys
|
||||||
outSecret = new byte[32];
|
outSecret = new byte[32];
|
||||||
random.nextBytes(outSecret);
|
random.nextBytes(outSecret);
|
||||||
ivKey = crypto.deriveIvKey(outSecret, true);
|
tagKey = crypto.deriveTagKey(outSecret, true);
|
||||||
frameKey = crypto.deriveFrameKey(outSecret, true);
|
frameKey = crypto.deriveFrameKey(outSecret, true);
|
||||||
macKey = crypto.deriveMacKey(outSecret, true);
|
macKey = crypto.deriveMacKey(outSecret, true);
|
||||||
mac = crypto.getMac();
|
mac = crypto.getMac();
|
||||||
@@ -65,9 +65,9 @@ public class FrameReadWriteTest extends TestCase {
|
|||||||
private void testWriteAndRead(boolean initiator) throws Exception {
|
private void testWriteAndRead(boolean initiator) throws Exception {
|
||||||
// Create and encrypt the IV
|
// Create and encrypt the IV
|
||||||
byte[] iv = IvEncoder.encodeIv(transportIndex.getInt(), connection);
|
byte[] iv = IvEncoder.encodeIv(transportIndex.getInt(), connection);
|
||||||
ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
|
tagCipher.init(Cipher.ENCRYPT_MODE, tagKey);
|
||||||
byte[] encryptedIv = ivCipher.doFinal(iv);
|
byte[] tag = tagCipher.doFinal(iv);
|
||||||
assertEquals(IV_LENGTH, encryptedIv.length);
|
assertEquals(TAG_LENGTH, tag.length);
|
||||||
// Generate two random frames
|
// Generate two random frames
|
||||||
byte[] frame = new byte[12345];
|
byte[] frame = new byte[12345];
|
||||||
random.nextBytes(frame);
|
random.nextBytes(frame);
|
||||||
@@ -75,12 +75,12 @@ public class FrameReadWriteTest extends TestCase {
|
|||||||
random.nextBytes(frame1);
|
random.nextBytes(frame1);
|
||||||
// Copy the keys - the copies will be erased
|
// Copy the keys - the copies will be erased
|
||||||
ErasableKey frameCopy = frameKey.copy();
|
ErasableKey frameCopy = frameKey.copy();
|
||||||
ErasableKey ivCopy = ivKey.copy();
|
ErasableKey tagCopy = tagKey.copy();
|
||||||
ErasableKey macCopy = macKey.copy();
|
ErasableKey macCopy = macKey.copy();
|
||||||
// Write the frames
|
// Write the frames
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
ConnectionEncrypter encrypter = new ConnectionEncrypterImpl(out,
|
ConnectionEncrypter encrypter = new ConnectionEncrypterImpl(out,
|
||||||
Long.MAX_VALUE, iv, ivCipher, frameCipher, ivCopy, frameCopy);
|
Long.MAX_VALUE, iv, tagCipher, frameCipher, tagCopy, frameCopy);
|
||||||
ConnectionWriter writer = new ConnectionWriterImpl(encrypter, mac,
|
ConnectionWriter writer = new ConnectionWriterImpl(encrypter, mac,
|
||||||
macCopy);
|
macCopy);
|
||||||
OutputStream out1 = writer.getOutputStream();
|
OutputStream out1 = writer.getOutputStream();
|
||||||
@@ -90,12 +90,12 @@ public class FrameReadWriteTest extends TestCase {
|
|||||||
out1.flush();
|
out1.flush();
|
||||||
// Read the IV back
|
// Read the IV back
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
||||||
byte[] recoveredEncryptedIv = new byte[IV_LENGTH];
|
byte[] recoveredTag = new byte[TAG_LENGTH];
|
||||||
assertEquals(IV_LENGTH, in.read(recoveredEncryptedIv));
|
assertEquals(TAG_LENGTH, in.read(recoveredTag));
|
||||||
assertArrayEquals(encryptedIv, recoveredEncryptedIv);
|
assertArrayEquals(tag, recoveredTag);
|
||||||
// Decrypt the IV
|
// Decrypt the IV
|
||||||
ivCipher.init(Cipher.DECRYPT_MODE, ivKey);
|
tagCipher.init(Cipher.DECRYPT_MODE, tagKey);
|
||||||
byte[] recoveredIv = ivCipher.doFinal(recoveredEncryptedIv);
|
byte[] recoveredIv = tagCipher.doFinal(recoveredTag);
|
||||||
iv = IvEncoder.encodeIv(transportIndex.getInt(), connection);
|
iv = IvEncoder.encodeIv(transportIndex.getInt(), connection);
|
||||||
assertArrayEquals(iv, recoveredIv);
|
assertArrayEquals(iv, recoveredIv);
|
||||||
// Read the frames back
|
// Read the frames back
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package net.sf.briar.transport.batch;
|
package net.sf.briar.transport.batch;
|
||||||
|
|
||||||
import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
|
import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
@@ -170,11 +170,11 @@ public class BatchConnectionReadWriteTest extends TestCase {
|
|||||||
// Create a connection recogniser and recognise the connection
|
// Create a connection recogniser and recognise the connection
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(b);
|
ByteArrayInputStream in = new ByteArrayInputStream(b);
|
||||||
ConnectionRecogniser rec = bob.getInstance(ConnectionRecogniser.class);
|
ConnectionRecogniser rec = bob.getInstance(ConnectionRecogniser.class);
|
||||||
byte[] encryptedIv = new byte[IV_LENGTH];
|
byte[] tag = new byte[TAG_LENGTH];
|
||||||
int read = in.read(encryptedIv);
|
int read = in.read(tag);
|
||||||
assertEquals(encryptedIv.length, read);
|
assertEquals(tag.length, read);
|
||||||
TestCallback callback = new TestCallback();
|
TestCallback callback = new TestCallback();
|
||||||
rec.acceptConnection(transportId, encryptedIv, callback);
|
rec.acceptConnection(transportId, tag, callback);
|
||||||
callback.latch.await();
|
callback.latch.await();
|
||||||
ConnectionContext ctx = callback.ctx;
|
ConnectionContext ctx = callback.ctx;
|
||||||
assertNotNull(ctx);
|
assertNotNull(ctx);
|
||||||
@@ -187,7 +187,7 @@ public class BatchConnectionReadWriteTest extends TestCase {
|
|||||||
bob.getInstance(ProtocolReaderFactory.class);
|
bob.getInstance(ProtocolReaderFactory.class);
|
||||||
BatchTransportReader reader = new TestBatchTransportReader(in);
|
BatchTransportReader reader = new TestBatchTransportReader(in);
|
||||||
IncomingBatchConnection batchIn = new IncomingBatchConnection(
|
IncomingBatchConnection batchIn = new IncomingBatchConnection(
|
||||||
connFactory, db, protoFactory, ctx, reader, encryptedIv);
|
connFactory, db, protoFactory, ctx, reader, tag);
|
||||||
// No messages should have been added yet
|
// No messages should have been added yet
|
||||||
assertFalse(listener.messagesAdded);
|
assertFalse(listener.messagesAdded);
|
||||||
// Read whatever needs to be read
|
// Read whatever needs to be read
|
||||||
|
|||||||
Reference in New Issue
Block a user