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; }
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; } }
@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()); }