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

Make caller enforce invariants when setting AES encryption key #702

Merged
merged 1 commit into from
Oct 24, 2018

Conversation

ecstatic-morse
Copy link
Contributor

Resolves #113.

GFp_AES_set_encrypt_key can fail if and only if the following invariants are violated.

  • All pointer arguments must be non-null.
  • The key size must be either 128 or 256 bits (192 bit keys aren't supported).

The first invariant should not be checked at runtime (except via assertion) as it is the responsibility of the caller.

The second could be expressed statically by accepting an enum with the valid key lengths, but enums don't provide any type safety in C. Instead, we document the acceptable key lengths and make them the responsibility of the caller.

As a result of these changes, GFp_AES_set_encrypt_key (as well as GFp_aes_c_set_encrypt_key) no longer needs to return an error code. The assembly functions still return an error code and do input validation.

// anyway.
GFp_AES_set_encrypt_key(key, (unsigned)key_len * 8, &ks);
unsigned bits = key_len * 8;
if (bits != 128 && bits != 256) {
Copy link
Owner

Choose a reason for hiding this comment

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

Instead, let's compare key_len != 16 && key_len != 32 so we don't have to worry about any overflow issues with the multiplication.

}
rk += 4;
}
}

rk[4] = from_be_u32_ptr(key + 16);
rk[5] = from_be_u32_ptr(key + 20);
rk[6] = from_be_u32_ptr(key + 24);
rk[7] = from_be_u32_ptr(key + 28);
if (bits == 256) {
Copy link
Owner

Choose a reason for hiding this comment

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

Remove the if (bits == 256) { here and do this unconditionally.

@ecstatic-morse
Copy link
Contributor Author

ecstatic-morse commented Oct 11, 2018

If/when this gets merged, the equivalent error handling code should be removed from the assembly implementations.

Also, 192-bit key support was removed from the vectorized AES implementation but not the one using AES-NI.

I can open new issues for these if you like.

}
rk += 4;
}
}

// bits == 256
Copy link
Owner

@briansmith briansmith Oct 17, 2018

Choose a reason for hiding this comment

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

This should be assert(bits == 256);. That is, we prefer checked (at debug time at least) assertions to unchecked assertions.

@@ -172,8 +174,8 @@ mod tests {
}

extern "C" {
fn GFp_AES_set_encrypt_key(key: *const u8, bits: usize,
Copy link
Owner

Choose a reason for hiding this comment

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

We should have done this change as a separate commit. But, OK.

@briansmith
Copy link
Owner

LGTM! Thanks!

Please squash these commits together, change the comment to an assert(...). and add the "I agree..." message to the commit message.

@briansmith
Copy link
Owner

@ecstatic-morse Are you still interested in this? It would be great if you could make the small changes I requested in the PR soon. I want to refactor the C code (or, if you want, you can do so, in another PR!) to remove the duplication between the 128-bit case and the 256-bit case, and to replace the weird loop constructions with straightforward for loops. I'd prefer to merge this PR before making those changes so that I don't create a merge conflict for you that you'd have to resolve manually.

@ecstatic-morse ecstatic-morse force-pushed the return-convention branch 2 times, most recently from 2ec35ef to 69a6be1 Compare October 22, 2018 22:22
@ecstatic-morse
Copy link
Contributor Author

Sorry, life got in the way last week. I made the changes and squashed.

My plan was to start working on #660 and #705 tonight. Refactoring AES round key generation would be a nice warm up.

On a more meta note, I'm trying to get accustomed to the programming style here before I tackle more involved issues. If you have any suggestions for next steps, I'd love to hear them.

@ecstatic-morse
Copy link
Contributor Author

ecstatic-morse commented Oct 23, 2018

I refactored the C AES key expansion routines. I'll submit a PR when this gets merged.

#if defined(HWAES)
if (hwaes_capable()) {
return GFp_aes_hw_set_encrypt_key(user_key, bits, key);
GFp_aes_hw_set_encrypt_key(user_key, bits, key);
Copy link
Owner

Choose a reason for hiding this comment

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

Please prefix this with (void) to make it clear we're ignoring the return value intentionally.

@@ -149,14 +153,15 @@ int GFp_AES_set_encrypt_key(const uint8_t *user_key, unsigned bits,
#error "BSAES and VPAES are enabled at the same time, unexpectedly."
#endif
if (vpaes_capable()) {
return GFp_vpaes_set_encrypt_key(user_key, bits, key);
GFp_vpaes_set_encrypt_key(user_key, bits, key);
Copy link
Owner

Choose a reason for hiding this comment

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

Ditto: prefix with (void).

@briansmith
Copy link
Owner

Thanks for the quick turnaround @ecstatic-morse. I was just about to merge this but I noticed a couple of things: (1) We are missing a couple places where we should be using (void), and (2) You didn't add "I agree to license..." to the end of your commit message. Please update the commit with those changes and I'll merge ASAP.

Copy link
Owner

@briansmith briansmith left a comment

Choose a reason for hiding this comment

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

See the previous comment for the changes requested.

`GFp_AES_set_encrypt_key` can fail if and only if the following invariants
are violated.

* All pointer arguments must be non-null.
* The key size must be either 128 or 256 bits (192 bit keys aren't
supported).

The first invariant should not be checked at runtime (except via
assertion) as it is the responsibility of the caller.

The second could be expressed statically by accepting an enum with the
valid key lengths, but enums don't provide any type safety in C.
Instead, we document the acceptable key lengths and make them the
responsibility of the caller.

As a result of these changes, `GFp_AES_set_encrypt_key` (as well as
`GFp_aes_c_set_encrypt_key`) no longer needs to return an error code.
The assembly functions still return an error code and do input
validation.

This commit also corrects the signature of `GFp_AES_set_encrypt_key`.

I agree to license my contributions to each file under the terms given
at the top of each file I changed.
@ecstatic-morse
Copy link
Contributor Author

Whoops, sorry about that. I added the disclaimer to the commit message and made the requested changes.

Is the use (void) to explicitly ignore return values documented anywhere? I didn't see it in STYLE.md.

@briansmith briansmith merged commit 20cfa87 into briansmith:master Oct 24, 2018
@briansmith
Copy link
Owner

Thanks!

No, I guess it isn't mentioned in the style guide. One reason is that it is unusual for us to ignore return values in the first place. We're only doing so here temporarily until the types of those functions change to be void.

FWIW, I'd normally write (void)x instead of (void) x but NBD.

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.

2 participants