RecordAEADCipher extends RecordCipher { @Override public void decrypt(Record record) throws CryptoException { LOGGER.debug("Decrypting Record"); record.getComputations().setCipherKey(getKeySet().getReadKey(context.getChooser().getConnectionEndType())); byte[] protocolBytes = record.getProtocolMessageBytes().getValue(); DecryptionParser parser = new DecryptionParser(0, protocolBytes); byte[] explicitNonce = parser.parseByteArrayField(aeadExplicitLength); record.getComputations().setExplicitNonce(explicitNonce); explicitNonce = record.getComputations().getExplicitNonce().getValue(); byte[] salt = getKeySet().getReadIv(context.getConnection().getLocalConnectionEndType()); record.getComputations().setAeadSalt(salt); salt = record.getComputations().getAeadSalt().getValue(); byte[] cipherTextOnly = parser.parseByteArrayField(parser.getBytesLeft() - aeadTagLength); record.getComputations().setCiphertext(cipherTextOnly); record.getComputations().setAuthenticatedNonMetaData(record.getComputations().getCiphertext().getValue()); byte[] additionalAuthenticatedData = collectAdditionalAuthenticatedData(record, context.getChooser() .getSelectedProtocolVersion()); record.getComputations().setAuthenticatedMetaData(additionalAuthenticatedData); additionalAuthenticatedData = record.getComputations().getAuthenticatedMetaData().getValue(); LOGGER.debug("Decrypting AEAD with the following AAD: {}", ArrayConverter.bytesToHexString(additionalAuthenticatedData)); byte[] gcmNonce = ArrayConverter.concatenate(salt, explicitNonce); if (version.isTLS13() || bulkCipherAlg == BulkCipherAlgorithm.CHACHA20_POLY1305) { gcmNonce = preprocessIv(record.getSequenceNumber().getValue().longValue(), gcmNonce); } record.getComputations().setGcmNonce(gcmNonce); gcmNonce = record.getComputations().getGcmNonce().getValue(); LOGGER.debug("Decrypting AEAD with the following IV: {}", ArrayConverter.bytesToHexString(gcmNonce)); byte[] authenticationTag = parser.parseByteArrayField(parser.getBytesLeft()); record.getComputations().setAuthenticationTag(authenticationTag); authenticationTag = record.getComputations().getAuthenticationTag().getValue(); try { byte[] plainRecordBytes = decryptCipher.decrypt(gcmNonce, aeadTagLength * Bits.IN_A_BYTE, additionalAuthenticatedData, ArrayConverter.concatenate(cipherTextOnly, authenticationTag)); record.getComputations().setAuthenticationTagValid(true); record.getComputations().setPlainRecordBytes(plainRecordBytes); plainRecordBytes = record.getComputations().getPlainRecordBytes().getValue(); if (version.isTLS13()) { int numberOfPaddingBytes = countTrailingZeroBytes(plainRecordBytes); if (numberOfPaddingBytes == plainRecordBytes.length) { LOGGER.warn("Record contains ONLY padding and no content type. Setting clean bytes == plainbytes"); record.setCleanProtocolMessageBytes(plainRecordBytes); return; } parser = new DecryptionParser(0, plainRecordBytes); byte[] cleanBytes = parser.parseByteArrayField(plainRecordBytes.length - numberOfPaddingBytes - 1); byte[] contentType = parser.parseByteArrayField(1); byte[] padding = parser.parseByteArrayField(numberOfPaddingBytes); record.getComputations().setPadding(padding); record.setCleanProtocolMessageBytes(cleanBytes); record.getComputations().setPadding(cleanBytes); record.setContentType(contentType[0]); record.setContentMessageType(ProtocolMessageType.getContentType(contentType[0])); } else { record.setCleanProtocolMessageBytes(plainRecordBytes); } } catch (CryptoException E) { LOGGER.warn("Tag invalid", E); record.getComputations().setAuthenticationTagValid(false); throw new CryptoException(E); } } 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 testDecryptGcmServer() 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.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("000000000000000077D85417660273BBA5F220778CC117ECB7AAC7F46B0E07A8679215363031E912DA4494F0E8BEA216DEA10FBB5AF87DF49E75EA206892A1A0"); cipher = new RecordAEADCipher(context, keySet); Record record = new Record(); record.setContentType(ProtocolMessageType.HANDSHAKE.getValue()); record.prepareComputations(); record.setSequenceNumber(new BigInteger("0")); record.setProtocolMessageBytes(data); record.setProtocolVersion(ProtocolVersion.TLS12.getValue()); cipher.decrypt(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("1400000CCE92FBEC9131F48A63FED31F71573F726479AA9108FB86A4FA16BC1D5CB5753003030303"), record.getCleanProtocolMessageBytes().getValue()); }
@Test public void testDecryptGcmClient() throws NoSuchAlgorithmException, CryptoException { context.setConnection(new OutboundConnection()); 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("000000000000000077D85417660273BBA5F220778CC117ECB7AAC7F46B0E07A8679215363031E912DA4494F0E8BEA216DEA10FBB5AF87DF49E75EA206892A1A0"); cipher = new RecordAEADCipher(context, keySet); Record record = new Record(); record.setContentType(ProtocolMessageType.HANDSHAKE.getValue()); record.prepareComputations(); record.setSequenceNumber(new BigInteger("0")); record.setProtocolMessageBytes(data); record.setProtocolVersion(ProtocolVersion.TLS12.getValue()); cipher.decrypt(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("1400000CCE92FBEC9131F48A63FED31F71573F726479AA9108FB86A4FA16BC1D5CB5753003030303"), record.getCleanProtocolMessageBytes().getValue()); }