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

Add AES encrypt/decrypt example #492

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

Firstyear
Copy link
Contributor

This adds an example of how to use AES-128-CBC encryption and decryption with a TPM.

@Firstyear
Copy link
Contributor Author

Please note there are two comments in the code that we should probably discuss. First is exposing the AES block size from the AesKeyBits enum. The second is if we should add pkcs7 padding to the crate to prevent people from "rolling their own".

Copy link
Member

@ionut-arm ionut-arm left a 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 effort of putting these examples together!

tss-esapi/examples/aes_encrypt_decrypt.rs Outdated Show resolved Hide resolved
Comment on lines 90 to 93
// REVIEW NOTE: Tss-esapi likely should expose these as constants from AesKeyBits::Aes128
// to prevent ambiguity!
const AES_BLOCK_SIZE: usize = 16;
Copy link
Member

Choose a reason for hiding this comment

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

I agree that we need to expose this constant from somewhere in the code (and I'd welcome it as a separate commit in this PR!), but I disagree it should have anything to do with AesKeyBits because the block size for AES is not tied to key size.

Given that this would be an addition to what the spec provides, the abstraction module would probably be the best place to have it, perhaps as a method on this. But I wouldn't be opposed to also adding it as a method on SymmetricCipherParameters, for example. We just need to figure out what that method should return for Xor and Null, and document them.

See comment below.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Wait what? I thought that block size was tied to the AESKeyBit size? IE AES-128 requires a 128bit key and a 16 byte block, where AES-256 requires a 256 bit key and a 32 byte block? I'm happy to be wrong, but all my other experience with openssl etc has the above assumptions enshrined.

Copy link
Member

@ionut-arm ionut-arm Feb 20, 2024

Choose a reason for hiding this comment

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

See NIST FIPS 197, paragraph three of section 1, first paragraph of section 3.1 ... Rijndael accepts different block sizes, but AES does not.

I'm not that great at digging through OpenSSL docs, the best I found was this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ahhh yes, it's related to cipher selection not key. Maybe it should be on https://docs.rs/tss-esapi/latest/tss_esapi/interface_types/algorithm/enum.SymmetricMode.html or https://docs.rs/tss-esapi/latest/tss_esapi/interface_types/algorithm/enum.SymmetricAlgorithm.html 🤔

AES-GCM makes it tricky since it's block size is 1, but I think the way we have the parameters laid out we need the SymmetricMode + Key to really know what the block size is.

Copy link
Member

Choose a reason for hiding this comment

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

I'm not actually sure if in the context of TPMs the same applies. I've skimmed a bit through the spec, couldn't find much, I'll need to test it.

Comment on lines 94 to 95
// REVIEW NOTE: Should we added PKCS7 padding as a function to MaxBuffer to prevent
// people needing to "roll their own"?
Copy link
Member

Choose a reason for hiding this comment

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

Yeah, agree, that would be good to have! But again, this seems like an abstraction kind of thing, perhaps it could go in the Cipher module - something like PaddedBuffer? We can then reference these new handy features in the documentation for the encryption/decryption methods, and, of course, in this example.

Actually, it strikes me that we could (maybe even should) offload these details to the cipher RustCrypto traits. For example if we allow Block, or a vector of Blocks, to be converted to MaxBuffer, then padding is free for us, and we can easily get the block size. This could be a first step towards tighter integration with those traits.

What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I think that's a good idea. But I suspect that is it's own PR?

Still even so, this example has highlighted a few places the api we have can be better :)

Copy link
Member

Choose a reason for hiding this comment

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

Having that as its own PR makes sense! And we can update this example when that's pushed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not even sure we'd need that since https://docs.rs/block-padding/0.3.2/block_padding/struct.Pkcs7.html already has .as_slice and we have https://docs.rs/tss-esapi/latest/tss_esapi/structures/struct.MaxBuffer.html#impl-TryFrom%3C%26%5Bu8%5D%3E-for-MaxBuffer

So we could just swap the padding process here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, reading that API it seems to be really limited and complex.

We would need to take the array of bytes, then iterate over it as chunks exact with https://doc.rust-lang.org/std/slice/struct.ChunksExact.html to match the block size.

We need this because we need to check the remainder case. If the remainder is empty, we need to append another block because pkcs7 always pads to avoid ambiguity. So that means we can't just look at the vec and grow it if needed, we have to clone the full input everytime because blocks are effectively an array.

And then a vec of generic array can't do to_slice, so we have to iterate again to make a new vec that we can try_from for max_buffer.

So unless I'm really overlooking something obvious, this seems like a really rough api to want to interface with.

@Firstyear Firstyear force-pushed the 20240203-aes-encrypt-decrypt-example branch from afdff20 to ad678ed Compare February 20, 2024 03:17
@Superhepper
Copy link
Collaborator

Have you forgot to sign the commits?

@Firstyear
Copy link
Contributor Author

Have you forgot to sign the commits?

Very likely :) But it wasn't ready to merge yet either.

Firstyear added 3 commits May 1, 2024 15:19
This adds an example of how to use AES-128-CBC encryption and decryption with a TPM.

Signed-off-by: William Brown <william.brown@suse.com>
@Firstyear Firstyear force-pushed the 20240203-aes-encrypt-decrypt-example branch from ad678ed to 32a3338 Compare May 1, 2024 05:28
@Firstyear
Copy link
Contributor Author

Okay, I've rebased an updated to latest main. I think that pkcs7/padding is "out of scope" for this crate, and I'm going to make an example of exposing the TPM via rust-crypto interfaces so we can inherit their padding options. I'll hopefully have this example "converted" shortly as a POC.

@Firstyear
Copy link
Contributor Author

This has finally come up again so I should be looping back to improve this shortly :)

}

impl<'a> cipher::BlockBackend for TpmEnc<'a> {
fn proc_block(&mut self, mut block: cipher::inout::InOut<'_, '_, cipher::Block<Self>>) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I guess InOut needs to be added here 🙄

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