### Question:
ChunkEncryptor { public EncryptedChunk encrypt(ChunkHash plaintextHash, byte[] plaintext) throws InvalidKeyException, IllegalBlockSizeException { byte[] nonce = generateNonce(); Cipher cipher; try { cipher = Cipher.getInstance(CIPHER_ALGORITHM); cipher.init( Cipher.ENCRYPT_MODE, mSecretKey, new GCMParameterSpec(GCM_TAG_LENGTH_BYTES * 8, nonce)); } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException e) { throw new AssertionError(e); } byte[] encryptedBytes; try { encryptedBytes = cipher.doFinal(plaintext); } catch (BadPaddingException e) { throw new AssertionError("Impossible: threw BadPaddingException in encrypt mode."); } return EncryptedChunk.create( plaintextHash, nonce, encryptedBytes); } ChunkEncryptor(SecretKey secretKey, SecureRandom secureRandom); EncryptedChunk encrypt(ChunkHash plaintextHash, byte[] plaintext);  }### Answer:
@Test public void encrypt_withHash_resultContainsHashAsKey() throws Exception { EncryptedChunk chunk = mChunkEncryptor.encrypt(mPlaintextHash, PLAINTEXT_BYTES); assertThat(chunk.key()).isEqualTo(mPlaintextHash); }
@Test public void encrypt_generatesHmacOfPlaintext() throws Exception { EncryptedChunk chunk = mChunkEncryptor.encrypt(mPlaintextHash, PLAINTEXT_BYTES); byte[] generatedHash = chunk.key().getHash(); Mac mac = Mac.getInstance(MAC_ALGORITHM); mac.init(mSecretKey); byte[] plaintextHmac = mac.doFinal(PLAINTEXT_BYTES); assertThat(generatedHash).isEqualTo(plaintextHmac); }
@Test public void encrypt_whenInvokedAgain_generatesNewNonce() throws Exception { EncryptedChunk chunk1 = mChunkEncryptor.encrypt(mPlaintextHash, PLAINTEXT_BYTES); EncryptedChunk chunk2 = mChunkEncryptor.encrypt(mPlaintextHash, PLAINTEXT_BYTES); assertThat(chunk1.nonce()).isNotEqualTo(chunk2.nonce()); }
@Test public void encrypt_whenInvokedAgain_generatesNewCiphertext() throws Exception { EncryptedChunk chunk1 = mChunkEncryptor.encrypt(mPlaintextHash, PLAINTEXT_BYTES); EncryptedChunk chunk2 = mChunkEncryptor.encrypt(mPlaintextHash, PLAINTEXT_BYTES); assertThat(chunk1.encryptedBytes()).isNotEqualTo(chunk2.encryptedBytes()); }
@Test public void encrypt_generates12ByteNonce() throws Exception { EncryptedChunk encryptedChunk = mChunkEncryptor.encrypt(mPlaintextHash, PLAINTEXT_BYTES); byte[] nonce = encryptedChunk.nonce(); assertThat(nonce).hasLength(GCM_NONCE_LENGTH_BYTES); }
@Test public void encrypt_decryptedResultCorrespondsToPlaintext() throws Exception { EncryptedChunk chunk = mChunkEncryptor.encrypt(mPlaintextHash, PLAINTEXT_BYTES); Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); cipher.init( Cipher.DECRYPT_MODE, mSecretKey, new GCMParameterSpec(GCM_TAG_LENGTH_BYTES * 8, chunk.nonce())); byte[] decrypted = cipher.doFinal(chunk.encryptedBytes()); assertThat(decrypted).isEqualTo(PLAINTEXT_BYTES); }