<div dir="ltr"><div><div><div>Hello everyone,<br><br>I apologize if this is not the right place so ask/report this. Please direct me to the correct place if it isn't.<br><br>I recently noticed that that the current javax.crypto.CipherInputStream implementation in OpenJDK 6/7/8 is insecure when AEAD modes are used, e.g. Cipher.getInstance("AES/GCM/NoPadding") with the BC provider. In particular, it is possible to tamper with the ciphertext -- without any exceptions being passed on to the application.<br>
<br></div>In an example at [1] (see "Test B"), I was able to decrypt an altered ciphertext to "Confirm 900$ pay" (original plaintext was "Confirm 100$ pay") by simply XORing the original ciphertext with 0x08 at index 8. The underlying GCM engine behaves correctly as "Test A" shows (a BadPaddingException "<span class=""></span><span class="">mac </span><span class="">check </span><span class="">in</span><span class=""> </span><span class="">GCM </span><span class="">failed</span>" is thrown), but the j.c.CipherInputStream simply ignores this exception in the close() method:<br>
<br>public void close() throws IOException {<br>...<br>  try {<br>    cipher.doFinal();<br>  }<br>  catch (BadPaddingException ex) {<br>     /// <<<<<< When GCM tag verification fails, a BadPaddingException is thrown<br>
     /// <<<<<< The CipherInputStream unfortunately ignores this exception!<br>  }<br>...<br>}<br><br></div>A discussion about this issue can be found in the Bouncy Castle mailing list [2], or in my blog post [3].<br>
<br>I hope I'm not the only one who thinks that this is a very serious security issue, because it gives developers a false sense of authenticated encryption -- where in fact at this stage AES/GCM is not better than AES/CTR when used with a CipherInputStream. I found this issue by chance, so there are probably many applications out there that are also vulnerable.<br>
<br></div><div>Current workaround: Bouncy Castle provides its own org.bouncycastle.crypto.io.CipherInputStream that (unfortunately) is also broken in v1.50, but will be fixed in 1.51. David Hook provided a fix [4] in response to the discussion; the full class can be found at [5].<br>
</div><div><br></div><div>Best,<br>Philipp<br></div><div><div><div><br>[1] <a href="https://github.com/binwiederhier/cipherinputstream-aes-gcm/blob/e9759ca71557e5d1da26ae72f6ce5aac918e34b0/src/CipherInputStreamIssuesTests.java#L89">https://github.com/binwiederhier/cipherinputstream-aes-gcm/blob/e9759ca71557e5d1da26ae72f6ce5aac918e34b0/src/CipherInputStreamIssuesTests.java#L89</a><br>
<div>[2] <a href="http://bouncycastle.org/devmailarchive/msg13615.html">http://bouncycastle.org/devmailarchive/msg13615.html</a><br>[3] <a href="http://blog.philippheckel.com/2014/03/01/cipherinputstream-for-aead-modes-is-broken-in-jdk7-gcm/">http://blog.philippheckel.com/2014/03/01/cipherinputstream-for-aead-modes-is-broken-in-jdk7-gcm/</a><br>
[4] <a href="https://github.com/bcgit/bc-java/commit/933119114c96f703d1303a3c77d9ac405091270d">https://github.com/bcgit/bc-java/commit/933119114c96f703d1303a3c77d9ac405091270d</a><br>[5] <a href="https://raw.github.com/bcgit/bc-java/933119114c96f703d1303a3c77d9ac405091270d/core/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java">https://raw.github.com/bcgit/bc-java/933119114c96f703d1303a3c77d9ac405091270d/core/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java</a><br>
</div></div></div></div></div>