Closed hargoniX closed 4 years ago
sounds like a good and interesting idea to me! a couple of thoughts:
which definitely results in an interesting balance of requirements for an API ^_^ i suspect a trait for symmetric enc/dec and a trait for each of asymmetric enc/dec and sign/verify might be a useful path, and enums for the algorithm type might be a reasonable midpoint for compile time decision making without encoding every supported algorithm in the API.
Your suggested path definitely sound reasonable to me. However especially the symmetric part would probably require a bit more than just encrypt() and decrypt() as symmetric cryptography also sometimes (but not always) requires an initialization vector additionally to the normal parameters.
The RustCrypto organization has already published a few traits with generic traits for different cipher types. I think it would be worthwhile to collaborate with @newpavlov to make these traits usable on embedded devices.
I'll take a quick look at the relevant traits they've designed so far:
block-cipher-trait
's BlockCipher
pub trait BlockCipher: Sized {
type KeySize: ArrayLength<u8>;
type BlockSize: ArrayLength<u8>;
type ParBlocks: ArrayLength<GenericArray<u8, Self::BlockSize>>;
fn new(key: &GenericArray<u8, Self::KeySize>) -> Self;
fn encrypt_block(&self, block: &mut GenericArray<u8, Self::BlockSize>);
fn decrypt_block(&self, block: &mut GenericArray<u8, Self::BlockSize>);
}
A problem with this one is that it requires you to provide a constructor method, which is impossible on embedded, where the block cipher functionality is provided by a peripheral that only exists once. I did open an issue about this a while ago (https://github.com/RustCrypto/traits/issues/30), but the currently published version doesn't seem to contain a fix.
stream-cipher
's (Sync)StreamCipher
and NewStreamCipher
Here the constructor is in a different trait NewStreamCipher
, which is good, but unfortunately it doesn't look like there's a way to configure the key/nonce except through that trait, which needs to create a cipher object from nothing.
This crate might not be super useful for embedded since "real" stream ciphers are rarely hardware-accelerated AFAICT.
block-modes
's BlockMode
traitpub trait BlockMode<C: BlockCipher, P: Padding>: Sized {
fn new(
cipher: C,
iv: &GenericArray<u8, <C as BlockCipher>::BlockSize>
) -> Self;
fn encrypt_blocks(
&mut self,
blocks: &mut [GenericArray<u8, <C as BlockCipher>::BlockSize>]
);
fn decrypt_blocks(
&mut self,
blocks: &mut [GenericArray<u8, <C as BlockCipher>::BlockSize>]
);
}
This has the same problem BlockCipher
has, where the constructor is a required method of this trait and is assumed to create a new object from scratch.
If the constructor was factored out, a way to reset an existing BlockMode
, giving it a new key and IV is still missing, but perhaps this would still be useful for embedded.
I am definitely interested in making RustCrypto traits more embedded-friendly! For signature traits check out @tarcieri's work in RustCrypto/signatures.
Regarding the constructor method problem, as was written in the issue I think one solution is to make "fake" constructor, which will acquire ownership over global resource. And Drop
implementation will release this resource back. To make things nicer we can add try_new
methods, which will be able to return an error in case if global resource was already locked and not freed yet.
Unfortunately that would require storing additional data in RAM. Even if it's just one byte, there's also the logic in new
and Drop
that needs to check that and potentially do unsafe
logic. That's not a very appealing solution.
I'd really prefer to separate object creation from actually performing operations on an already existing object (I believe that's considered good style anyways).
Hello! I'm very much interested in embedded cryptography in Rust 😉
As it were, there's an application open for a Rust Cryptography WG, with a proposed goal of creating a set of crates in the spirit of embedded-hal
which contain just the sorts of traits being proposed here:
https://github.com/rust-lang/wg-governance/issues/12
As @newpavlov mentioned I've done some work in https://github.com/RustCrypto/signatures with some initial abstractions for the signing use case. In particular these are intended to be common abstractions useful for software or hardware signers (I'm presently using them with a YubiHSM2).
All of the traits being worked on under https://github.com/RustCrypto/signatures designed to support no_std
use cases, in addition to hardware-backed signers. I would love to try using them with e.g. some of the cryptographic functionality in the MCUs I'm presently using (e.g. SAMD51, SAML11) and may have some use cases for that soon.
I'd really prefer to separate object creation from actually performing operations on an already existing object (I believe that's considered good style anyways).
A quick note on the signature
crate: it uses entirely object safe traits for signing and verifying, and right now has no common trait for constructors:
https://docs.rs/signature/latest/signature/trait.Signer.html https://docs.rs/signature/latest/signature/trait.Verifier.html
Regarding the predefined constructor convention I agree with @jonas-schievink. I am not aware of any current embedded hal trait which enforces a certain constructor signature which is presumably due to the idea/principle of not being too device specific as different hardware might require different arguments. So IMHO going with the style used in the signature crate and figuring out some way to also get this to work with other common cryptographic concepts would be the best way to go .
Any particular reason this was closed? I hope the recent releases of the RustCrypto traits have addressed the issues brought up in this thread.
I'll also note the next release of the ecdsa
crate will have SignPrimitive
and VerifyPrimitive
traits which may be useful for hardware ECDSA accelerators.
Judging from your Oxidize talk I concluded that the RustCrypto traits can (or are at least supposed to be) easily adoptable to Hardware Crypto so I dont think embedded-hal is the proper place to discuss this topic anymore? Correct me if Im wrong though.
Sounds good to me! Please let us know if there are any issues adapting our traits to hardware devices.
I think there are probably several more traits that could use a *Mut
equivalent for wrapping a peripheral device, but other than that I think we should be good.
I'd like to propose a trait or rather a group of traits providing clear interfaces for hardware cryptography accelerators. Modern Cortex-M chips like for example the stm32h7 series provide hardware acceleration for common cryptographic functions like AES, SHA and more. As for example one of the design goals of the AES function was to be extremly performant both in soft and hardware it would just make sense to use these existing hardware implementations as well.
For the traits themselves an encrypt() and a decrypt() function as well as a hash() function should be sufficient for the symmetric and hashing algorithms. If there are any hardware based implementations of asymmetric functions, I am currently not aware of any, one would also have to take the public and private key management into consideration.
All in all I think the traits themself would not be that complex to implement and still provide a good interface for hardware based cryptography in embedded Rust.