/** * Takes ciphertexts and decrypts it * * @param data correctly padded data * @return * @throws CryptoException */ public byte[] decrypt(byte[] data) throws CryptoException { try { byte[] plaintext; if (useExplicitIv) { decryptIv = new IvParameterSpec(Arrays.copyOf(data, decryptCipher.getBlockSize())); } if (tlsContext.getMyConnectionEnd() == ConnectionEnd.CLIENT) { decryptCipher.init( Cipher.DECRYPT_MODE, new SecretKeySpec(serverWriteKey, bulkCipherAlg.getJavaName()), decryptIv); } else { decryptCipher.init( Cipher.DECRYPT_MODE, new SecretKeySpec(clientWriteKey, bulkCipherAlg.getJavaName()), decryptIv); } if (useExplicitIv) { plaintext = decryptCipher.doFinal( Arrays.copyOfRange(data, decryptCipher.getBlockSize(), data.length)); } else { plaintext = decryptCipher.doFinal(data); decryptIv = new IvParameterSpec( Arrays.copyOfRange(data, data.length - decryptCipher.getBlockSize(), data.length)); } return plaintext; } catch (BadPaddingException | IllegalBlockSizeException | InvalidAlgorithmParameterException | InvalidKeyException | UnsupportedOperationException ex) { throw new CryptoException(ex); } }
public TlsRecordBlockCipher(TlsContext tlsContext) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException { this.tlsContext = tlsContext; ProtocolVersion protocolVersion = tlsContext.getProtocolVersion(); CipherSuite cipherSuite = tlsContext.getSelectedCipherSuite(); if (protocolVersion == ProtocolVersion.TLS11 || protocolVersion == ProtocolVersion.TLS12 || protocolVersion == ProtocolVersion.DTLS10 || protocolVersion == ProtocolVersion.DTLS12) { useExplicitIv = true; } bulkCipherAlg = BulkCipherAlgorithm.getBulkCipherAlgorithm(cipherSuite); CipherAlgorithm cipherAlg = AlgorithmResolver.getCipher(cipherSuite); int keySize = cipherAlg.getKeySize(); encryptCipher = Cipher.getInstance(cipherAlg.getJavaName()); decryptCipher = Cipher.getInstance(cipherAlg.getJavaName()); MacAlgorithm macAlg = AlgorithmResolver.getMacAlgorithm(cipherSuite); readMac = Mac.getInstance(macAlg.getJavaName()); writeMac = Mac.getInstance(macAlg.getJavaName()); int secretSetSize = (2 * keySize) + readMac.getMacLength() + writeMac.getMacLength(); if (!useExplicitIv) { secretSetSize += encryptCipher.getBlockSize() + decryptCipher.getBlockSize(); } byte[] masterSecret = tlsContext.getMasterSecret(); byte[] seed = tlsContext.getServerClientRandom(); PRFAlgorithm prfAlgorithm = AlgorithmResolver.getPRFAlgorithm( tlsContext.getProtocolVersion(), tlsContext.getSelectedCipherSuite()); byte[] keyBlock = PseudoRandomFunction.compute( prfAlgorithm, masterSecret, PseudoRandomFunction.KEY_EXPANSION_LABEL, seed, secretSetSize); LOGGER.debug("A new key block was generated: {}", ArrayConverter.bytesToHexString(keyBlock)); int offset = 0; byte[] clientMacWriteSecret = Arrays.copyOfRange(keyBlock, offset, offset + readMac.getMacLength()); offset += readMac.getMacLength(); LOGGER.debug( "Client MAC write Secret: {}", ArrayConverter.bytesToHexString(clientMacWriteSecret)); byte[] serverMacWriteSecret = Arrays.copyOfRange(keyBlock, offset, offset + writeMac.getMacLength()); offset += writeMac.getMacLength(); LOGGER.debug( "Server MAC write Secret: {}", ArrayConverter.bytesToHexString(serverMacWriteSecret)); clientWriteKey = Arrays.copyOfRange(keyBlock, offset, offset + keySize); offset += keySize; LOGGER.debug("Client write key: {}", ArrayConverter.bytesToHexString(clientWriteKey)); serverWriteKey = Arrays.copyOfRange(keyBlock, offset, offset + keySize); offset += keySize; LOGGER.debug("Server write key: {}", ArrayConverter.bytesToHexString(serverWriteKey)); byte[] clientWriteIv, serverWriteIv; if (useExplicitIv) { clientWriteIv = new byte[encryptCipher.getBlockSize()]; RandomHelper.getRandom().nextBytes(clientWriteIv); serverWriteIv = new byte[decryptCipher.getBlockSize()]; RandomHelper.getRandom().nextBytes(serverWriteIv); } else { clientWriteIv = Arrays.copyOfRange(keyBlock, offset, offset + encryptCipher.getBlockSize()); offset += encryptCipher.getBlockSize(); LOGGER.debug("Client write IV: {}", ArrayConverter.bytesToHexString(clientWriteIv)); serverWriteIv = Arrays.copyOfRange(keyBlock, offset, offset + decryptCipher.getBlockSize()); offset += decryptCipher.getBlockSize(); LOGGER.debug("Server write IV: {}", ArrayConverter.bytesToHexString(serverWriteIv)); } if (tlsContext.getMyConnectionEnd() == ConnectionEnd.CLIENT) { encryptIv = new IvParameterSpec(clientWriteIv); decryptIv = new IvParameterSpec(serverWriteIv); encryptKey = new SecretKeySpec(clientWriteKey, bulkCipherAlg.getJavaName()); decryptKey = new SecretKeySpec(serverWriteKey, bulkCipherAlg.getJavaName()); encryptCipher.init(Cipher.ENCRYPT_MODE, encryptKey, encryptIv); decryptCipher.init(Cipher.DECRYPT_MODE, decryptKey, decryptIv); readMac.init(new SecretKeySpec(serverMacWriteSecret, macAlg.getJavaName())); writeMac.init(new SecretKeySpec(clientMacWriteSecret, macAlg.getJavaName())); } else { decryptIv = new IvParameterSpec(clientWriteIv); encryptIv = new IvParameterSpec(serverWriteIv); // todo check if this correct??? encryptCipher.init( Cipher.ENCRYPT_MODE, new SecretKeySpec(serverWriteKey, bulkCipherAlg.getJavaName()), encryptIv); decryptCipher.init( Cipher.DECRYPT_MODE, new SecretKeySpec(clientWriteKey, bulkCipherAlg.getJavaName()), decryptIv); readMac.init(new SecretKeySpec(clientMacWriteSecret, macAlg.getJavaName())); writeMac.init(new SecretKeySpec(serverMacWriteSecret, macAlg.getJavaName())); } if (offset != keyBlock.length) { throw new CryptoException("Offset exceeded the generated key block length"); } // mac has to be put into one or more blocks, depending on the MAC/block // length // additionally, there is a need for one explicit IV block minimalEncryptedRecordLength = ((readMac.getMacLength() / decryptCipher.getBlockSize()) + 2) * decryptCipher.getBlockSize(); }