mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-19 06:09:55 +01:00
Merge branch 'use-xsalsa20-poly1305' into 'master'
Use XSalsa20-Poly1305 instead of AES-GCM for transport encryption and password storage. This patch integrates @str4d's new authenticated cipher implementation. It depends on !18. See merge request !35
This commit is contained in:
@@ -55,12 +55,12 @@ implements InvitationListener {
|
|||||||
private boolean localCompared = false, remoteCompared = false;
|
private boolean localCompared = false, remoteCompared = false;
|
||||||
private boolean localMatched = false, remoteMatched = false;
|
private boolean localMatched = false, remoteMatched = false;
|
||||||
private String contactName = null;
|
private String contactName = null;
|
||||||
private boolean bluetoothWasEnabled = false;
|
|
||||||
|
|
||||||
// Fields that are accessed from background threads must be volatile
|
// Fields that are accessed from background threads must be volatile
|
||||||
@Inject private volatile DatabaseComponent db;
|
@Inject private volatile DatabaseComponent db;
|
||||||
@Inject private volatile IdentityManager identityManager;
|
@Inject private volatile IdentityManager identityManager;
|
||||||
private volatile boolean leaveBluetoothEnabled = true;
|
private volatile boolean bluetoothWasEnabled = false;
|
||||||
|
private volatile boolean leaveBluetoothEnabled = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle state) {
|
public void onCreate(Bundle state) {
|
||||||
@@ -173,7 +173,8 @@ implements InvitationListener {
|
|||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Loading setting took " + duration + " ms");
|
LOG.info("Loading setting took " + duration + " ms");
|
||||||
leaveBluetoothEnabled = c.getBoolean("enable", false);
|
leaveBluetoothEnabled = bluetoothWasEnabled
|
||||||
|
|| c.getBoolean("enable", false);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
@@ -328,7 +329,7 @@ implements InvitationListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void disableBluetooth() {
|
public void disableBluetooth() {
|
||||||
if (!bluetoothWasEnabled && !leaveBluetoothEnabled) {
|
if (!leaveBluetoothEnabled) {
|
||||||
if (LOG.isLoggable(INFO)) LOG.info("Turning off Bluetooth again");
|
if (LOG.isLoggable(INFO)) LOG.info("Turning off Bluetooth again");
|
||||||
|
|
||||||
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public interface TransportConstants {
|
|||||||
+ MAC_LENGTH;
|
+ MAC_LENGTH;
|
||||||
|
|
||||||
/** The length of the frame initalisation vector (IV) in bytes. */
|
/** The length of the frame initalisation vector (IV) in bytes. */
|
||||||
int FRAME_IV_LENGTH = 12;
|
int FRAME_IV_LENGTH = 24;
|
||||||
|
|
||||||
/** The length of the frame header in bytes. */
|
/** The length of the frame header in bytes. */
|
||||||
int FRAME_HEADER_LENGTH = 4 + MAC_LENGTH;
|
int FRAME_HEADER_LENGTH = 4 + MAC_LENGTH;
|
||||||
|
|||||||
@@ -26,14 +26,14 @@ interface AuthenticatedCipher {
|
|||||||
* including the MAC.
|
* including the MAC.
|
||||||
* @param inputOff the offset into the input array where the data to be
|
* @param inputOff the offset into the input array where the data to be
|
||||||
* processed starts.
|
* processed starts.
|
||||||
* @param len the number of bytes to be processed. If decrypting, includes
|
* @param len the length of the input. If decrypting, includes the MAC
|
||||||
* the MAC length.
|
* length.
|
||||||
* @param output the output buffer the processed bytes go into. If
|
* @param output the output byte array. If encrypting, the ciphertext
|
||||||
* encrypting, the ciphertext including the MAC. If
|
* including the MAC. If decrypting, the plaintext.
|
||||||
* decrypting, the plaintext.
|
* @param outputOff the offset into the output byte array where the
|
||||||
* @param outputOff the offset into the output byte array the processed
|
* processed data starts.
|
||||||
* data starts at.
|
* @return the length of the output. If encrypting, includes the MAC
|
||||||
* @return the number of bytes processed.
|
* length.
|
||||||
* @throws GeneralSecurityException on invalid input.
|
* @throws GeneralSecurityException on invalid input.
|
||||||
*/
|
*/
|
||||||
int process(byte[] input, int inputOff, int len, byte[] output,
|
int process(byte[] input, int inputOff, int len, byte[] output,
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
package org.briarproject.crypto;
|
|
||||||
|
|
||||||
import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH;
|
|
||||||
|
|
||||||
import java.security.GeneralSecurityException;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
AuthenticatedCipherImpl() {
|
|
||||||
cipher = new GCMBlockCipher(new AESLightEngine(),
|
|
||||||
new BasicGCMMultiplier());
|
|
||||||
}
|
|
||||||
|
|
||||||
public int process(byte[] input, int inputOff, int len, byte[] output,
|
|
||||||
int outputOff) throws GeneralSecurityException {
|
|
||||||
int processed = 0;
|
|
||||||
if (len != 0) {
|
|
||||||
processed = cipher.processBytes(input, inputOff, len, output,
|
|
||||||
outputOff);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return processed + cipher.doFinal(output, outputOff + processed);
|
|
||||||
} catch (DataLengthException e) {
|
|
||||||
throw new GeneralSecurityException(e.getMessage());
|
|
||||||
} catch (InvalidCipherTextException e) {
|
|
||||||
throw new GeneralSecurityException(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init(boolean encrypt, SecretKey key, byte[] iv)
|
|
||||||
throws GeneralSecurityException {
|
|
||||||
KeyParameter k = new KeyParameter(key.getBytes());
|
|
||||||
// Authenticate the IV by passing it as additional authenticated data
|
|
||||||
AEADParameters params = new AEADParameters(k, MAC_LENGTH * 8, iv, iv);
|
|
||||||
try {
|
|
||||||
cipher.init(encrypt, params);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
throw new GeneralSecurityException(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMacBytes() {
|
|
||||||
return MAC_LENGTH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -55,8 +55,8 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
|
|
||||||
private static final int AGREEMENT_KEY_PAIR_BITS = 256;
|
private static final int AGREEMENT_KEY_PAIR_BITS = 256;
|
||||||
private static final int SIGNATURE_KEY_PAIR_BITS = 256;
|
private static final int SIGNATURE_KEY_PAIR_BITS = 256;
|
||||||
private static final int STORAGE_IV_BYTES = 16; // 128 bits
|
private static final int STORAGE_IV_BYTES = 24; // 196 bits
|
||||||
private static final int PBKDF_SALT_BYTES = 16; // 128 bits
|
private static final int PBKDF_SALT_BYTES = 32; // 256 bits
|
||||||
private static final int PBKDF_TARGET_MILLIS = 500;
|
private static final int PBKDF_TARGET_MILLIS = 500;
|
||||||
private static final int PBKDF_SAMPLES = 30;
|
private static final int PBKDF_SAMPLES = 30;
|
||||||
|
|
||||||
@@ -94,16 +94,16 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
private final KeyParser agreementKeyParser, signatureKeyParser;
|
private final KeyParser agreementKeyParser, signatureKeyParser;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
CryptoComponentImpl(SeedProvider r) {
|
CryptoComponentImpl(SeedProvider seedProvider) {
|
||||||
if (!FortunaSecureRandom.selfTest()) throw new RuntimeException();
|
if (!FortunaSecureRandom.selfTest()) throw new RuntimeException();
|
||||||
SecureRandom secureRandom1 = new SecureRandom();
|
SecureRandom platformSecureRandom = new SecureRandom();
|
||||||
if (LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
String provider = secureRandom1.getProvider().getName();
|
String provider = platformSecureRandom.getProvider().getName();
|
||||||
String algorithm = secureRandom1.getAlgorithm();
|
String algorithm = platformSecureRandom.getAlgorithm();
|
||||||
LOG.info("Default SecureRandom: " + provider + " " + algorithm);
|
LOG.info("Default SecureRandom: " + provider + " " + algorithm);
|
||||||
}
|
}
|
||||||
SecureRandom secureRandom2 = new FortunaSecureRandom(r.getSeed());
|
SecureRandom fortuna = new FortunaSecureRandom(seedProvider.getSeed());
|
||||||
secureRandom = new CombinedSecureRandom(secureRandom1, secureRandom2);
|
secureRandom = new CombinedSecureRandom(platformSecureRandom, fortuna);
|
||||||
ECKeyGenerationParameters params = new ECKeyGenerationParameters(
|
ECKeyGenerationParameters params = new ECKeyGenerationParameters(
|
||||||
PARAMETERS, secureRandom);
|
PARAMETERS, secureRandom);
|
||||||
agreementKeyPairGenerator = new ECKeyPairGenerator();
|
agreementKeyPairGenerator = new ECKeyPairGenerator();
|
||||||
@@ -325,7 +325,7 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public byte[] encryptWithPassword(byte[] input, String password) {
|
public byte[] encryptWithPassword(byte[] input, String password) {
|
||||||
AuthenticatedCipher cipher = new AuthenticatedCipherImpl();
|
AuthenticatedCipher cipher = new XSalsa20Poly1305AuthenticatedCipher();
|
||||||
int macBytes = cipher.getMacBytes();
|
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];
|
||||||
@@ -355,7 +355,7 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public byte[] decryptWithPassword(byte[] input, String password) {
|
public byte[] decryptWithPassword(byte[] input, String password) {
|
||||||
AuthenticatedCipher cipher = new AuthenticatedCipherImpl();
|
AuthenticatedCipher cipher = new XSalsa20Poly1305AuthenticatedCipher();
|
||||||
int macBytes = cipher.getMacBytes();
|
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 + macBytes)
|
if (input.length < PBKDF_SALT_BYTES + 4 + STORAGE_IV_BYTES + macBytes)
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
package org.briarproject.crypto;
|
package org.briarproject.crypto;
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
import com.google.inject.AbstractModule;
|
||||||
|
import com.google.inject.Provides;
|
||||||
|
|
||||||
|
import org.briarproject.api.crypto.CryptoComponent;
|
||||||
|
import org.briarproject.api.crypto.CryptoExecutor;
|
||||||
|
import org.briarproject.api.crypto.PasswordStrengthEstimator;
|
||||||
|
import org.briarproject.api.crypto.StreamDecrypterFactory;
|
||||||
|
import org.briarproject.api.crypto.StreamEncrypterFactory;
|
||||||
|
import org.briarproject.api.lifecycle.LifecycleManager;
|
||||||
|
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
@@ -11,15 +19,7 @@ import java.util.concurrent.ThreadPoolExecutor;
|
|||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import org.briarproject.api.crypto.CryptoComponent;
|
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||||
import org.briarproject.api.crypto.CryptoExecutor;
|
|
||||||
import org.briarproject.api.crypto.PasswordStrengthEstimator;
|
|
||||||
import org.briarproject.api.crypto.StreamDecrypterFactory;
|
|
||||||
import org.briarproject.api.crypto.StreamEncrypterFactory;
|
|
||||||
import org.briarproject.api.lifecycle.LifecycleManager;
|
|
||||||
|
|
||||||
import com.google.inject.AbstractModule;
|
|
||||||
import com.google.inject.Provides;
|
|
||||||
|
|
||||||
public class CryptoModule extends AbstractModule {
|
public class CryptoModule extends AbstractModule {
|
||||||
|
|
||||||
@@ -42,7 +42,8 @@ public class CryptoModule extends AbstractModule {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void configure() {
|
protected void configure() {
|
||||||
bind(AuthenticatedCipher.class).to(AuthenticatedCipherImpl.class);
|
bind(AuthenticatedCipher.class).to(
|
||||||
|
XSalsa20Poly1305AuthenticatedCipher.class);
|
||||||
bind(CryptoComponent.class).to(
|
bind(CryptoComponent.class).to(
|
||||||
CryptoComponentImpl.class).in(Singleton.class);
|
CryptoComponentImpl.class).in(Singleton.class);
|
||||||
bind(PasswordStrengthEstimator.class).to(
|
bind(PasswordStrengthEstimator.class).to(
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH;
|
|||||||
* <li>http://cr.yp.to/highspeed/naclcrypto-20090310.pdf</li>
|
* <li>http://cr.yp.to/highspeed/naclcrypto-20090310.pdf</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
public class XSalsa20Poly1305AC implements AuthenticatedCipher {
|
public class XSalsa20Poly1305AuthenticatedCipher
|
||||||
|
implements AuthenticatedCipher {
|
||||||
|
|
||||||
/** Length of the padding to be used to generate the Poly1305 key */
|
/** Length of the padding to be used to generate the Poly1305 key */
|
||||||
private static final int SUBKEY_LENGTH = 32;
|
private static final int SUBKEY_LENGTH = 32;
|
||||||
@@ -34,13 +35,14 @@ public class XSalsa20Poly1305AC implements AuthenticatedCipher {
|
|||||||
|
|
||||||
private boolean encrypting;
|
private boolean encrypting;
|
||||||
|
|
||||||
XSalsa20Poly1305AC() {
|
XSalsa20Poly1305AuthenticatedCipher() {
|
||||||
xSalsa20Engine = new XSalsa20Engine();
|
xSalsa20Engine = new XSalsa20Engine();
|
||||||
poly1305 = new Poly1305();
|
poly1305 = new Poly1305();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(boolean encrypt, SecretKey key, byte[] iv) throws GeneralSecurityException {
|
public void init(boolean encrypt, SecretKey key, byte[] iv)
|
||||||
|
throws GeneralSecurityException {
|
||||||
encrypting = encrypt;
|
encrypting = encrypt;
|
||||||
KeyParameter k = new KeyParameter(key.getBytes());
|
KeyParameter k = new KeyParameter(key.getBytes());
|
||||||
ParametersWithIV params = new ParametersWithIV(k, iv);
|
ParametersWithIV params = new ParametersWithIV(k, iv);
|
||||||
@@ -52,12 +54,10 @@ public class XSalsa20Poly1305AC implements AuthenticatedCipher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int process(byte[] input, int inputOff, int len, byte[] output, int outputOff) throws GeneralSecurityException {
|
public int process(byte[] input, int inputOff, int len, byte[] output,
|
||||||
if (len == 0)
|
int outputOff) throws GeneralSecurityException {
|
||||||
return 0;
|
if (!encrypting && len < MAC_LENGTH)
|
||||||
else if (!encrypting && len < MAC_LENGTH)
|
|
||||||
throw new GeneralSecurityException("Invalid MAC");
|
throw new GeneralSecurityException("Invalid MAC");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Generate the Poly1305 subkey from an empty array
|
// Generate the Poly1305 subkey from an empty array
|
||||||
byte[] zero = new byte[SUBKEY_LENGTH];
|
byte[] zero = new byte[SUBKEY_LENGTH];
|
||||||
@@ -100,7 +100,7 @@ public class XSalsa20Poly1305AC implements AuthenticatedCipher {
|
|||||||
throw new GeneralSecurityException("Invalid MAC");
|
throw new GeneralSecurityException("Invalid MAC");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invert the stream encryption
|
// Apply or invert the stream encryption
|
||||||
int processed = xSalsa20Engine.processBytes(
|
int processed = xSalsa20Engine.processBytes(
|
||||||
input, encrypting ? inputOff : inputOff + MAC_LENGTH,
|
input, encrypting ? inputOff : inputOff + MAC_LENGTH,
|
||||||
encrypting ? len : len - MAC_LENGTH,
|
encrypting ? len : len - MAC_LENGTH,
|
||||||
@@ -112,7 +112,7 @@ public class XSalsa20Poly1305AC implements AuthenticatedCipher {
|
|||||||
poly1305.doFinal(output, outputOff);
|
poly1305.doFinal(output, outputOff);
|
||||||
}
|
}
|
||||||
|
|
||||||
return processed;
|
return encrypting ? processed + MAC_LENGTH : processed;
|
||||||
} catch (DataLengthException e) {
|
} catch (DataLengthException e) {
|
||||||
throw new GeneralSecurityException(e.getMessage());
|
throw new GeneralSecurityException(e.getMessage());
|
||||||
}
|
}
|
||||||
@@ -6,10 +6,12 @@ import org.briarproject.util.StringUtils;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
public class XSalsa20Poly1305ACTest extends BriarTestCase {
|
public class XSalsa20Poly1305AuthenticatedCipherTest extends BriarTestCase {
|
||||||
|
|
||||||
// Test vectors from the NaCl paper
|
// Test vectors from the NaCl paper
|
||||||
// http://cr.yp.to/highspeed/naclcrypto-20090310.pdf
|
// http://cr.yp.to/highspeed/naclcrypto-20090310.pdf
|
||||||
@@ -47,43 +49,45 @@ public class XSalsa20Poly1305ACTest extends BriarTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testEncrypt() throws Exception {
|
public void testEncrypt() throws Exception {
|
||||||
SecretKey k = new SecretKey(TEST_KEY);
|
SecretKey k = new SecretKey(TEST_KEY);
|
||||||
AuthenticatedCipher cipher = new XSalsa20Poly1305AC();
|
AuthenticatedCipher cipher = new XSalsa20Poly1305AuthenticatedCipher();
|
||||||
cipher.init(true, k, TEST_IV);
|
cipher.init(true, k, TEST_IV);
|
||||||
byte[] output = new byte[TEST_PLAINTEXT.length + cipher.getMacBytes()];
|
byte[] output = new byte[TEST_CIPHERTEXT.length];
|
||||||
cipher.process(TEST_PLAINTEXT, 0, TEST_PLAINTEXT.length, output, 0);
|
assertEquals(TEST_CIPHERTEXT.length, cipher.process(TEST_PLAINTEXT, 0,
|
||||||
|
TEST_PLAINTEXT.length, output, 0));
|
||||||
assertArrayEquals(TEST_CIPHERTEXT, output);
|
assertArrayEquals(TEST_CIPHERTEXT, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDecrypt() throws Exception {
|
public void testDecrypt() throws Exception {
|
||||||
SecretKey k = new SecretKey(TEST_KEY);
|
SecretKey k = new SecretKey(TEST_KEY);
|
||||||
AuthenticatedCipher cipher = new XSalsa20Poly1305AC();
|
AuthenticatedCipher cipher = new XSalsa20Poly1305AuthenticatedCipher();
|
||||||
cipher.init(false, k, TEST_IV);
|
cipher.init(false, k, TEST_IV);
|
||||||
byte[] output = new byte[TEST_CIPHERTEXT.length - cipher.getMacBytes()];
|
byte[] output = new byte[TEST_PLAINTEXT.length];
|
||||||
cipher.process(TEST_CIPHERTEXT, 0, TEST_CIPHERTEXT.length, output, 0);
|
assertEquals(TEST_PLAINTEXT.length, cipher.process(TEST_CIPHERTEXT, 0,
|
||||||
|
TEST_CIPHERTEXT.length, output, 0));
|
||||||
assertArrayEquals(TEST_PLAINTEXT, output);
|
assertArrayEquals(TEST_PLAINTEXT, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = GeneralSecurityException.class)
|
@Test(expected = GeneralSecurityException.class)
|
||||||
public void testDecryptFailsWithShortInput() throws Exception {
|
public void testDecryptFailsWithShortInput() throws Exception {
|
||||||
SecretKey k = new SecretKey(TEST_KEY);
|
SecretKey k = new SecretKey(TEST_KEY);
|
||||||
AuthenticatedCipher cipher = new XSalsa20Poly1305AC();
|
AuthenticatedCipher cipher = new XSalsa20Poly1305AuthenticatedCipher();
|
||||||
cipher.init(false, k, TEST_IV);
|
cipher.init(false, k, TEST_IV);
|
||||||
byte[] input = new byte[8];
|
byte[] input = new byte[cipher.getMacBytes() - 1];
|
||||||
System.arraycopy(TEST_CIPHERTEXT, 0, input, 0, 8);
|
System.arraycopy(TEST_CIPHERTEXT, 0, input, 0, input.length);
|
||||||
byte[] output = new byte[TEST_CIPHERTEXT.length - cipher.getMacBytes()];
|
byte[] output = new byte[TEST_PLAINTEXT.length];
|
||||||
cipher.process(input, 0, input.length, output, 0);
|
cipher.process(input, 0, input.length, output, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = GeneralSecurityException.class)
|
@Test(expected = GeneralSecurityException.class)
|
||||||
public void testDecryptFailsWithAlteredCiphertext() throws Exception {
|
public void testDecryptFailsWithAlteredCiphertext() throws Exception {
|
||||||
SecretKey k = new SecretKey(TEST_KEY);
|
SecretKey k = new SecretKey(TEST_KEY);
|
||||||
AuthenticatedCipher cipher = new XSalsa20Poly1305AC();
|
AuthenticatedCipher cipher = new XSalsa20Poly1305AuthenticatedCipher();
|
||||||
cipher.init(false, k, TEST_IV);
|
cipher.init(false, k, TEST_IV);
|
||||||
byte[] input = new byte[TEST_CIPHERTEXT.length];
|
byte[] input = new byte[TEST_CIPHERTEXT.length];
|
||||||
System.arraycopy(TEST_CIPHERTEXT, 0, input, 0, TEST_CIPHERTEXT.length);
|
System.arraycopy(TEST_CIPHERTEXT, 0, input, 0, TEST_CIPHERTEXT.length);
|
||||||
input[TEST_CIPHERTEXT.length - cipher.getMacBytes()] = 42;
|
input[new Random().nextInt(TEST_CIPHERTEXT.length)] ^= 0xFF;
|
||||||
byte[] output = new byte[TEST_CIPHERTEXT.length - cipher.getMacBytes()];
|
byte[] output = new byte[TEST_PLAINTEXT.length];
|
||||||
cipher.process(input, 0, input.length, output, 0);
|
cipher.process(input, 0, input.length, output, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user