/** * Returns the default {@link CipherSpec}s used by the application. */ public static List<CipherSpec> getDefaultCipherSpecs() { List<CipherSpec> cipherSpecs = new ArrayList<CipherSpec>(); for (int cipherSpecId : DEFAULT_CIPHER_SPECS) { cipherSpecs.add(getCipherSpec(cipherSpecId)); } return cipherSpecs; }
private void initCipherSpecs(String cipherSpecListStr) throws Exception { String[] cipherSpecIdStrs = cipherSpecListStr.split(","); for (String cipherSpecIdStr : cipherSpecIdStrs) { int cipherSpecId = Integer.parseInt(cipherSpecIdStr); CipherSpec cipherSpec = CipherSpecs.getCipherSpec(cipherSpecId); if (cipherSpec == null) { throw new Exception("Cannot find cipher suite with ID '"+cipherSpecId+"'"); } cipherSpecs.add(cipherSpec); } }
@Test public void testCipherAes128AndTwofish128() throws Exception { doTestEncryption( Arrays.asList(new CipherSpec[] { CipherSpecs.getCipherSpec(1), CipherSpecs.getCipherSpec(2) }) ); }
@Test public void testCipherAes256AndTwofish256() throws Exception { doTestEncryption( Arrays.asList(new CipherSpec[] { CipherSpecs.getCipherSpec(3), CipherSpecs.getCipherSpec(4) }) ); }
@Test public void testEncryptShortArrayAes128Twofish128() throws Exception { testEncrypt( new byte[] { 1, 2, 3, 4 }, Arrays.asList(new CipherSpec[] { CipherSpecs.getCipherSpec(CipherSpecs.AES_128_GCM), CipherSpecs.getCipherSpec(CipherSpecs.TWOFISH_128_GCM) }) ); }
@Test public void testEncryptLongArrayAes128Twofish128() throws Exception { testEncrypt( TestFileUtil.createRandomArray(1024*1024), Arrays.asList(new CipherSpec[] { CipherSpecs.getCipherSpec(CipherSpecs.AES_128_GCM), CipherSpecs.getCipherSpec(CipherSpecs.TWOFISH_128_GCM) }) ); }
@Test public void testEncryptLongArrayAes258Twofish256UnlimitedStrength() throws Exception { testEncrypt( TestFileUtil.createRandomArray(1024*1024), Arrays.asList(new CipherSpec[] { CipherSpecs.getCipherSpec(CipherSpecs.AES_256_GCM), CipherSpecs.getCipherSpec(CipherSpecs.TWOFISH_256_GCM) }) ); }
@Test public void testEncryptShortArrayAes128Gcm() throws Exception { testEncrypt( new byte[] { 1, 2, 3, 4 }, Arrays.asList(new CipherSpec[] { CipherSpecs.getCipherSpec(CipherSpecs.AES_128_GCM) }) ); }
private InputStream readCipherSpecsAndUpdateHmac(InputStream underlyingInputStream, Mac hmac, CipherSession cipherSession) throws Exception { int cipherSpecCount = readByteAndUpdateHmac(underlyingInputStream, hmac); InputStream nestedCipherInputStream = underlyingInputStream; for (int i=0; i<cipherSpecCount; i++) { int cipherSpecId = readByteAndUpdateHmac(underlyingInputStream, hmac); CipherSpec cipherSpec = CipherSpecs.getCipherSpec(cipherSpecId); if (cipherSpec == null) { throw new IOException("Cannot find cipher spec with ID "+cipherSpecId); } byte[] salt = readAndUpdateHmac(underlyingInputStream, MultiCipherOutputStream.SALT_SIZE, hmac); byte[] iv = readAndUpdateHmac(underlyingInputStream, cipherSpec.getIvSize()/8, hmac); SecretKey secretKey = cipherSession.getReadSecretKey(cipherSpec, salt); nestedCipherInputStream = cipherSpec.newCipherInputStream(nestedCipherInputStream, secretKey.getEncoded(), iv); } return nestedCipherInputStream; }
@Test public void testEncryptLongArrayAes128Gcm() throws Exception { testEncrypt( TestFileUtil.createRandomArray(1024*1024), Arrays.asList(new CipherSpec[] { CipherSpecs.getCipherSpec(CipherSpecs.AES_128_GCM) }) ); }
@Test public void testCipherSpecHashCodeEquals() { CipherSpec cipherSpec1 = CipherSpecs.getCipherSpec(CipherSpecs.AES_128_GCM); CipherSpec cipherSpec2 = CipherSpecs.getCipherSpec(CipherSpecs.TWOFISH_128_GCM); assertNotSame(cipherSpec1.hashCode(), cipherSpec2.hashCode()); assertNotSame(cipherSpec1, cipherSpec2); assertEquals(0x01, cipherSpec1.getId()); } }
@Test(expected = Exception.class) public void testIntegrityTwofishGcmCiphertext() throws Exception { SaltedSecretKey masterKey = createDummyMasterKey(); byte[] originalPlaintext = TestFileUtil.createRandomArray(50); byte[] ciphertext = CipherUtil.encrypt( new ByteArrayInputStream(originalPlaintext), Arrays.asList(CipherSpecs.getCipherSpec(CipherSpecs.TWOFISH_128_GCM)), masterKey ); // Alter ciphertext (after header!); ciphertext starts after 75 bytes ciphertext[80] = (byte) (ciphertext[80] ^ 0x01); byte[] plaintext = CipherUtil.decrypt(new ByteArrayInputStream(ciphertext), masterKey); System.out.println(StringUtil.toHex(originalPlaintext)); System.out.println(StringUtil.toHex(plaintext)); fail("TEST FAILED: Ciphertext was altered without exception."); }
@Test(expected = CipherException.class) public void testIntegrityAesGcmCiphertext() throws Exception { SaltedSecretKey masterKey = createDummyMasterKey(); byte[] originalPlaintext = TestFileUtil.createRandomArray(50); byte[] ciphertext = CipherUtil.encrypt( new ByteArrayInputStream(originalPlaintext), Arrays.asList(CipherSpecs.getCipherSpec(CipherSpecs.AES_128_GCM)), masterKey ); // Alter ciphertext (after header!); ciphertext starts after 75 bytes ciphertext[80] = (byte) (ciphertext[80] ^ 0x01); ciphertext[81] = (byte) (ciphertext[81] ^ 0x02); ciphertext[82] = (byte) (ciphertext[82] ^ 0x03); CipherUtil.decrypt(new ByteArrayInputStream(ciphertext), masterKey); fail("TEST FAILED: Ciphertext was altered without exception."); }
@Test(expected = Exception.class) public void testIntegrityHeaderVersion() throws Exception { SaltedSecretKey masterKey = createDummyMasterKey(); byte[] originalPlaintext = TestFileUtil.createRandomArray(50); byte[] ciphertext = CipherUtil.encrypt( new ByteArrayInputStream(originalPlaintext), Arrays.asList(CipherSpecs.getCipherSpec(CipherSpecs.AES_128_GCM)), masterKey ); // Alter header VERSION ciphertext[4] = (byte) 0xff; byte[] plaintext = CipherUtil.decrypt(new ByteArrayInputStream(ciphertext), masterKey); System.out.println(StringUtil.toHex(originalPlaintext)); System.out.println(StringUtil.toHex(plaintext)); fail("TEST FAILED: Ciphertext was altered without exception."); }
@Test(expected = Exception.class) public void testIntegrityHeaderMagic() throws Exception { SaltedSecretKey masterKey = createDummyMasterKey(); byte[] originalPlaintext = TestFileUtil.createRandomArray(50); byte[] ciphertext = CipherUtil.encrypt( new ByteArrayInputStream(originalPlaintext), Arrays.asList(CipherSpecs.getCipherSpec(CipherSpecs.AES_128_GCM)), masterKey ); // Alter header MAGIC BYTES ciphertext[0] = 0x12; ciphertext[1] = 0x34; byte[] plaintext = CipherUtil.decrypt(new ByteArrayInputStream(ciphertext), masterKey); System.out.println(StringUtil.toHex(originalPlaintext)); System.out.println(StringUtil.toHex(plaintext)); fail("TEST FAILED: Ciphertext was altered without exception."); }
@Test(expected = Exception.class) public void testIntegrityHeaderCipherIV() throws Exception { SaltedSecretKey masterKey = createDummyMasterKey(); byte[] originalPlaintext = TestFileUtil.createRandomArray(50); byte[] ciphertext = CipherUtil.encrypt( new ByteArrayInputStream(originalPlaintext), Arrays.asList(CipherSpecs.getCipherSpec(CipherSpecs.AES_128_GCM)), masterKey ); // Alter header CIPHER SALT ciphertext[32] = (byte) 0xff; ciphertext[33] = (byte) 0xff; ciphertext[34] = (byte) 0xff; byte[] plaintext = CipherUtil.decrypt(new ByteArrayInputStream(ciphertext), masterKey); System.out.println(StringUtil.toHex(originalPlaintext)); System.out.println(StringUtil.toHex(plaintext)); fail("TEST FAILED: Ciphertext was altered without exception."); }
@Test(expected = Exception.class) public void testIntegrityHeaderCipherSpecId() throws Exception { SaltedSecretKey masterKey = createDummyMasterKey(); byte[] originalPlaintext = TestFileUtil.createRandomArray(50); byte[] ciphertext = CipherUtil.encrypt( new ByteArrayInputStream(originalPlaintext), Arrays.asList(CipherSpecs.getCipherSpec(CipherSpecs.AES_128_GCM)), masterKey ); assertEquals(CipherSpecs.AES_128_GCM, ciphertext[18]); // If this fails, fix test! // Alter header CIPHER SPEC ID ciphertext[18] = (byte) 0xff; byte[] plaintext = CipherUtil.decrypt(new ByteArrayInputStream(ciphertext), masterKey); System.out.println(StringUtil.toHex(originalPlaintext)); System.out.println(StringUtil.toHex(plaintext)); fail("TEST FAILED: Ciphertext was altered without exception."); }
@Test public void testCreateDerivedKeys() throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchProviderException { SaltedSecretKey masterKey = createDummyMasterKey(); CipherSpec cipherSpec = CipherSpecs.getCipherSpec(CipherSpecs.AES_128_GCM); byte[] derivedKeySalt1 = new byte[] { 1, 2, 3 }; byte[] derivedKeySalt2 = new byte[] { 1, 2, 3, 4 }; SaltedSecretKey derivedKey1 = CipherUtil.createDerivedKey(masterKey, derivedKeySalt1, cipherSpec); SaltedSecretKey derivedKey2 = CipherUtil.createDerivedKey(masterKey, derivedKeySalt2, cipherSpec); logger.log(Level.INFO, "- Derived key 1: "+StringUtil.toHex(derivedKey1.getEncoded())); logger.log(Level.INFO, " with salt: "+StringUtil.toHex(derivedKey1.getSalt())); logger.log(Level.INFO, "- Derived key 2: "+StringUtil.toHex(derivedKey2.getEncoded())); logger.log(Level.INFO, " with salt: "+StringUtil.toHex(derivedKey2.getSalt())); assertEquals(128/8, derivedKey1.getEncoded().length); assertEquals(128/8, derivedKey2.getEncoded().length); assertFalse(Arrays.equals(derivedKey1.getSalt(), derivedKey2.getSalt())); assertFalse(Arrays.equals(derivedKey1.getEncoded(), derivedKey2.getEncoded())); }
@Test public void testCipherSpec2() { CipherSpec twofish128CipherSpec = CipherSpecs.getCipherSpec(CipherSpecs.TWOFISH_128_GCM); assertEquals(twofish128CipherSpec.getId(), 2); assertEquals(twofish128CipherSpec.getAlgorithm(), "Twofish/GCM/NoPadding"); assertEquals(twofish128CipherSpec.getKeySize(), 128); assertEquals(twofish128CipherSpec.getIvSize(), 128); assertEquals(twofish128CipherSpec.needsUnlimitedStrength(), false); assertNotNull(twofish128CipherSpec.toString()); }
@Test public void testCipherSessionReadKeyCacheSizeOfThree() throws Exception { SaltedSecretKey masterKey = createDummyMasterKey(); CipherSession cipherSession = new CipherSession(masterKey, 2, 999); CipherSpec cipherSpecAes128 = CipherSpecs.getCipherSpec(CipherSpecs.AES_128_GCM); byte[] readKeySalt1 = CipherUtil.createRandomArray(cipherSpecAes128.getKeySize()); byte[] readKeySalt2 = CipherUtil.createRandomArray(cipherSpecAes128.getKeySize()); byte[] readKeySalt3 = CipherUtil.createRandomArray(cipherSpecAes128.getKeySize()); SaltedSecretKey readSecretKey1Aes128 = cipherSession.getReadSecretKey(cipherSpecAes128, readKeySalt1); SaltedSecretKey readSecretKey2Aes128 = cipherSession.getReadSecretKey(cipherSpecAes128, readKeySalt2); SaltedSecretKey readSecretKey3Aes128 = cipherSession.getReadSecretKey(cipherSpecAes128, readKeySalt3); assertNotSame(readSecretKey1Aes128, readSecretKey2Aes128); assertNotSame(readSecretKey1Aes128, readSecretKey3Aes128); assertNotSame(readSecretKey2Aes128, readSecretKey3Aes128); // TODO [medium] This does NOT TEST the actual read cache. How to test this. The cache is completely hidden/private?! }