RecordAEADCipher extends RecordCipher { @Override public void encrypt(Record record) throws CryptoException { LOGGER.debug("Encrypting Record"); record.getComputations().setCipherKey(getKeySet().getWriteKey(context.getChooser().getConnectionEndType())); if (version.isTLS13()) { int additionalPadding = context.getConfig().getDefaultAdditionalPadding(); if (additionalPadding > 65536) { LOGGER.warn("Additional padding is too big. setting it to max possible value"); additionalPadding = 65536; } else if (additionalPadding < 0) { LOGGER.warn("Additional padding is negative, setting it to 0"); additionalPadding = 0; } record.getComputations().setPadding(new byte[additionalPadding]); record.getComputations().setPlainRecordBytes( ArrayConverter.concatenate(record.getCleanProtocolMessageBytes().getValue(), new byte[] { record .getContentType().getValue() }, record.getComputations().getPadding().getValue())); record.setLength(record.getComputations().getPlainRecordBytes().getValue().length + AEAD_TAG_LENGTH); record.setContentType(ProtocolMessageType.APPLICATION_DATA.getValue()); } else { record.getComputations().setPlainRecordBytes(record.getCleanProtocolMessageBytes().getValue()); } byte[] explicitNonce = prepareEncryptionExplicitNonce(record); byte[] aeadSalt = prepareEncryptionAeadSalt(record); byte[] gcmNonce = prepareEncryptionGcmNonce(aeadSalt, explicitNonce, record); LOGGER.debug("Encrypting AEAD with the following IV: {}", ArrayConverter.bytesToHexString(gcmNonce)); byte[] additionalAuthenticatedData = collectAdditionalAuthenticatedData(record, context.getChooser() .getSelectedProtocolVersion()); record.getComputations().setAuthenticatedMetaData(additionalAuthenticatedData); additionalAuthenticatedData = record.getComputations().getAuthenticatedMetaData().getValue(); LOGGER.debug("Encrypting AEAD with the following AAD: {}", ArrayConverter.bytesToHexString(additionalAuthenticatedData)); byte[] plainBytes = record.getComputations().getPlainRecordBytes().getValue(); byte[] wholeCipherText = encryptCipher.encrypt(gcmNonce, aeadTagLength * Bits.IN_A_BYTE, additionalAuthenticatedData, plainBytes); if (aeadTagLength >= wholeCipherText.length) { throw new CryptoException("Could not encrypt data. Supposed Tag is longer than the ciphertext"); } byte[] onlyCiphertext = Arrays.copyOfRange(wholeCipherText, 0, wholeCipherText.length - aeadTagLength); record.getComputations().setAuthenticatedNonMetaData(onlyCiphertext); byte[] authenticationTag = Arrays.copyOfRange(wholeCipherText, wholeCipherText.length - aeadTagLength, wholeCipherText.length); record.getComputations().setAuthenticationTag(authenticationTag); authenticationTag = record.getComputations().getAuthenticationTag().getValue(); record.getComputations().setCiphertext(onlyCiphertext); onlyCiphertext = record.getComputations().getCiphertext().getValue(); record.setProtocolMessageBytes(ArrayConverter.concatenate(explicitNonce, onlyCiphertext, authenticationTag)); record.getComputations().setAuthenticationTagValid(true); } RecordAEADCipher(TlsContext context, KeySet keySet); int getAeadSizeIncrease(); @Override void encrypt(Record record); @Override void decrypt(Record record); @Override void encrypt(BlobRecord br); @Override void decrypt(BlobRecord br); byte[] preprocessIv(long sequenceNumber, byte[] iv);  }
@Test public void testEncryptGcmServer() throws NoSuchAlgorithmException, CryptoException { context.setConnection(new OutboundConnection()); context.setTalkingConnectionEndType(ConnectionEndType.SERVER); context.setSelectedCipherSuite(CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256); context.setSelectedProtocolVersion(ProtocolVersion.TLS12); KeySet keySet = new KeySet(); keySet.setClientWriteKey(ArrayConverter .hexStringToByteArray("65B7DA726864D4184D75A549BF5C06AB20867846AF4434CC")); keySet.setClientWriteMacSecret(new byte[0]); keySet.setClientWriteIv(ArrayConverter.hexStringToByteArray("11223344556677889900AABB")); keySet.setServerWriteIv(new byte[12]); keySet.setServerWriteKey(new byte[16]); keySet.setServerWriteMacSecret(new byte[0]); context.setRandom(new TestRandomData(ArrayConverter.hexStringToByteArray("FFEEDDCC"))); byte[] data = ArrayConverter .hexStringToByteArray("1400000CCE92FBEC9131F48A63FED31F71573F726479AA9108FB86A4FA16BC1D5CB5753003030303"); cipher = new RecordAEADCipher(context, keySet); Record record = new Record(); record.setContentType(ProtocolMessageType.HANDSHAKE.getValue()); record.prepareComputations(); record.setSequenceNumber(new BigInteger("0")); record.setCleanProtocolMessageBytes(data); record.setProtocolVersion(ProtocolVersion.TLS12.getValue()); cipher.encrypt(record); assertNull(record.getComputations().getCbcInitialisationVector()); assertNull(record.getComputations().getMacKey()); assertNull(record.getComputations().getMac()); assertNull(record.getComputations().getMacValid()); assertNull(record.getComputations().getPaddingValid()); assertNull(record.getComputations().getPadding()); assertArrayEquals(ArrayConverter.hexStringToByteArray("0000000000000000"), record.getComputations() .getExplicitNonce().getValue()); assertArrayEquals(ArrayConverter.hexStringToByteArray("11223344556677889900AABB"), record.getComputations() .getAeadSalt().getValue()); assertArrayEquals(ArrayConverter.hexStringToByteArray("11223344556677889900AABB0000000000000000"), record .getComputations().getGcmNonce().getValue()); assertArrayEquals(ArrayConverter.hexStringToByteArray("DEA10FBB5AF87DF49E75EA206892A1A0"), record .getComputations().getAuthenticationTag().getValue()); assertTrue(record.getComputations().getAuthenticationTagValid()); assertArrayEquals(ArrayConverter.hexStringToByteArray("00000000000000001603030028"), record.getComputations() .getAuthenticatedMetaData().getValue()); assertArrayEquals( ArrayConverter .hexStringToByteArray("77D85417660273BBA5F220778CC117ECB7AAC7F46B0E07A8679215363031E912DA4494F0E8BEA216"), record.getComputations().getAuthenticatedNonMetaData().getValue()); assertArrayEquals(ArrayConverter.hexStringToByteArray("65B7DA726864D4184D75A549BF5C06AB20867846AF4434CC"), record.getComputations().getCipherKey().getValue()); assertArrayEquals( ArrayConverter .hexStringToByteArray("1400000CCE92FBEC9131F48A63FED31F71573F726479AA9108FB86A4FA16BC1D5CB5753003030303"), record.getComputations().getPlainRecordBytes().getValue()); assertArrayEquals( ArrayConverter .hexStringToByteArray("77D85417660273BBA5F220778CC117ECB7AAC7F46B0E07A8679215363031E912DA4494F0E8BEA216"), record.getComputations().getCiphertext().getValue()); assertArrayEquals( ArrayConverter .hexStringToByteArray("000000000000000077D85417660273BBA5F220778CC117ECB7AAC7F46B0E07A8679215363031E912DA4494F0E8BEA216DEA10FBB5AF87DF49E75EA206892A1A0"), record.getProtocolMessageBytes().getValue()); }
@Test public void testEncryptGcmClient() throws NoSuchAlgorithmException, CryptoException { context.setConnection(new InboundConnection()); context.setSelectedCipherSuite(CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256); context.setSelectedProtocolVersion(ProtocolVersion.TLS12); KeySet keySet = new KeySet(); keySet.setServerWriteKey(ArrayConverter .hexStringToByteArray("65B7DA726864D4184D75A549BF5C06AB20867846AF4434CC")); keySet.setServerWriteMacSecret(new byte[0]); keySet.setServerWriteIv(ArrayConverter.hexStringToByteArray("11223344556677889900AABB")); keySet.setClientWriteIv(new byte[12]); keySet.setClientWriteKey(new byte[16]); keySet.setClientWriteMacSecret(new byte[0]); context.setRandom(new TestRandomData(ArrayConverter.hexStringToByteArray("FFEEDDCC"))); byte[] data = ArrayConverter .hexStringToByteArray("1400000CCE92FBEC9131F48A63FED31F71573F726479AA9108FB86A4FA16BC1D5CB5753003030303"); cipher = new RecordAEADCipher(context, keySet); Record record = new Record(); record.setContentType(ProtocolMessageType.HANDSHAKE.getValue()); record.prepareComputations(); record.setSequenceNumber(new BigInteger("0")); record.setCleanProtocolMessageBytes(data); record.setProtocolVersion(ProtocolVersion.TLS12.getValue()); cipher.encrypt(record); assertNull(record.getComputations().getCbcInitialisationVector()); assertNull(record.getComputations().getMacKey()); assertNull(record.getComputations().getMac()); assertNull(record.getComputations().getMacValid()); assertNull(record.getComputations().getPaddingValid()); assertNull(record.getComputations().getPadding()); assertArrayEquals(ArrayConverter.hexStringToByteArray("0000000000000000"), record.getComputations() .getExplicitNonce().getValue()); assertArrayEquals(ArrayConverter.hexStringToByteArray("11223344556677889900AABB"), record.getComputations() .getAeadSalt().getValue()); assertArrayEquals(ArrayConverter.hexStringToByteArray("11223344556677889900AABB0000000000000000"), record .getComputations().getGcmNonce().getValue()); assertArrayEquals(ArrayConverter.hexStringToByteArray("DEA10FBB5AF87DF49E75EA206892A1A0"), record .getComputations().getAuthenticationTag().getValue()); assertTrue(record.getComputations().getAuthenticationTagValid()); assertArrayEquals(ArrayConverter.hexStringToByteArray("00000000000000001603030028"), record.getComputations() .getAuthenticatedMetaData().getValue()); assertArrayEquals( ArrayConverter .hexStringToByteArray("77D85417660273BBA5F220778CC117ECB7AAC7F46B0E07A8679215363031E912DA4494F0E8BEA216"), record.getComputations().getAuthenticatedNonMetaData().getValue()); assertArrayEquals(ArrayConverter.hexStringToByteArray("65B7DA726864D4184D75A549BF5C06AB20867846AF4434CC"), record.getComputations().getCipherKey().getValue()); assertArrayEquals( ArrayConverter .hexStringToByteArray("1400000CCE92FBEC9131F48A63FED31F71573F726479AA9108FB86A4FA16BC1D5CB5753003030303"), record.getComputations().getPlainRecordBytes().getValue()); assertArrayEquals( ArrayConverter .hexStringToByteArray("77D85417660273BBA5F220778CC117ECB7AAC7F46B0E07A8679215363031E912DA4494F0E8BEA216"), record.getComputations().getCiphertext().getValue()); assertArrayEquals( ArrayConverter .hexStringToByteArray("000000000000000077D85417660273BBA5F220778CC117ECB7AAC7F46B0E07A8679215363031E912DA4494F0E8BEA216DEA10FBB5AF87DF49E75EA206892A1A0"), record.getProtocolMessageBytes().getValue()); }