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