-
Notifications
You must be signed in to change notification settings - Fork 18k
crypto/cipher: GCM AEAD Open modifies ciphertext on failure #13886
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Probably https://golang.org/cl/10484 (efeeee3). /cc @vkrasnov I suspect swapping the order of lines 158--162 and 164--169 of crypto/aes/aes_gcm.go would restore compatibility with Go 1.5. (Edit: No, I'm wrong; it's not that simple.) |
Assuming I'm looking at the same code you're referring to, it looks like Open probably isn't modifying ciphertext per se, but that the caller is reusing the same memory as the dst argument and expecting Open to not modify dst if the MAC is invalid. Seemingly this is guaranteed by AEAD.Open's documentation:
It looks like the new AES-GCM code is appending data to dst even when unsuccessful. |
It was a design decision to not allow reusing the failed result or partial result, in case the MAC failed, we instead zero the output, to make the usage safer. The scenario where one might reuse ciphertext after failure (not on purpose), is exactly one we wanted to avoid. |
I appreciate the rationale but that decision has already been made
differently in Go 1.5, and that will break existing uses. It seems like we
should restore what Go 1.5 did.
|
That was my concern when I submited the patch. The code performs simultaneous decryption and authentication, and the alternative was to copy to a temp buffer. |
OK, well at the least we need to document the change in behavior. I'll take
care of that. Thanks.
|
The more serious issue I see, is that the non amd64 behavior is unchanged, and therefore the same version has different behavior for different architectures. |
My 2c: If we're going to accept the new behavior on amd64, we should change the generic GCM code to also zero out dst on MAC failures. |
Since the optimised code stitches together the decryption and authentication for performance, it needs to write the plaintext before it can check whether the authentication tag is correct. Thus, unlike the generic code, it cannot leave the destination buffer untouched in all failure cases. Since it has written plaintext that it knows is dangerous, zeroing out is, I think, I fair behaviour. However, it does still leave the destination buffer untouched in other failure cases so it's not the case that it'll always zero it out. BoringSSL does always zero it out but Go is different because it returns a slice and so I'm not immediately convinced that it needs to be the same. Given that, I think I would like to keep the AESNI behaviour to save a copy, and thus update the generic code to act the same. I'll write some changes to do this. |
CL https://golang.org/cl/18480 mentions this issue. |
CL https://golang.org/cl/18481 mentions this issue. |
This change documents the behaviour change caused by https://go-review.googlesource.com/18480 in Go 1.6. Updates #13886 Change-Id: I2daa08a62775bbc209f0f4cbeae21b8184ce7609 Reviewed-on: https://go-review.googlesource.com/18481 Reviewed-by: Russ Cox <rsc@golang.org>
Debugging a test failure. Have to stop for now but it looks like in Go 1.5 a failure during
NewGCM(block).Open(packet, nonce, ciphertext, data)
left nonce, ciphertext unchanged. But now in Go 1.6 it looks like they have been modified when the error is returned. Code that tried Open with successive possibilities for data used to be able to reuse the nonce, ciphertext for each call until one succeeded. Now it cannot.At the least this requires a note in the release notes. Perhaps the old behavior can be restored instead. Will look more later.
/cc @agl
The text was updated successfully, but these errors were encountered: