diff --git a/briar-api/src/org/briarproject/api/crypto/AuthenticatedCipher.java b/briar-api/src/org/briarproject/api/crypto/AuthenticatedCipher.java index 6f60ed0526c2fe714cb80c7418ee0d3db95b2b69..8256b31febcf73f4311bc0c5e01bffaf1c7a2738 100644 --- a/briar-api/src/org/briarproject/api/crypto/AuthenticatedCipher.java +++ b/briar-api/src/org/briarproject/api/crypto/AuthenticatedCipher.java @@ -2,14 +2,12 @@ package org.briarproject.api.crypto; import java.security.GeneralSecurityException; -/** An authenticated cipher that supports additional authenticated data. */ public interface AuthenticatedCipher { /** - * Initializes this cipher with a key, an initialisation vector (IV) and - * additional authenticated data (AAD). + * Initializes this cipher with a key and an initialisation vector (IV). */ - void init(boolean encrypt, SecretKey key, byte[] iv, byte[] aad) + void init(boolean encrypt, SecretKey key, byte[] iv) throws GeneralSecurityException; /** Encrypts or decrypts data in a single-part operation. */ @@ -17,8 +15,8 @@ public interface AuthenticatedCipher { int outputOff) throws GeneralSecurityException; /** Returns the length of the message authentication code (MAC) in bytes. */ - int getMacLength(); + int getMacBytes(); /** Returns the block size of the cipher in bytes. */ - int getBlockSize(); + int getBlockBytes(); } diff --git a/briar-core/src/org/briarproject/crypto/AuthenticatedCipherImpl.java b/briar-core/src/org/briarproject/crypto/AuthenticatedCipherImpl.java index d001b60c5441d4f90fbeb074874485c8a4f984e0..d840313846210a7b3085f273fe47851f00202857 100644 --- a/briar-core/src/org/briarproject/crypto/AuthenticatedCipherImpl.java +++ b/briar-core/src/org/briarproject/crypto/AuthenticatedCipherImpl.java @@ -6,18 +6,22 @@ import org.briarproject.api.crypto.AuthenticatedCipher; import org.briarproject.api.crypto.SecretKey; import org.spongycastle.crypto.DataLengthException; import org.spongycastle.crypto.InvalidCipherTextException; +import org.spongycastle.crypto.engines.AESLightEngine; import org.spongycastle.crypto.modes.AEADBlockCipher; +import org.spongycastle.crypto.modes.GCMBlockCipher; +import org.spongycastle.crypto.modes.gcm.BasicGCMMultiplier; import org.spongycastle.crypto.params.AEADParameters; import org.spongycastle.crypto.params.KeyParameter; class AuthenticatedCipherImpl implements AuthenticatedCipher { + private static final int MAC_BYTES = 16; + private final AEADBlockCipher cipher; - private final int macLength; - AuthenticatedCipherImpl(AEADBlockCipher cipher, int macLength) { - this.cipher = cipher; - this.macLength = macLength; + AuthenticatedCipherImpl() { + cipher = new GCMBlockCipher(new AESLightEngine(), + new BasicGCMMultiplier()); } public int process(byte[] input, int inputOff, int len, byte[] output, @@ -36,10 +40,11 @@ class AuthenticatedCipherImpl implements AuthenticatedCipher { } } - public void init(boolean encrypt, SecretKey key, byte[] iv, byte[] aad) + public void init(boolean encrypt, SecretKey key, byte[] iv) throws GeneralSecurityException { KeyParameter k = new KeyParameter(key.getBytes()); - AEADParameters params = new AEADParameters(k, macLength * 8, iv, aad); + // Authenticate the IV by passing it as additional authenticated data + AEADParameters params = new AEADParameters(k, MAC_BYTES * 8, iv, iv); try { cipher.init(encrypt, params); } catch(IllegalArgumentException e) { @@ -47,11 +52,11 @@ class AuthenticatedCipherImpl implements AuthenticatedCipher { } } - public int getMacLength() { - return macLength; + public int getMacBytes() { + return MAC_BYTES; } - public int getBlockSize() { + public int getBlockBytes() { return cipher.getUnderlyingCipher().getBlockSize(); } } diff --git a/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java b/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java index 5612c407769787fd131893587e45798395047aa7..5474bcbec856f3dac9ae532024ee0d974de60f50 100644 --- a/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java +++ b/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java @@ -41,9 +41,6 @@ import org.spongycastle.crypto.engines.AESLightEngine; import org.spongycastle.crypto.generators.ECKeyPairGenerator; import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator; import org.spongycastle.crypto.macs.HMac; -import org.spongycastle.crypto.modes.AEADBlockCipher; -import org.spongycastle.crypto.modes.GCMBlockCipher; -import org.spongycastle.crypto.modes.gcm.BasicGCMMultiplier; import org.spongycastle.crypto.params.ECKeyGenerationParameters; import org.spongycastle.crypto.params.ECPrivateKeyParameters; import org.spongycastle.crypto.params.ECPublicKeyParameters; @@ -57,7 +54,6 @@ class CryptoComponentImpl implements CryptoComponent { private static final int CIPHER_KEY_BYTES = 32; // 256 bits private static final int AGREEMENT_KEY_PAIR_BITS = 384; private static final int SIGNATURE_KEY_PAIR_BITS = 384; - private static final int 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_TARGET_MILLIS = 500; @@ -299,9 +295,7 @@ class CryptoComponentImpl implements CryptoComponent { } private AuthenticatedCipher getAuthenticatedCipher() { - AEADBlockCipher a = new GCMBlockCipher(new AESLightEngine(), - new BasicGCMMultiplier()); - return new AuthenticatedCipherImpl(a, MAC_BYTES); + return new AuthenticatedCipherImpl(); } public void encodeTag(byte[] tag, SecretKey tagKey, long streamNumber) { @@ -318,6 +312,8 @@ class CryptoComponentImpl implements CryptoComponent { } public byte[] encryptWithPassword(byte[] input, String password) { + AuthenticatedCipher cipher = getAuthenticatedCipher(); + int macBytes = cipher.getMacBytes(); // Generate a random salt byte[] salt = new byte[PBKDF_SALT_BYTES]; secureRandom.nextBytes(salt); @@ -329,15 +325,14 @@ class CryptoComponentImpl implements CryptoComponent { byte[] iv = new byte[STORAGE_IV_BYTES]; secureRandom.nextBytes(iv); // The output contains the salt, iterations, IV, ciphertext and MAC - int outputLen = salt.length + 4 + iv.length + input.length + MAC_BYTES; + int outputLen = salt.length + 4 + iv.length + input.length + macBytes; byte[] output = new byte[outputLen]; System.arraycopy(salt, 0, output, 0, salt.length); ByteUtils.writeUint32(iterations, output, salt.length); System.arraycopy(iv, 0, output, salt.length + 4, iv.length); // Initialise the cipher and encrypt the plaintext - AuthenticatedCipher cipher = getAuthenticatedCipher(); try { - cipher.init(true, key, iv, null); + cipher.init(true, key, iv); int outputOff = salt.length + 4 + iv.length; cipher.process(input, 0, input.length, output, outputOff); return output; @@ -347,22 +342,23 @@ class CryptoComponentImpl implements CryptoComponent { } public byte[] decryptWithPassword(byte[] input, String password) { + AuthenticatedCipher cipher = getAuthenticatedCipher(); + int macBytes = cipher.getMacBytes(); // The input contains the salt, iterations, IV, ciphertext and MAC - if(input.length < PBKDF_SALT_BYTES + 4 + STORAGE_IV_BYTES + MAC_BYTES) + if(input.length < PBKDF_SALT_BYTES + 4 + STORAGE_IV_BYTES + macBytes) return null; // Invalid byte[] salt = new byte[PBKDF_SALT_BYTES]; System.arraycopy(input, 0, salt, 0, salt.length); long iterations = ByteUtils.readUint32(input, salt.length); if(iterations < 0 || iterations > Integer.MAX_VALUE) - return null; // Invalid + return null; // Invalid iteration count byte[] iv = new byte[STORAGE_IV_BYTES]; System.arraycopy(input, salt.length + 4, iv, 0, iv.length); // Derive the key from the password SecretKey key = new SecretKey(pbkdf2(password, salt, (int) iterations)); // Initialise the cipher - AuthenticatedCipher cipher = getAuthenticatedCipher(); try { - cipher.init(false, key, iv, null); + cipher.init(false, key, iv); } catch(GeneralSecurityException e) { throw new RuntimeException(e); } @@ -370,7 +366,7 @@ class CryptoComponentImpl implements CryptoComponent { try { int inputOff = salt.length + 4 + iv.length; int inputLen = input.length - inputOff; - byte[] output = new byte[inputLen - MAC_BYTES]; + byte[] output = new byte[inputLen - macBytes]; cipher.process(input, inputOff, inputLen, output, 0); return output; } catch(GeneralSecurityException e) { diff --git a/briar-core/src/org/briarproject/crypto/StreamDecrypterImpl.java b/briar-core/src/org/briarproject/crypto/StreamDecrypterImpl.java index b27b0cf9e44c33b0933f775696690b0aab1e58b6..e950fff2f6ed42978722f30e3e90841310d13175 100644 --- a/briar-core/src/org/briarproject/crypto/StreamDecrypterImpl.java +++ b/briar-core/src/org/briarproject/crypto/StreamDecrypterImpl.java @@ -21,7 +21,7 @@ class StreamDecrypterImpl implements StreamDecrypter { private final InputStream in; private final AuthenticatedCipher frameCipher; private final SecretKey frameKey; - private final byte[] iv, aad, header, ciphertext; + private final byte[] iv, header, ciphertext; private long frameNumber; private boolean finalFrame; @@ -32,7 +32,6 @@ class StreamDecrypterImpl implements StreamDecrypter { this.frameCipher = frameCipher; this.frameKey = frameKey; iv = new byte[IV_LENGTH]; - aad = new byte[IV_LENGTH]; header = new byte[HEADER_LENGTH]; ciphertext = new byte[MAX_FRAME_LENGTH]; frameNumber = 0; @@ -52,9 +51,8 @@ class StreamDecrypterImpl implements StreamDecrypter { } // Decrypt and authenticate the header FrameEncoder.encodeIv(iv, frameNumber, true); - FrameEncoder.encodeIv(aad, frameNumber, true); try { - frameCipher.init(false, frameKey, iv, aad); + frameCipher.init(false, frameKey, iv); int decrypted = frameCipher.process(ciphertext, 0, HEADER_LENGTH, header, 0); if(decrypted != HEADER_LENGTH - MAC_LENGTH) @@ -78,9 +76,8 @@ class StreamDecrypterImpl implements StreamDecrypter { } // Decrypt and authenticate the payload and padding FrameEncoder.encodeIv(iv, frameNumber, false); - FrameEncoder.encodeIv(aad, frameNumber, false); try { - frameCipher.init(false, frameKey, iv, aad); + frameCipher.init(false, frameKey, iv); int decrypted = frameCipher.process(ciphertext, HEADER_LENGTH, payloadLength + paddingLength + MAC_LENGTH, payload, 0); if(decrypted != payloadLength + paddingLength) diff --git a/briar-core/src/org/briarproject/crypto/StreamEncrypterImpl.java b/briar-core/src/org/briarproject/crypto/StreamEncrypterImpl.java index 475c62f59fe8cec9994f8115ca8369b9c2465cbf..ce06b09c410207bb38957647c979d73dee3cdbbd 100644 --- a/briar-core/src/org/briarproject/crypto/StreamEncrypterImpl.java +++ b/briar-core/src/org/briarproject/crypto/StreamEncrypterImpl.java @@ -20,7 +20,7 @@ class StreamEncrypterImpl implements StreamEncrypter { private final OutputStream out; private final AuthenticatedCipher frameCipher; private final SecretKey frameKey; - private final byte[] tag, iv, aad, plaintext, ciphertext; + private final byte[] tag, iv, plaintext, ciphertext; private long frameNumber; private boolean writeTag; @@ -32,7 +32,6 @@ class StreamEncrypterImpl implements StreamEncrypter { this.frameKey = frameKey; this.tag = tag; iv = new byte[IV_LENGTH]; - aad = new byte[IV_LENGTH]; plaintext = new byte[HEADER_LENGTH + MAX_PAYLOAD_LENGTH]; ciphertext = new byte[MAX_FRAME_LENGTH]; frameNumber = 0; @@ -55,9 +54,8 @@ class StreamEncrypterImpl implements StreamEncrypter { paddingLength); // Encrypt and authenticate the header FrameEncoder.encodeIv(iv, frameNumber, true); - FrameEncoder.encodeIv(aad, frameNumber, true); try { - frameCipher.init(true, frameKey, iv, aad); + frameCipher.init(true, frameKey, iv); int encrypted = frameCipher.process(plaintext, 0, HEADER_LENGTH - MAC_LENGTH, ciphertext, 0); if(encrypted != HEADER_LENGTH) throw new RuntimeException(); @@ -70,9 +68,8 @@ class StreamEncrypterImpl implements StreamEncrypter { plaintext[HEADER_LENGTH + payloadLength + i] = 0; // Encrypt and authenticate the payload and padding FrameEncoder.encodeIv(iv, frameNumber, false); - FrameEncoder.encodeIv(aad, frameNumber, false); try { - frameCipher.init(true, frameKey, iv, aad); + frameCipher.init(true, frameKey, iv); int encrypted = frameCipher.process(plaintext, HEADER_LENGTH, payloadLength + paddingLength, ciphertext, HEADER_LENGTH); if(encrypted != payloadLength + paddingLength + MAC_LENGTH) diff --git a/briar-tests/src/org/briarproject/crypto/TestAuthenticatedCipher.java b/briar-tests/src/org/briarproject/crypto/TestAuthenticatedCipher.java index 0271975bd43f5b64368486dbfdb2c5f0d9f0f64e..018db0b6c24c95018fe907d3a854af4341c8944a 100644 --- a/briar-tests/src/org/briarproject/crypto/TestAuthenticatedCipher.java +++ b/briar-tests/src/org/briarproject/crypto/TestAuthenticatedCipher.java @@ -13,7 +13,7 @@ class TestAuthenticatedCipher implements AuthenticatedCipher { private boolean encrypt = false; - public void init(boolean encrypt, SecretKey key, byte[] iv, byte[] aad) + public void init(boolean encrypt, SecretKey key, byte[] iv) throws GeneralSecurityException { this.encrypt = encrypt; } @@ -35,11 +35,11 @@ class TestAuthenticatedCipher implements AuthenticatedCipher { } } - public int getMacLength() { + public int getMacBytes() { return MAC_LENGTH; } - public int getBlockSize() { + public int getBlockBytes() { return BLOCK_BYTES; } }