public CipherTransformer(List<CipherSpec> cipherSpecs, SaltedSecretKey masterKey) { this.cipherSpecs = cipherSpecs; this.cipherSession = new CipherSession(masterKey); }
private Mac readHmacSaltAndInitHmac(InputStream inputStream, CipherSession cipherSession) throws Exception { byte[] hmacSalt = readNoHmac(inputStream, MultiCipherOutputStream.SALT_SIZE); SecretKey hmacSecretKey = cipherSession.getReadSecretKey(MultiCipherOutputStream.HMAC_SPEC, hmacSalt); Mac hmac = Mac.getInstance(MultiCipherOutputStream.HMAC_SPEC.getAlgorithm(), CRYPTO_PROVIDER_ID); hmac.init(hmacSecretKey); return hmac; }
private SaltedSecretKey createSaltedSecretKey(CipherSpec cipherSpec) throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchProviderException { byte[] salt = CipherUtil.createRandomArray(MultiCipherOutputStream.SALT_SIZE); return createSaltedSecretKey(cipherSpec, salt); }
@Test public void testCipherSessionWriteKeyReuseCountOfTwo() throws Exception { SaltedSecretKey masterKey = createDummyMasterKey(); CipherSession cipherSession = new CipherSession(masterKey, 999, 2); CipherSpec cipherSpecAes128 = CipherSpecs.getCipherSpec(CipherSpecs.AES_128_GCM); CipherSpec cipherSpecTwofish128 = CipherSpecs.getCipherSpec(CipherSpecs.TWOFISH_128_GCM); SaltedSecretKey writeSecretKey1Aes128 = cipherSession.getWriteSecretKey(cipherSpecAes128); SaltedSecretKey writeSecretKey2Aes128 = cipherSession.getWriteSecretKey(cipherSpecAes128); SaltedSecretKey writeSecretKey3Aes128 = cipherSession.getWriteSecretKey(cipherSpecAes128); SaltedSecretKey writeSecretKey1Twofish128 = cipherSession.getWriteSecretKey(cipherSpecTwofish128); SaltedSecretKey writeSecretKey2Twofish128 = cipherSession.getWriteSecretKey(cipherSpecTwofish128); SaltedSecretKey writeSecretKey3Twofish128 = cipherSession.getWriteSecretKey(cipherSpecTwofish128); assertEquals(writeSecretKey1Aes128, writeSecretKey2Aes128); assertNotSame(writeSecretKey1Aes128, writeSecretKey3Aes128); assertEquals(writeSecretKey1Twofish128, writeSecretKey2Twofish128); assertNotSame(writeSecretKey1Twofish128, writeSecretKey3Twofish128); assertNotSame(writeSecretKey1Aes128, writeSecretKey1Twofish128); }
@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?! }
private void writeHeader() throws IOException { if (!headerWritten) { try { // Initialize header HMAC SaltedSecretKey hmacSecretKey = cipherSession.getWriteSecretKey(HMAC_SPEC); headerHmac = Mac.getInstance(HMAC_SPEC.getAlgorithm(), CRYPTO_PROVIDER_ID); headerHmac.init(hmacSecretKey); // Write header writeNoHmac(underlyingOutputStream, STREAM_MAGIC); writeNoHmac(underlyingOutputStream, STREAM_VERSION); writeNoHmac(underlyingOutputStream, hmacSecretKey.getSalt()); writeAndUpdateHmac(underlyingOutputStream, cipherSpecs.size()); cipherOutputStream = underlyingOutputStream; for (CipherSpec cipherSpec : cipherSpecs) { SaltedSecretKey saltedSecretKey = cipherSession.getWriteSecretKey(cipherSpec); byte[] iv = CipherUtil.createRandomArray(cipherSpec.getIvSize()/8); writeAndUpdateHmac(underlyingOutputStream, cipherSpec.getId()); writeAndUpdateHmac(underlyingOutputStream, saltedSecretKey.getSalt()); writeAndUpdateHmac(underlyingOutputStream, iv); cipherOutputStream = cipherSpec.newCipherOutputStream(cipherOutputStream, saltedSecretKey.getEncoded(), iv); } writeNoHmac(underlyingOutputStream, headerHmac.doFinal()); } catch (Exception e) { throw new IOException(e); } headerWritten = true; } }
public static void encrypt(InputStream plaintextInputStream, OutputStream ciphertextOutputStream, List<CipherSpec> cipherSpecs, SaltedSecretKey masterKey) throws CipherException { try { CipherSession cipherSession = new CipherSession(masterKey); OutputStream multiCipherOutputStream = new MultiCipherOutputStream(ciphertextOutputStream, cipherSpecs, cipherSession); int read = -1; byte[] buffer = new byte[4096]; while (-1 != (read = plaintextInputStream.read(buffer))) { multiCipherOutputStream.write(buffer, 0, read); } plaintextInputStream.close(); multiCipherOutputStream.close(); } catch (IOException e) { throw new CipherException(e); } }
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; }
SaltedSecretKey saltedSecretKey = createSaltedSecretKey(cipherSpec, salt); secretKeyCacheEntry = new SecretKeyCacheEntry(saltedSecretKey);
private void initCipherSession(String masterKeyStr, String masterKeySaltStr) { byte[] masterKeySalt = StringUtil.fromHex(masterKeySaltStr); byte[] masterKeyBytes = StringUtil.fromHex(masterKeyStr); SaltedSecretKey masterKey = new SaltedSecretKey(new SecretKeySpec(masterKeyBytes, "RAW"), masterKeySalt); cipherSession = new CipherSession(masterKey); }
SaltedSecretKey saltedSecretKey = createSaltedSecretKey(cipherSpec);
public static byte[] decrypt(InputStream fromInputStream, SaltedSecretKey masterKey) throws CipherException { try { CipherSession cipherSession = new CipherSession(masterKey); MultiCipherInputStream multiCipherInputStream = new MultiCipherInputStream(fromInputStream, cipherSession); ByteArrayOutputStream plaintextOutputStream = new ByteArrayOutputStream(); int read = -1; byte[] buffer = new byte[4096]; while (-1 != (read = multiCipherInputStream.read(buffer))) { plaintextOutputStream.write(buffer, 0, read); } multiCipherInputStream.close(); plaintextOutputStream.close(); return plaintextOutputStream.toByteArray(); } catch (IOException e) { throw new CipherException(e); } }