Replaced further JCE calls with direct instantiation of SC objects.

This commit is contained in:
akwizgran
2013-06-14 12:22:32 +01:00
parent a979cab43a
commit 1808ceaf58
6 changed files with 135 additions and 280 deletions

View File

@@ -5,8 +5,6 @@ import java.security.KeyPair;
import java.security.SecureRandom;
import java.security.Signature;
import javax.crypto.Cipher;
public interface CryptoComponent {
ErasableKey generateSecretKey();
@@ -82,18 +80,11 @@ public interface CryptoComponent {
ErasableKey deriveFrameKey(byte[] secret, long connection, boolean alice,
boolean initiator);
/**
* Returns a cipher for generating the pseudo-random tags that are used to
* recognise connections.
*/
Cipher getTagCipher();
/** Returns a cipher for encrypting and authenticating connections. */
AuthenticatedCipher getFrameCipher();
/** Encodes the pseudo-random tag that is used to recognise a connection. */
void encodeTag(byte[] tag, Cipher tagCipher, ErasableKey tagKey,
long connection);
void encodeTag(byte[] tag, ErasableKey tagKey, long connection);
/**
* Encrypts and authenticates the given plaintext so it can be written to

View File

@@ -15,7 +15,6 @@ import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
@@ -30,10 +29,7 @@ import java.security.spec.EllipticCurve;
import java.util.Arrays;
import java.util.logging.Logger;
import javax.crypto.Cipher;
import javax.crypto.CipherSpi;
import javax.crypto.KeyAgreement;
import javax.crypto.spec.IvParameterSpec;
import net.sf.briar.api.crypto.AuthenticatedCipher;
import net.sf.briar.api.crypto.CryptoComponent;
@@ -43,6 +39,7 @@ import net.sf.briar.api.crypto.MessageDigest;
import net.sf.briar.api.crypto.PseudoRandom;
import net.sf.briar.util.ByteUtils;
import org.spongycastle.crypto.BlockCipher;
import org.spongycastle.crypto.CipherParameters;
import org.spongycastle.crypto.engines.AESFastEngine;
import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator;
@@ -51,7 +48,6 @@ import org.spongycastle.crypto.modes.GCMBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.jcajce.provider.asymmetric.ec.KeyPairGeneratorSpi;
import org.spongycastle.jcajce.provider.digest.SHA384;
import org.spongycastle.jcajce.provider.symmetric.AES;
import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.spongycastle.util.Strings;
@@ -61,21 +57,19 @@ class CryptoComponentImpl implements CryptoComponent {
Logger.getLogger(CryptoComponentImpl.class.getName());
private static final String PROVIDER = "SC"; // Spongy Castle
private static final String SECRET_KEY_ALGO = "AES";
private static final int SECRET_KEY_BYTES = 32; // 256 bits
private static final String CIPHER_ALGO = "AES";
private static final int CIPHER_BLOCK_BYTES = 16; // 128 bits
private static final int CIPHER_KEY_BYTES = 32; // 256 bits
private static final String AGREEMENT_ALGO = "ECDHC";
private static final String AGREEMENT_KEY_PAIR_ALGO = "ECDH";
private static final int AGREEMENT_KEY_PAIR_BITS = 384;
private static final String SIGNATURE_ALGO = "ECDSA";
private static final String SIGNATURE_KEY_PAIR_ALGO = "ECDSA";
private static final int SIGNATURE_KEY_PAIR_BITS = 384;
private static final String TAG_CIPHER_ALGO = "AES/ECB/NoPadding";
private static final int GCM_MAC_BYTES = 16; // 128 bits
private static final int STORAGE_IV_BYTES = 16; // 128 bits
private static final int PBKDF_SALT_BYTES = 16; // 128 bits
private static final int PBKDF_ITERATIONS = 1000;
private static final String KEY_DERIVATION_ALGO = "AES/CTR/NoPadding";
private static final int KEY_DERIVATION_IV_BYTES = 16; // 128 bits
// Labels for secret derivation
private static final byte[] MASTER = { 'M', 'A', 'S', 'T', 'E', 'R', '\0' };
@@ -96,11 +90,8 @@ class CryptoComponentImpl implements CryptoComponent {
{ 'B', '_', 'F', 'R', 'A', 'M', 'E', '_', 'A', '\0' };
private static final byte[] B_FRAME_B =
{ 'B', '_', 'F', 'R', 'A', 'M', 'E', '_', 'B', '\0' };
// Blank plaintext for key derivation
private static final byte[] KEY_DERIVATION_BLANK_PLAINTEXT =
new byte[SECRET_KEY_BYTES];
// Blank secret for argument validation
private static final byte[] BLANK_SECRET = new byte[SECRET_KEY_BYTES];
private static final byte[] BLANK_SECRET = new byte[CIPHER_KEY_BYTES];
// Parameters for NIST elliptic curve P-384 - see "Suite B Implementer's
// Guide to NIST SP 800-56A", section A.2
@@ -137,38 +128,34 @@ class CryptoComponentImpl implements CryptoComponent {
private static final ECParameterSpec P_384_PARAMS =
new ECParameterSpec(P_384_CURVE, P_384_G, P_384_N, P_384_H);
private final Provider provider;
private final KeyParser agreementKeyParser, signatureKeyParser;
private final KeyPairGenerator agreementKeyPairGenerator;
private final KeyPairGenerator signatureKeyPairGenerator;
private final SecureRandom secureRandom;
CryptoComponentImpl() {
provider = new BouncyCastleProvider();
Security.addProvider(provider);
Security.addProvider(new BouncyCastleProvider());
try {
KeyFactory agreementKeyFactory = KeyFactory.getInstance(
AGREEMENT_KEY_PAIR_ALGO, PROVIDER);
if(LOG.isLoggable(INFO)) {
LOG.info("Agreement KeyFactory: "
+ agreementKeyFactory.getClass().getName());
}
agreementKeyParser = new Sec1KeyParser(agreementKeyFactory,
P_384_PARAMS, P_384_Q, AGREEMENT_KEY_PAIR_BITS);
KeyFactory signatureKeyFactory = KeyFactory.getInstance(
SIGNATURE_KEY_PAIR_ALGO, PROVIDER);
if(LOG.isLoggable(INFO)) {
LOG.info("Signature KeyFactory: "
+ signatureKeyFactory.getClass().getName());
}
signatureKeyParser = new Sec1KeyParser(signatureKeyFactory,
P_384_PARAMS, P_384_Q, SIGNATURE_KEY_PAIR_BITS);
agreementKeyPairGenerator = new KeyPairGeneratorSpi.ECDH();
agreementKeyPairGenerator.initialize(AGREEMENT_KEY_PAIR_BITS);
signatureKeyPairGenerator = new KeyPairGeneratorSpi.ECDSA();
signatureKeyPairGenerator.initialize(SIGNATURE_KEY_PAIR_BITS);
if(LOG.isLoggable(INFO)) {
LOG.info("Agreement KeyFactory: "
+ agreementKeyFactory.getClass().getName());
LOG.info("Signature KeyFactory: "
+ signatureKeyFactory.getClass().getName());
LOG.info("Agreement KeyPairGenerator: "
+ agreementKeyPairGenerator.getClass().getName());
LOG.info("Signature KeyPairGenerator: "
+ signatureKeyPairGenerator.getClass().getName());
}
} catch(GeneralSecurityException e) {
throw new RuntimeException(e);
}
@@ -176,9 +163,9 @@ class CryptoComponentImpl implements CryptoComponent {
}
public ErasableKey generateSecretKey() {
byte[] b = new byte[SECRET_KEY_BYTES];
byte[] b = new byte[CIPHER_KEY_BYTES];
secureRandom.nextBytes(b);
return new ErasableKeyImpl(b, SECRET_KEY_ALGO);
return new ErasableKeyImpl(b, CIPHER_ALGO);
}
public MessageDigest getMessageDigest() {
@@ -243,7 +230,7 @@ class CryptoComponentImpl implements CryptoComponent {
}
public int[] deriveConfirmationCodes(byte[] secret) {
if(secret.length != SECRET_KEY_BYTES)
if(secret.length != CIPHER_KEY_BYTES)
throw new IllegalArgumentException();
if(Arrays.equals(secret, BLANK_SECRET))
throw new IllegalArgumentException();
@@ -258,7 +245,7 @@ class CryptoComponentImpl implements CryptoComponent {
}
public byte[][] deriveInvitationNonces(byte[] secret) {
if(secret.length != SECRET_KEY_BYTES)
if(secret.length != CIPHER_KEY_BYTES)
throw new IllegalArgumentException();
if(Arrays.equals(secret, BLANK_SECRET))
throw new IllegalArgumentException();
@@ -305,7 +292,7 @@ class CryptoComponentImpl implements CryptoComponent {
}
public byte[] deriveInitialSecret(byte[] secret, int transportIndex) {
if(secret.length != SECRET_KEY_BYTES)
if(secret.length != CIPHER_KEY_BYTES)
throw new IllegalArgumentException();
if(Arrays.equals(secret, BLANK_SECRET))
throw new IllegalArgumentException();
@@ -314,7 +301,7 @@ class CryptoComponentImpl implements CryptoComponent {
}
public byte[] deriveNextSecret(byte[] secret, long period) {
if(secret.length != SECRET_KEY_BYTES)
if(secret.length != CIPHER_KEY_BYTES)
throw new IllegalArgumentException();
if(Arrays.equals(secret, BLANK_SECRET))
throw new IllegalArgumentException();
@@ -324,7 +311,7 @@ class CryptoComponentImpl implements CryptoComponent {
}
public ErasableKey deriveTagKey(byte[] secret, boolean alice) {
if(secret.length != SECRET_KEY_BYTES)
if(secret.length != CIPHER_KEY_BYTES)
throw new IllegalArgumentException();
if(Arrays.equals(secret, BLANK_SECRET))
throw new IllegalArgumentException();
@@ -334,7 +321,7 @@ class CryptoComponentImpl implements CryptoComponent {
public ErasableKey deriveFrameKey(byte[] secret, long connection,
boolean alice, boolean initiator) {
if(secret.length != SECRET_KEY_BYTES)
if(secret.length != CIPHER_KEY_BYTES)
throw new IllegalArgumentException();
if(Arrays.equals(secret, BLANK_SECRET))
throw new IllegalArgumentException();
@@ -350,16 +337,12 @@ class CryptoComponentImpl implements CryptoComponent {
}
private ErasableKey deriveKey(byte[] secret, byte[] label, long context) {
if(secret.length != SECRET_KEY_BYTES)
if(secret.length != CIPHER_KEY_BYTES)
throw new IllegalArgumentException();
if(Arrays.equals(secret, BLANK_SECRET))
throw new IllegalArgumentException();
byte[] key = counterModeKdf(secret, label, context);
return new ErasableKeyImpl(key, SECRET_KEY_ALGO);
}
public Cipher getTagCipher() {
return new CipherFromSpi(new AES.ECB(), provider, TAG_CIPHER_ALGO);
return new ErasableKeyImpl(key, CIPHER_ALGO);
}
public AuthenticatedCipher getFrameCipher() {
@@ -367,20 +350,15 @@ class CryptoComponentImpl implements CryptoComponent {
return new AuthenticatedCipherImpl(cipher, GCM_MAC_BYTES);
}
public void encodeTag(byte[] tag, Cipher tagCipher, ErasableKey tagKey,
long connection) {
public void encodeTag(byte[] tag, ErasableKey tagKey, long connection) {
if(tag.length < TAG_LENGTH) throw new IllegalArgumentException();
if(connection < 0 || connection > MAX_32_BIT_UNSIGNED)
throw new IllegalArgumentException();
for(int i = 0; i < TAG_LENGTH; i++) tag[i] = 0;
ByteUtils.writeUint32(connection, tag, 0);
try {
tagCipher.init(ENCRYPT_MODE, tagKey);
int encrypted = tagCipher.doFinal(tag, 0, TAG_LENGTH, tag);
if(encrypted != TAG_LENGTH) throw new IllegalArgumentException();
} catch(GeneralSecurityException e) {
throw new IllegalArgumentException(e); // Unsuitable cipher or key
}
BlockCipher cipher = new AESFastEngine();
cipher.init(true, new KeyParameter(tagKey.getEncoded()));
cipher.processBlock(tag, 0, tag, 0);
}
public byte[] encryptWithPassword(byte[] input, char[] password) {
@@ -389,7 +367,7 @@ class CryptoComponentImpl implements CryptoComponent {
secureRandom.nextBytes(salt);
// Derive the key from the password
byte[] keyBytes = pbkdf2(password, salt);
ErasableKey key = new ErasableKeyImpl(keyBytes, SECRET_KEY_ALGO);
ErasableKey key = new ErasableKeyImpl(keyBytes, CIPHER_ALGO);
// Generate a random IV
byte[] iv = new byte[STORAGE_IV_BYTES];
secureRandom.nextBytes(iv);
@@ -424,7 +402,7 @@ class CryptoComponentImpl implements CryptoComponent {
System.arraycopy(input, salt.length, iv, 0, iv.length);
// Derive the key from the password
byte[] keyBytes = pbkdf2(password, salt);
ErasableKey key = new ErasableKeyImpl(keyBytes, SECRET_KEY_ALGO);
ErasableKey key = new ErasableKeyImpl(keyBytes, CIPHER_ALGO);
// Initialise the cipher
AuthenticatedCipher cipher;
try {
@@ -472,7 +450,7 @@ class CryptoComponentImpl implements CryptoComponent {
byte[] initiatorInfo, byte[] responderInfo) {
// The output of the hash function must be long enough to use as a key
MessageDigest messageDigest = getMessageDigest();
if(messageDigest.getDigestLength() < SECRET_KEY_BYTES)
if(messageDigest.getDigestLength() < CIPHER_KEY_BYTES)
throw new RuntimeException();
// All fields are length-prefixed
byte[] length = new byte[1];
@@ -490,7 +468,7 @@ class CryptoComponentImpl implements CryptoComponent {
messageDigest.update(responderInfo);
byte[] hash = messageDigest.digest();
// The secret is the first SECRET_KEY_BYTES bytes of the hash
byte[] output = new byte[SECRET_KEY_BYTES];
byte[] output = new byte[CIPHER_KEY_BYTES];
System.arraycopy(hash, 0, output, 0, output.length);
ByteUtils.erase(hash);
return output;
@@ -499,30 +477,24 @@ class CryptoComponentImpl implements CryptoComponent {
// Key derivation function based on a block cipher in CTR mode - see
// NIST SP 800-108, section 5.1
private byte[] counterModeKdf(byte[] secret, byte[] label, long context) {
if(secret.length != SECRET_KEY_BYTES)
if(secret.length != CIPHER_KEY_BYTES)
throw new IllegalArgumentException();
if(Arrays.equals(secret, BLANK_SECRET))
throw new IllegalArgumentException();
// The label and context must leave a byte free for the counter
if(label.length + 4 >= KEY_DERIVATION_IV_BYTES)
if(label.length + 4 >= CIPHER_BLOCK_BYTES)
throw new IllegalArgumentException();
byte[] ivBytes = new byte[KEY_DERIVATION_IV_BYTES];
System.arraycopy(label, 0, ivBytes, 0, label.length);
ByteUtils.writeUint32(context, ivBytes, label.length);
// Use the secret and the IV to encrypt a blank plaintext
IvParameterSpec iv = new IvParameterSpec(ivBytes);
ErasableKey key = new ErasableKeyImpl(secret, SECRET_KEY_ALGO);
try {
CipherSpi spi = new AES.ECB();
Cipher cipher = new CipherFromSpi(spi, provider,
KEY_DERIVATION_ALGO);
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
byte[] output = cipher.doFinal(KEY_DERIVATION_BLANK_PLAINTEXT);
assert output.length == SECRET_KEY_BYTES;
return output;
} catch(GeneralSecurityException e) {
throw new RuntimeException(e);
byte[] counter = new byte[CIPHER_BLOCK_BYTES];
System.arraycopy(label, 0, counter, 0, label.length);
ByteUtils.writeUint32(context, counter, label.length);
BlockCipher cipher = new AESFastEngine();
cipher.init(true, new KeyParameter(secret));
byte[] output = new byte[CIPHER_KEY_BYTES];
for(int i = 0; i * CIPHER_BLOCK_BYTES < output.length; i++) {
counter[counter.length - 1] = (byte) i;
cipher.processBlock(counter, 0, output, i * CIPHER_BLOCK_BYTES);
}
return output;
}
// Password-based key derivation function - see PKCS#5 v2.1, section 5.2
@@ -532,7 +504,7 @@ class CryptoComponentImpl implements CryptoComponent {
byte[] utf8 = toUtf8ByteArray(password);
PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator();
gen.init(utf8, salt, PBKDF_ITERATIONS);
int keyLengthInBits = SECRET_KEY_BYTES * 8;
int keyLengthInBits = CIPHER_KEY_BYTES * 8;
CipherParameters p = gen.generateDerivedParameters(keyLengthInBits);
ByteUtils.erase(utf8);
return ((KeyParameter) p).getKey();
@@ -551,12 +523,4 @@ class CryptoComponentImpl implements CryptoComponent {
throw new RuntimeException(e);
}
}
private static class CipherFromSpi extends Cipher {
private CipherFromSpi(CipherSpi spi, Provider provider,
String transformation) {
super(spi, provider, transformation);
}
}
}

View File

@@ -4,8 +4,6 @@ import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
import java.io.OutputStream;
import javax.crypto.Cipher;
import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.crypto.ErasableKey;
import net.sf.briar.api.transport.ConnectionContext;
@@ -35,9 +33,8 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory {
FrameWriter encryption;
if(initiator) {
byte[] tag = new byte[TAG_LENGTH];
Cipher tagCipher = crypto.getTagCipher();
ErasableKey tagKey = crypto.deriveTagKey(secret, initiatorIsAlice);
crypto.encodeTag(tag, tagCipher, tagKey, connection);
crypto.encodeTag(tag, tagKey, connection);
tagKey.erase();
encryption = new OutgoingEncryptionLayer(out, capacity,
crypto.getFrameCipher(), frameKey, maxFrameLength, tag);

View File

@@ -7,8 +7,6 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
import net.sf.briar.api.Bytes;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.TransportId;
@@ -43,11 +41,10 @@ class TransportConnectionRecogniser {
TagContext t = tagMap.remove(new Bytes(tag));
if(t == null) return null; // The tag was not expected
// Update the connection window and the expected tags
Cipher cipher = crypto.getTagCipher();
ErasableKey key = crypto.deriveTagKey(t.secret, !t.alice);
for(long connection : t.window.setSeen(t.connection)) {
byte[] tag1 = new byte[TAG_LENGTH];
crypto.encodeTag(tag1, cipher, key, connection);
crypto.encodeTag(tag1, key, connection);
if(connection < t.connection) {
TagContext removed = tagMap.remove(new Bytes(tag1));
assert removed != null;
@@ -75,12 +72,11 @@ class TransportConnectionRecogniser {
long centre = s.getWindowCentre();
byte[] bitmap = s.getWindowBitmap();
// Create the connection window and the expected tags
Cipher cipher = crypto.getTagCipher();
ErasableKey key = crypto.deriveTagKey(secret, !alice);
ConnectionWindow window = new ConnectionWindow(centre, bitmap);
for(long connection : window.getUnseen()) {
byte[] tag = new byte[TAG_LENGTH];
crypto.encodeTag(tag, cipher, key, connection);
crypto.encodeTag(tag, key, connection);
TagContext added = new TagContext(contactId, alice, period,
secret, window, connection);
TagContext duplicate = tagMap.put(new Bytes(tag), added);
@@ -102,11 +98,10 @@ class TransportConnectionRecogniser {
// Locking: this
private void removeSecret(RemovalContext r) {
// Remove the expected tags
Cipher cipher = crypto.getTagCipher();
ErasableKey key = crypto.deriveTagKey(r.secret, !r.alice);
byte[] tag = new byte[TAG_LENGTH];
for(long connection : r.window.getUnseen()) {
crypto.encodeTag(tag, cipher, key, connection);
crypto.encodeTag(tag, key, connection);
TagContext removed = tagMap.remove(new Bytes(tag));
assert removed != null;
}

View File

@@ -7,9 +7,6 @@ import static org.junit.Assert.assertArrayEquals;
import java.util.Arrays;
import java.util.Collections;
import javax.crypto.Cipher;
import javax.crypto.NullCipher;
import net.sf.briar.BriarTestCase;
import net.sf.briar.TestUtils;
import net.sf.briar.api.ContactId;
@@ -45,7 +42,6 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
private final byte[] secret0, secret1, secret2, secret3, secret4;
private final byte[] key0, key1, key2, key3, key4;
private final byte[] initialSecret;
private final Cipher cipher;
public KeyRotationIntegrationTest() {
contactId = new ContactId(234);
@@ -72,7 +68,6 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
for(int i = 0; i < key4.length; i++) key4[i] = 5;
initialSecret = new byte[32];
for(int i = 0; i < initialSecret.length; i++) initialSecret[i] = 123;
cipher = new NullCipher();
}
@Test
@@ -155,39 +150,33 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
will(returnValue(secret2.clone()));
oneOf(db).addSecrets(Arrays.asList(s0, s1, s2));
// The recogniser should derive the tags for period 0
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret0, false);
will(returnValue(k0));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k0), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k0),
with((long) i));
will(new EncodeTagAction());
oneOf(k0).getEncoded();
will(returnValue(key0));
}
oneOf(k0).erase();
// The recogniser should derive the tags for period 1
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret1, false);
will(returnValue(k1));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k1), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1),
with((long) i));
will(new EncodeTagAction());
oneOf(k1).getEncoded();
will(returnValue(key1));
}
oneOf(k1).erase();
// The recogniser should derive the tags for period 2
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret2, false);
will(returnValue(k2));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k2), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
with((long) i));
will(new EncodeTagAction());
oneOf(k2).getEncoded();
will(returnValue(key2));
@@ -195,39 +184,33 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
oneOf(k2).erase();
// stop()
// The recogniser should derive the tags for period 0
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret0, false);
will(returnValue(k0));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k0), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k0),
with((long) i));
will(new EncodeTagAction());
oneOf(k0).getEncoded();
will(returnValue(key0));
}
oneOf(k0).erase();
// The recogniser should derive the tags for period 1
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret1, false);
will(returnValue(k1));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k1), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1),
with((long) i));
will(new EncodeTagAction());
oneOf(k1).getEncoded();
will(returnValue(key1));
}
oneOf(k1).erase();
// The recogniser should derive the tags for period 2
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret2, false);
will(returnValue(k2));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k2), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
with((long) i));
will(new EncodeTagAction());
oneOf(k2).getEncoded();
will(returnValue(key2));
@@ -290,39 +273,33 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
will(returnValue(secret2.clone()));
oneOf(db).addSecrets(Arrays.asList(s0, s1, s2));
// The recogniser should derive the tags for period 0
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret0, false);
will(returnValue(k0));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k0), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k0),
with((long) i));
will(new EncodeTagAction());
oneOf(k0).getEncoded();
will(returnValue(key0));
}
oneOf(k0).erase();
// The recogniser should derive the tags for period 1
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret1, false);
will(returnValue(k1));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k1), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1),
with((long) i));
will(new EncodeTagAction());
oneOf(k1).getEncoded();
will(returnValue(key1));
}
oneOf(k1).erase();
// The recogniser should derive the tags for period 2
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret2, false);
will(returnValue(k2));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k2), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
with((long) i));
will(new EncodeTagAction());
oneOf(k2).getEncoded();
will(returnValue(key2));
@@ -333,39 +310,33 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
will(returnValue(0L));
// stop()
// The recogniser should derive the tags for period 0
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret0, false);
will(returnValue(k0));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k0), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k0),
with((long) i));
will(new EncodeTagAction());
oneOf(k0).getEncoded();
will(returnValue(key0));
}
oneOf(k0).erase();
// The recogniser should derive the tags for period 1
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret1, false);
will(returnValue(k1));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k1), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1),
with((long) i));
will(new EncodeTagAction());
oneOf(k1).getEncoded();
will(returnValue(key1));
}
oneOf(k1).erase();
// The recogniser should derive the tags for period 2
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret2, false);
will(returnValue(k2));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k2), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
with((long) i));
will(new EncodeTagAction());
oneOf(k2).getEncoded();
will(returnValue(key2));
@@ -436,50 +407,42 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
will(returnValue(secret2.clone()));
oneOf(db).addSecrets(Arrays.asList(s0, s1, s2));
// The recogniser should derive the tags for period 0
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret0, false);
will(returnValue(k0));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k0), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k0),
with((long) i));
will(new EncodeTagAction());
oneOf(k0).getEncoded();
will(returnValue(key0));
}
oneOf(k0).erase();
// The recogniser should derive the tags for period 1
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret1, false);
will(returnValue(k1));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k1), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1),
with((long) i));
will(new EncodeTagAction());
oneOf(k1).getEncoded();
will(returnValue(key1));
}
oneOf(k1).erase();
// The recogniser should derive the tags for period 2
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret2, false);
will(returnValue(k2));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k2), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
with((long) i));
will(new EncodeTagAction());
oneOf(k2).getEncoded();
will(returnValue(key2));
}
oneOf(k2).erase();
// acceptConnection()
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret2, false);
will(returnValue(k2));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
oneOf(crypto).encodeTag(with(any(byte[].class)),
with(k2), with(16L));
will(new EncodeTagAction());
oneOf(k2).getEncoded();
@@ -489,39 +452,33 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
oneOf(k2).erase();
// stop()
// The recogniser should derive the tags for period 0
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret0, false);
will(returnValue(k0));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k0), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k0),
with((long) i));
will(new EncodeTagAction());
oneOf(k0).getEncoded();
will(returnValue(key0));
}
oneOf(k0).erase();
// The recogniser should derive the tags for period 1
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret1, false);
will(returnValue(k1));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k1), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1),
with((long) i));
will(new EncodeTagAction());
oneOf(k1).getEncoded();
will(returnValue(key1));
}
oneOf(k1).erase();
// The recogniser should derive the updated tags for period 2
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret2, false);
will(returnValue(k2));
for(int i = 1; i < 17; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k2), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
with((long) i));
will(new EncodeTagAction());
oneOf(k2).getEncoded();
will(returnValue(key2));
@@ -584,39 +541,33 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
oneOf(clock).currentTimeMillis();
will(returnValue(EPOCH));
// The recogniser should derive the tags for period 0
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret0, false);
will(returnValue(k0));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k0), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k0),
with((long) i));
will(new EncodeTagAction());
oneOf(k0).getEncoded();
will(returnValue(key0));
}
oneOf(k0).erase();
// The recogniser should derive the tags for period 1
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret1, false);
will(returnValue(k1));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k1), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1),
with((long) i));
will(new EncodeTagAction());
oneOf(k1).getEncoded();
will(returnValue(key1));
}
oneOf(k1).erase();
// The recogniser should derive the tags for period 2
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret2, false);
will(returnValue(k2));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k2), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
with((long) i));
will(new EncodeTagAction());
oneOf(k2).getEncoded();
will(returnValue(key2));
@@ -627,39 +578,33 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
with(any(long.class)), with(any(long.class)));
// stop()
// The recogniser should remove the tags for period 0
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret0, false);
will(returnValue(k0));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k0), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k0),
with((long) i));
will(new EncodeTagAction());
oneOf(k0).getEncoded();
will(returnValue(key0));
}
oneOf(k0).erase();
// The recogniser should derive the tags for period 1
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret1, false);
will(returnValue(k1));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k1), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1),
with((long) i));
will(new EncodeTagAction());
oneOf(k1).getEncoded();
will(returnValue(key1));
}
oneOf(k1).erase();
// The recogniser should derive the tags for period 2
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret2, false);
will(returnValue(k2));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k2), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
with((long) i));
will(new EncodeTagAction());
oneOf(k2).getEncoded();
will(returnValue(key2));
@@ -720,39 +665,33 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
will(returnValue(secret3.clone()));
oneOf(db).addSecrets(Arrays.asList(s3));
// The recogniser should derive the tags for period 1
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret1, false);
will(returnValue(k1));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k1), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1),
with((long) i));
will(new EncodeTagAction());
oneOf(k1).getEncoded();
will(returnValue(key1));
}
oneOf(k1).erase();
// The recogniser should derive the tags for period 2
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret2, false);
will(returnValue(k2));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k2), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
with((long) i));
will(new EncodeTagAction());
oneOf(k2).getEncoded();
will(returnValue(key2));
}
oneOf(k2).erase();
// The recogniser should derive the tags for period 3
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret3, false);
will(returnValue(k3));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k3), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k3),
with((long) i));
will(new EncodeTagAction());
oneOf(k3).getEncoded();
will(returnValue(key3));
@@ -763,39 +702,33 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
with(any(long.class)), with(any(long.class)));
// stop()
// The recogniser should derive the tags for period 1
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret1, false);
will(returnValue(k1));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k1), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k1),
with((long) i));
will(new EncodeTagAction());
oneOf(k1).getEncoded();
will(returnValue(key1));
}
oneOf(k1).erase();
// The recogniser should derive the tags for period 2
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret2, false);
will(returnValue(k2));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k2), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
with((long) i));
will(new EncodeTagAction());
oneOf(k2).getEncoded();
will(returnValue(key2));
}
oneOf(k2).erase();
// The recogniser should remove the tags for period 3
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret3, false);
will(returnValue(k3));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k3), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k3),
with((long) i));
will(new EncodeTagAction());
oneOf(k3).getEncoded();
will(returnValue(key3));
@@ -858,39 +791,33 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
// The new secrets should be stored
oneOf(db).addSecrets(Arrays.asList(s3, s4));
// The recogniser should derive the tags for period 2
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret2, false);
will(returnValue(k2));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k2), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
with((long) i));
will(new EncodeTagAction());
oneOf(k2).getEncoded();
will(returnValue(key2));
}
oneOf(k2).erase();
// The recogniser should derive the tags for period 3
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret3, false);
will(returnValue(k3));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k3), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k3),
with((long) i));
will(new EncodeTagAction());
oneOf(k3).getEncoded();
will(returnValue(key3));
}
oneOf(k3).erase();
// The recogniser should derive the tags for period 4
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret4, false);
will(returnValue(k4));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k4), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k4),
with((long) i));
will(new EncodeTagAction());
oneOf(k4).getEncoded();
will(returnValue(key4));
@@ -901,39 +828,33 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
with(any(long.class)), with(any(long.class)));
// stop()
// The recogniser should derive the tags for period 2
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret2, false);
will(returnValue(k2));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k2), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k2),
with((long) i));
will(new EncodeTagAction());
oneOf(k2).getEncoded();
will(returnValue(key2));
}
oneOf(k2).erase();
// The recogniser should remove the tags for period 3
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret3, false);
will(returnValue(k3));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k3), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k3),
with((long) i));
will(new EncodeTagAction());
oneOf(k3).getEncoded();
will(returnValue(key3));
}
oneOf(k3).erase();
// The recogniser should derive the tags for period 4
oneOf(crypto).getTagCipher();
will(returnValue(cipher));
oneOf(crypto).deriveTagKey(secret4, false);
will(returnValue(k4));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)), with(cipher),
with(k4), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(k4),
with((long) i));
will(new EncodeTagAction());
oneOf(k4).getEncoded();
will(returnValue(key4));
@@ -964,10 +885,9 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
public Object invoke(Invocation invocation) throws Throwable {
byte[] tag = (byte[]) invocation.getParameter(0);
ErasableKey key = (ErasableKey) invocation.getParameter(2);
long connection = (Long) invocation.getParameter(3);
byte[] rawKey = key.getEncoded();
encodeTag(tag, rawKey, connection);
ErasableKey key = (ErasableKey) invocation.getParameter(1);
long connection = (Long) invocation.getParameter(2);
encodeTag(tag, key.getEncoded(), connection);
return null;
}
}

View File

@@ -5,9 +5,6 @@ import static org.junit.Assert.assertArrayEquals;
import java.util.Random;
import javax.crypto.Cipher;
import javax.crypto.NullCipher;
import net.sf.briar.BriarTestCase;
import net.sf.briar.TestUtils;
import net.sf.briar.api.ContactId;
@@ -31,7 +28,6 @@ public class TransportConnectionRecogniserTest extends BriarTestCase {
private final ContactId contactId = new ContactId(234);
private final TransportId transportId =
new TransportId(TestUtils.getRandomId());
private final Cipher tagCipher = new NullCipher();
@Test
public void testAddAndRemoveSecret() {
@@ -44,24 +40,20 @@ public class TransportConnectionRecogniserTest extends BriarTestCase {
final DatabaseComponent db = context.mock(DatabaseComponent.class);
context.checking(new Expectations() {{
// Add secret
oneOf(crypto).getTagCipher();
will(returnValue(tagCipher));
oneOf(crypto).deriveTagKey(secret, !alice);
will(returnValue(tagKey));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)),
with(tagCipher), with(tagKey), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(tagKey),
with((long) i));
will(new EncodeTagAction());
}
oneOf(tagKey).erase();
// Remove secret
oneOf(crypto).getTagCipher();
will(returnValue(tagCipher));
oneOf(crypto).deriveTagKey(secret, !alice);
will(returnValue(tagKey));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)),
with(tagCipher), with(tagKey), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(tagKey),
with((long) i));
will(new EncodeTagAction());
}
oneOf(tagKey).erase();
@@ -86,24 +78,20 @@ public class TransportConnectionRecogniserTest extends BriarTestCase {
final DatabaseComponent db = context.mock(DatabaseComponent.class);
context.checking(new Expectations() {{
// Add secret
oneOf(crypto).getTagCipher();
will(returnValue(tagCipher));
oneOf(crypto).deriveTagKey(secret, !alice);
will(returnValue(tagKey));
for(int i = 0; i < 16; i++) {
oneOf(crypto).encodeTag(with(any(byte[].class)),
with(tagCipher), with(tagKey), with((long) i));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(tagKey),
with((long) i));
will(new EncodeTagAction());
}
oneOf(tagKey).erase();
// Accept connection 0
oneOf(crypto).getTagCipher();
will(returnValue(tagCipher));
oneOf(crypto).deriveTagKey(secret, !alice);
will(returnValue(tagKey));
// The window should slide to include connection 16
oneOf(crypto).encodeTag(with(any(byte[].class)), with(tagCipher),
with(tagKey), with(16L));
oneOf(crypto).encodeTag(with(any(byte[].class)), with(tagKey),
with(16L));
will(new EncodeTagAction());
// The updated window should be stored
oneOf(db).setConnectionWindow(contactId, transportId, 0, 1,
@@ -136,7 +124,7 @@ public class TransportConnectionRecogniserTest extends BriarTestCase {
public Object invoke(Invocation invocation) throws Throwable {
byte[] tag = (byte[]) invocation.getParameter(0);
long connection = (Long) invocation.getParameter(3);
long connection = (Long) invocation.getParameter(2);
// Encode a fake tag based on the connection number
ByteUtils.writeUint32(connection, tag, 0);
return null;