-
Notifications
You must be signed in to change notification settings - Fork 151
Implementation of XAES-256-GCM with EVP_CIPHER #2750
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
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clang-tidy made some suggestions
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## xaes-256-gcm #2750 +/- ##
================================================
+ Coverage 78.94% 79.03% +0.09%
================================================
Files 677 677
Lines 115525 114623 -902
Branches 16249 16261 +12
================================================
- Hits 91198 90592 -606
+ Misses 23530 23234 -296
Partials 797 797 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
…to xaes-256-gcm
crypto/fipsmodule/cipher/e_aes.c
Outdated
| out->ctx_size = sizeof(EVP_AES_GCM_CTX) + EVP_AES_GCM_CTX_PADDING | ||
| + sizeof(XAES_256_GCM_CTX); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this correct? why are we not storing everything in XAES_256_GCM_CTX?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is just style. Like I explained, I can declare a field of type EVP_AES_GCM_CTX inside XAES_256_GCM_CTX. Then, like in previous review, you require another function similar to aes_gcm_from_cipher_ctx to specify the start position of EVP_AES_GCM_CTX. Then I also have to see why a test case failed? Is that too cumbersome?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way I understand it is that it differs from the AEAD implementation in #2652 in that, here, in the EVP API, we want to be able to do multiple cipher calls (complete with a tag, not streaming) using the same derived key but new (second half?) IV. In the AEAD implementation, every "seal" or "open" operation had a new IV that derived a new key so the gcm context was temporary. So here, the cipher call is pointing to aes_gcm_cipher and uses a gcm context.
I think it would be clearer if that context were part of the xaes context as dkostic suggests.
On another note, can the interface take a half IV for GCM and not re-derive the key? Or I'm wrong in assuming that that use-case is implemented?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nebeid I have included EVP_AES_GCM_CTX inside XAES_256_GCM_CTX in the newest update. Please review again based on that. This will make the code longer since in EVP_AEAD implementation, XAES_256_GCM_CTX does not need EVP_AES_GCM_CTX inside. I will have to define another struct for AEAD case, then another aead_xaes_256_gcm_ctx_init(), which is totally the same as xaes_256_gcm_ctx_init(), but different by only one argument. Similarly for aead_xaes_256_gcm_CMAC_derive_key(), totally the same as xaes_256_gcm_CMAC_derive_key().
For your second question, currently it has not implemented yet since people have not agreed on that design. Furthermore, I tried to keep this PR as simple as possible for review. If that case is required, I'll fix and create another PR.
|
|
||
| // XAES-256-GCM Encryption | ||
| ASSERT_TRUE(EVP_CipherInit_ex(ctx.get(), nullptr, nullptr, key.data(), nonce.data(), -1)); | ||
| ASSERT_EQ(aad_len, EVP_Cipher(ctx.get(), nullptr, aad.data(), aad_len)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This assert is questionable.; it compares the return value of a function with the length of the aad. ASSERT_TRUE on the EVP_Cipher call is what I believe you intended.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I follow this: https://github.com/aws/aws-lc/blob/main/crypto/cipher_extra/cipher_test.cc#L258
Should I need to change it to ASSERT_TRUE instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the reference. I noticed this explanation
aws-lc/include/openssl/cipher.h
Lines 466 to 475 in 93f9f73
| // If |ctx|'s cipher has the |EVP_CIPH_FLAG_CUSTOM_CIPHER| flag, it runs in one | |
| // of two modes: If |in| is non-NULL, it behaves like |EVP_CipherUpdate|. If | |
| // |in| is NULL, it behaves like |EVP_CipherFinal_ex|. In both cases, it returns | |
| // |*out_len| on success and -1 on error. | |
| // | |
| // WARNING: The two possible calling conventions of this function signal errors | |
| // incompatibly. In the first, zero indicates an error. In the second, zero | |
| // indicates success with zero bytes of output. | |
| OPENSSL_EXPORT int EVP_Cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, | |
| const uint8_t *in, size_t in_len); |
crypto/test/test_util.h
Outdated
| // hexdump writes |msg| to |fp| followed by the hex encoding of |len| bytes | ||
| // from |in|. | ||
| void hexdump(FILE *fp, const char *msg, const void *in, size_t len); | ||
| bool ConvertToBytes(std::vector<uint8_t> *out, const std::string &value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I should have realised that you could probably use DecodeHex instead of exposing this function. It's used for example in
aws-lc/crypto/fipsmodule/evp/evp_ctx_test.cc
Line 413 in d826708
| DecodeHex(&raw_key, hmac_hexkey); |
| int len = 0; | ||
| ASSERT_TRUE(EVP_CipherFinal_ex(ctx.get(), ciphertext.data() + ciphertext_len, &len)); | ||
| ciphertext_len += len; | ||
| ASSERT_TRUE(EVP_DigestUpdate(d.get(), ciphertext.data(), ciphertext_len)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This accumulation is necessary to match the final result in that linked file, right?
| test(plaintext, strlen((const char *)plaintext), ciphertext, tag); | ||
| } | ||
|
|
||
| // Source of multi-loop tests: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see tests for the following usecases, unless you're planning on doing them in a subsequent PR (or point me to them if I missed them):
- Are there KATs (known-answer tests) that test the streaming API, i.e. calling CipherUpdate multiple times?
- are the shorter nonces tested at least with a self-consistency test, i.e. we can decrypt what we encrypt?
nebeid
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Pending CI)
Issues:
Description of Changes
Implementation for API EVP_CIPHER of XAES-256-GCM is appended to e_aes.c, and the tests are appended to cipher_test.cc.
Testing
We use the test vectors provided here:
https://github.com/C2SP/C2SP/blob/main/XAES-256-GCM.md
https://github.com/C2SP/C2SP/blob/main/XAES-256-GCM/openssl/openssl.c
https://github.com/C2SP/C2SP/blob/main/XAES-256-GCM/go/XAES-256-GCM_test.go
Evaluation
Performance evaluation with speedtool:

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license and the ISC license.