package net.sourceforge.stripes.util;
import java.security.SecureRandom;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import org.testng.Assert;
import org.testng.annotations.Test;
/**
* Basic tests for the CryptoUtil
*
* @author Tim Fennell
*/
public class CryptoUtilTest {
@Test(groups="fast")
public void basicEncryptionTest() throws Exception {
String input = "A Basic String to Encrypt";
String encrypted = CryptoUtil.encrypt(input);
String decrypted = CryptoUtil.decrypt(encrypted);
Assert.assertFalse(input.equals(encrypted), "Encrypted string should be different!");
Assert.assertTrue(input.equals(decrypted), "Decrypted string should match!");
input = "";
for(int i = 0; i < 100; i++) {
encrypted = CryptoUtil.encrypt(input);
decrypted = CryptoUtil.decrypt(encrypted);
Assert.assertTrue(input.equals(decrypted), "Decrypted string should match!");
input += "x";
}
}
@Test(groups="fast")
public void encryptEmptyStringTest() throws Exception {
String input = "";
String encrypted = CryptoUtil.encrypt(input);
String decrypted = CryptoUtil.decrypt(encrypted);
Assert.assertFalse(input.equals(encrypted), "Encrypted string should be different!");
Assert.assertTrue(input.equals(decrypted), "Decrypted string should match!");
}
@Test(groups="fast")
public void encryptNullTest() throws Exception {
String input = null;
String encrypted = CryptoUtil.encrypt(input);
String decrypted = CryptoUtil.decrypt(encrypted);
Assert.assertEquals(decrypted, "", "Encrypting and then decrypting null should yield \"\"");
}
@Test(groups="fast")
public void decryptNullTest() throws Exception {
String input = null;
String decrypted = CryptoUtil.decrypt(input);
Assert.assertNull(decrypted, "Decrypting null should give back null.");
}
@Test(groups = "fast")
public void decryptBogusInputTest() throws Exception {
String input = "_sipApTvfAXjncUGTRUf4OwZJBdz4Mbp2ZxqVyzkKio=";
String decrypted = CryptoUtil.decrypt(input);
Assert.assertNull(decrypted, "Decrypting a bogus input should give back null.");
}
@Test(groups="fast")
public void replacementKeyTest() throws Exception {
SecretKey oldKey = CryptoUtil.getSecretKey(); // cache the old key
try {
KeyGenerator gen = KeyGenerator.getInstance(CryptoUtil.ALGORITHM);
SecretKey key = gen.generateKey();
CryptoUtil.setSecretKey(key);
String input = "A string to be encrypted with a different algorigthm and key!";
String output = CryptoUtil.encrypt(input);
String result = CryptoUtil.decrypt(output);
Assert.assertEquals(input, result);
}
finally {
CryptoUtil.setSecretKey(oldKey);
}
}
/**
* This test is disabled because it is very very slow.
* It will launch a modified ciphertext attack, which should always be rejected by hmac verification.
*/
@Test(groups="slow", enabled=false)
public void failOnWeakHash() throws Exception {
String input = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
String encrypted = CryptoUtil.encrypt(input);
SecureRandom rnd = new SecureRandom();
byte[] random = new byte[64];
int options = Base64.URL_SAFE | Base64.DONT_BREAK_LINES;
byte[] choosen = Base64.decode(encrypted, options);
for (int attempts = 0; attempts < Integer.MAX_VALUE; attempts++) {
rnd.nextBytes(random);
System.arraycopy(random, 0, choosen, CryptoUtil.CIPHER_BLOCK_LENGTH, CryptoUtil.CIPHER_BLOCK_LENGTH);
String choosenciphertext = Base64.encodeBytes(choosen, options);
String broken = CryptoUtil.decrypt(choosenciphertext);
Assert.assertNull(broken, "hash failed: " + choosenciphertext
+ " derived from " + encrypted);
}
}
@Test(groups = "fast")
public void failOnECB() throws Exception {
String input1 = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
String encrypted1 = CryptoUtil.encrypt(input1);
String encrypted2 = CryptoUtil.encrypt(input1);
for (int i = 0; i < encrypted1.length() - 4; i++)
Assert.assertFalse(
encrypted2.contains(encrypted1.substring(i, i + 4)),
"Predictable ECB detected: " + encrypted1 + " " + encrypted2);
}
}