@Override public String getString(CipherSpec cipherSpec) { return "" + cipherSpec.getId(); } });
/** * Creates a derived key from the given {@link SecretKey} an input salt and wraps the key in * a {@link SecretKeySpec} using the given {@link CipherSpec}. * * <p>This method simply uses the {@link #createDerivedKey(byte[], byte[], String, int) createDerivedKey()} * method using the encoded input key and the algorithm and key size given by the cipher spec. * * @param inputKey The source key to derive the new key from * @param inputSalt Input salt used to generate the new key (a non-secret random value!) * @param outputCipherSpec Defines the algorithm and key size of the new output key * @return Returns a derived key (including the given input salt) */ public static SaltedSecretKey createDerivedKey(SecretKey inputKey, byte[] inputSalt, CipherSpec outputCipherSpec) throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchProviderException { return createDerivedKey(inputKey.getEncoded(), inputSalt, outputCipherSpec.getAlgorithm(), outputCipherSpec.getKeySize()); }
@Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((cipherSpec == null) ? 0 : cipherSpec.hashCode()); result = prime * result + Arrays.hashCode(salt); return result; }
@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()); }
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 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()); } }
out.println(" [" + cipherSuite.getId() + "] " + cipherSuite); if (cipherSpec.needsUnlimitedStrength()) { unlimitedStrengthNeeded = true;
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 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 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?! }
public CipherSpec(int id, String algorithm, int keySize, int ivSize, boolean needsUnlimitedStrength) { this.id = id; this.algorithm = algorithm; this.keySize = keySize; this.ivSize = ivSize; this.needsUnlimitedStrength = needsUnlimitedStrength; doSanityChecks(); }
@Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof CipherSpecWithSalt)) { return false; } CipherSpecWithSalt other = (CipherSpecWithSalt) obj; if (cipherSpec == null) { if (other.cipherSpec != null) { return false; } } else if (!cipherSpec.equals(other.cipherSpec)) { return false; } if (!Arrays.equals(salt, other.salt)) { return false; } return true; } }
@Test public void testHmacAvailability() throws Exception { Mac.getInstance(MultiCipherOutputStream.HMAC_SPEC.getAlgorithm()); // Should not throw an exception }
@Test public void testCipherSpecs() { Map<Integer, CipherSpec> availableCipherSpecs = CipherSpecs.getAvailableCipherSpecs(); assertEquals(4, availableCipherSpecs.size()); assertEquals(availableCipherSpecs.get(CipherSpecs.AES_128_GCM).getAlgorithm(), "AES/GCM/NoPadding"); }