-
Notifications
You must be signed in to change notification settings - Fork 44
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
Implement constant time AES CBC #14
Conversation
ctaes.h
Outdated
@@ -38,4 +38,7 @@ void AES256_init(AES256_ctx* ctx, const unsigned char* key32); | |||
void AES256_encrypt(const AES256_ctx* ctx, size_t blocks, unsigned char* cipher16, const unsigned char* plain16); | |||
void AES256_decrypt(const AES256_ctx* ctx, size_t blocks, unsigned char* plain16, const unsigned char* cipher16); | |||
|
|||
void AES_encrypt(const AES_state* rounds, int nrounds, unsigned char* cipher16, const unsigned char* plain16); | |||
void AES_decrypt(const AES_state* rounds, int nrounds, unsigned char* plain16, const unsigned char* cipher16); |
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.
nit: perhaps better to declare these in the -cbc.c
, as I take it's not a part of the public interface.
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 could also be avoided by just merging this into ctaes.c, as it's a tiny amount of code, so I doubt any user would care. Having them in the same module may also enable better interprocedural optimization.
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 looks very good. I'm very sorry I didn't notice this earlier (or maybe I did, and forgot).
I can't expect you're still interested in this after all this time, so if you aren't, or I don't get a response here, I'll address the comments myself.
ctaes-cbc.c
Outdated
unsigned char buf[16]; | ||
|
||
for (i = 0; i < blocks; i++) { | ||
for (j = 0; j < 16; j++) { |
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 could use memcpy
.
ctaes-cbc.c
Outdated
} | ||
Xor128(buf, iv); | ||
AES_encrypt(rounds, nk, encrypted, buf); | ||
for (j = 0; j < 16; j++) { |
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.
Use memcpy
.
ctaes-cbc.c
Outdated
uint8_t next_iv[16]; | ||
|
||
for (i = 0; i < blocks; i++) { | ||
for (j = 0; j < 16; j++) { |
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.
memcpy
.
ctaes-cbc.c
Outdated
} | ||
AES_decrypt(rounds, nk, plain, encrypted); | ||
Xor128(plain, iv); | ||
for (j = 0; j < 16; j++) { |
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.
memcpy
.
ctaes-cbc.c
Outdated
void AES128_CBC_init(AES128_CBC_ctx* ctx, const unsigned char* key16, const uint8_t* iv) { | ||
size_t i; | ||
AES128_init(&(ctx->ctx), key16); | ||
for (i = 0; i < 16; i++) { |
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.
memcpy
.
ctaes-cbc.c
Outdated
void AES192_CBC_init(AES192_CBC_ctx* ctx, const unsigned char* key16, const uint8_t* iv) { | ||
size_t i; | ||
AES192_init(&(ctx->ctx), key16); | ||
for (i = 0; i < 16; i++) { |
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.
memcpy
.
ctaes-cbc.c
Outdated
void AES256_CBC_init(AES256_CBC_ctx* ctx, const unsigned char* key16, const uint8_t* iv) { | ||
size_t i; | ||
AES256_init(&(ctx->ctx), key16); | ||
for (i = 0; i < 16; i++) { |
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.
memcpy
.
ctaes-cbc.h
Outdated
|
||
typedef struct { | ||
AES128_ctx ctx; | ||
uint8_t iv[16]; |
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.
Perhaps document that this isn't exactly the IV (after the first block, it's the carried-forward previous ciphertext).
ctaes.h
Outdated
@@ -38,4 +38,7 @@ void AES256_init(AES256_ctx* ctx, const unsigned char* key32); | |||
void AES256_encrypt(const AES256_ctx* ctx, size_t blocks, unsigned char* cipher16, const unsigned char* plain16); | |||
void AES256_decrypt(const AES256_ctx* ctx, size_t blocks, unsigned char* plain16, const unsigned char* cipher16); | |||
|
|||
void AES_encrypt(const AES_state* rounds, int nrounds, unsigned char* cipher16, const unsigned char* plain16); | |||
void AES_decrypt(const AES_state* rounds, int nrounds, unsigned char* plain16, const unsigned char* cipher16); |
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 could also be avoided by just merging this into ctaes.c, as it's a tiny amount of code, so I doubt any user would care. Having them in the same module may also enable better interprocedural optimization.
2890e41
to
4cb6dcc
Compare
Addressed review comments. |
Just remembered why I choose to not use |
Yeah, memcpy is C89, so it should be ~everywhere. It may also be easier to optimize for the compiler (using something faster than byte per byte copy). Any reason to keep the CBC tests in a separate file? |
It's not only about availability, if libc is implemented correct way, linker will not need to add code of unused functions in a final executable, so any extra function may increase size. I've done some embedded programming in the past, where sometimes every byte counts, so that thinking by default is from there. :) But memcpy is actually used by a lot of other libc stuff itself, so likely will be in almost any piece of software anyway.
Guess not. Will move them to |
Done. |
ctaes.h
Outdated
@@ -26,6 +26,21 @@ typedef struct { | |||
AES_state rk[15]; | |||
} AES256_ctx; | |||
|
|||
typedef struct { | |||
AES128_ctx ctx; | |||
uint8_t iv[16]; // iv is updated after each use |
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.
Please use /* */
comments (//
only exists in C++ and C99+).
test.c
Outdated
@@ -101,6 +129,51 @@ int main(void) { | |||
fail++; | |||
} | |||
} | |||
for (i = 0; i < sizeof(ctaes_cbc_tests) / sizeof(ctaes_cbc_tests[0]); i++) { | |||
const ctaes_cbc_test* test = &ctaes_cbc_tests[i]; | |||
unsigned char key[32], iv[16], plain[test->nblocks * 16], cipher[test->nblocks * 16], ciphered[test->nblocks * 16], deciphered[test->nblocks * 16]; |
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.
No VLAs in C89.
Generally looks good-- just the C99isms need to be fixed otherwise I think it's good to go, thanks for submitting this! |
Addressed additional review comments. Tested compiling tests with |
ACK 8835446 |
1 similar comment
ACK 8835446 |
I just realized that AES-CBC in practice also includes a padding scheme, and as that e.g. needs to be checked in constant time, it seems appropriate to also have that implemented here. Unfortunately, it doesn't quite match the API implemented here very well. The problem is that if the padding is incorrect, the decryption has to be rejected, which doesn't work well with a mutable state that lets you decrypt initial blocks before checking the padding. In case where the amount of data is large, and you want to use it in a streaming fashion, there is little that can be done about that, but I'm not sure there is a need for that. Instead, there could just be a function that takes a @kristapsk Are you interested in tackling that as well, or would you like me to do that instead? |
Before, the submodule pointed to https://github.com/digitalbitbox/ctaes/tree/cbc, which was a re-host of bitcoin-core/ctaes#14 before it was merged. It has since been merged. https://github.com/digitalbitbox/ctaes/tree/master is now at 8012b062ea4931f10cc2fd2075fddc3782a57ee4, which is up to date with upstream https://github.com/bitcoin-core/ctaes. The submodule is updated to this commit revision.
Tried to not change anything in existing code, except for making
AES_encrypt()
andAES_decrypt()
public.Related to #11.