Skip to content
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

Merged
merged 1 commit into from
Aug 18, 2020
Merged

Implement constant time AES CBC #14

merged 1 commit into from
Aug 18, 2020

Conversation

kristapsk
Copy link
Contributor

Tried to not change anything in existing code, except for making AES_encrypt() and AES_decrypt() public.

Related to #11.

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);
Copy link

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.

Copy link
Contributor

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.

Copy link
Contributor

@sipa sipa left a 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++) {
Copy link
Contributor

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++) {
Copy link
Contributor

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++) {
Copy link
Contributor

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++) {
Copy link
Contributor

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++) {
Copy link
Contributor

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++) {
Copy link
Contributor

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++) {
Copy link
Contributor

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];
Copy link
Contributor

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);
Copy link
Contributor

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.

@kristapsk
Copy link
Contributor Author

Addressed review comments.

@kristapsk
Copy link
Contributor Author

Just remembered why I choose to not use memcpy() back then - didn't want to introduce dependency on additional libc function and string.h. But it doesn't matter actually, as it is hard to think about any piece of software that will use this and not memcpy() anywhere.

@sipa
Copy link
Contributor

sipa commented Aug 15, 2020

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?

@kristapsk
Copy link
Contributor Author

kristapsk commented Aug 15, 2020

memcpy is C89, so it should be ~everywhere.

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.

Any reason to keep the CBC tests in a separate file?

Guess not. Will move them to test.c.

@kristapsk
Copy link
Contributor Author

Guess not. Will move them to test.c.

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
Copy link
Contributor

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];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No VLAs in C89.

@gmaxwell
Copy link
Contributor

Generally looks good-- just the C99isms need to be fixed otherwise I think it's good to go, thanks for submitting this!

@kristapsk
Copy link
Contributor Author

Addressed additional review comments. Tested compiling tests with --std=c89 -Wall.

@sipa
Copy link
Contributor

sipa commented Aug 18, 2020

ACK 8835446

1 similar comment
@gmaxwell
Copy link
Contributor

ACK 8835446

@sipa sipa merged commit a1caf29 into bitcoin-core:master Aug 18, 2020
@sipa sipa mentioned this pull request Aug 18, 2020
sipa added a commit that referenced this pull request Aug 18, 2020
f0177f2 Reinstate endif comment (Pieter Wuille)

Pull request description:

  This was inadvertently removed in #14.

Top commit has no ACKs.

Tree-SHA512: dafed550a7ddfaff331473b5469781247ea34bbcd7060bab71047dcb76665bd2e64498552e02882ffef41b955294ef5c3d3d6203c7252155728ffb746963b39d
@sipa sipa mentioned this pull request Aug 18, 2020
@sipa
Copy link
Contributor

sipa commented Aug 18, 2020

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 const AES<n>_ctx , and an input and an output byte array, and does the whole thing at once.

@kristapsk Are you interested in tackling that as well, or would you like me to do that instead?

benma added a commit to benma/bitbox02-firmware that referenced this pull request Jun 12, 2022
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants