Remove AAD from AuthenticatedCipher interface.

This commit is contained in:
akwizgran
2015-01-09 13:01:02 +00:00
parent 4e57029d98
commit dc5e37a96d
6 changed files with 39 additions and 46 deletions

View File

@@ -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();
}

View File

@@ -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 final AEADBlockCipher cipher;
private final int macLength;
private static final int MAC_BYTES = 16;
AuthenticatedCipherImpl(AEADBlockCipher cipher, int macLength) {
this.cipher = cipher;
this.macLength = macLength;
private final AEADBlockCipher cipher;
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();
}
}

View File

@@ -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) {

View File

@@ -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)

View File

@@ -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)

View File

@@ -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;
}
}