AesEaxJce implements Aead { @SuppressWarnings("InsecureCryptoUsage") @Override public byte[] decrypt(final byte[] ciphertext, final byte[] associatedData) throws GeneralSecurityException { int plaintextLength = ciphertext.length - ivSizeInBytes - TAG_SIZE_IN_BYTES; if (plaintextLength < 0) { throw new GeneralSecurityException("ciphertext too short"); } Cipher ecb = localEcbCipher.get(); ecb.init(Cipher.ENCRYPT_MODE, keySpec); byte[] n = omac(ecb, 0, ciphertext, 0, ivSizeInBytes); byte[] aad = associatedData; if (aad == null) { aad = new byte[0]; } byte[] h = omac(ecb, 1, aad, 0, aad.length); byte[] t = omac(ecb, 2, ciphertext, ivSizeInBytes, plaintextLength); byte res = 0; int offset = ciphertext.length - TAG_SIZE_IN_BYTES; for (int i = 0; i < TAG_SIZE_IN_BYTES; i++) { res = (byte) (res | (ciphertext[offset + i] ^ h[i] ^ n[i] ^ t[i])); } if (res != 0) { throw new AEADBadTagException("tag mismatch"); } Cipher ctr = localCtrCipher.get(); ctr.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(n)); return ctr.doFinal(ciphertext, ivSizeInBytes, plaintextLength); } @SuppressWarnings("InsecureCryptoUsage")  AesEaxJce(final byte[] key, int ivSizeInBytes); @SuppressWarnings("InsecureCryptoUsage") @Override byte[] encrypt(final byte[] plaintext, final byte[] associatedData); @SuppressWarnings("InsecureCryptoUsage") @Override byte[] decrypt(final byte[] ciphertext, final byte[] associatedData);  }
@Test public void testWycheproofVectors() throws Exception { JSONObject json = WycheproofTestUtil.readJson("../wycheproof/testvectors/aes_eax_test.json"); int errors = 0; int cntSkippedTests = 0; JSONArray testGroups = json.getJSONArray("testGroups"); for (int i = 0; i < testGroups.length(); i++) { JSONObject group = testGroups.getJSONObject(i); int keySize = group.getInt("keySize"); int ivSize = group.getInt("ivSize"); JSONArray tests = group.getJSONArray("tests"); if (!Arrays.asList(keySizeInBytes).contains(keySize / 8) || !Arrays.asList(ivSizeInBytes).contains(ivSize / 8)) { cntSkippedTests += tests.length(); continue; } for (int j = 0; j < tests.length(); j++) { JSONObject testcase = tests.getJSONObject(j); String tcId = String.format( "testcase %d (%s)", testcase.getInt("tcId"), testcase.getString("comment")); byte[] iv = Hex.decode(testcase.getString("iv")); byte[] key = Hex.decode(testcase.getString("key")); byte[] msg = Hex.decode(testcase.getString("msg")); byte[] aad = Hex.decode(testcase.getString("aad")); byte[] ct = Hex.decode(testcase.getString("ct")); byte[] tag = Hex.decode(testcase.getString("tag")); byte[] ciphertext = Bytes.concat(iv, ct, tag); String result = testcase.getString("result"); try { AesEaxJce eax = new AesEaxJce(key, iv.length); byte[] decrypted = eax.decrypt(ciphertext, aad); boolean eq = TestUtil.arrayEquals(decrypted, msg); if (result.equals("invalid")) { System.out.printf( "FAIL %s: accepting invalid ciphertext, cleartext: %s, decrypted: %s%n", tcId, Hex.encode(msg), Hex.encode(decrypted)); errors++; } else { if (!eq) { System.out.printf( "FAIL %s: incorrect decryption, result: %s, expected: %s%n", tcId, Hex.encode(decrypted), Hex.encode(msg)); errors++; } } } catch (GeneralSecurityException ex) { if (result.equals("valid")) { System.out.printf("FAIL %s: cannot decrypt, exception %s%n", tcId, ex); errors++; } } } } System.out.printf("Number of tests skipped: %d", cntSkippedTests); assertEquals(0, errors); }