-
Notifications
You must be signed in to change notification settings - Fork 230
kem: use byte arrays for EK and SS
#2220
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,44 +12,131 @@ pub use common::{ | |
| self, Generate, InvalidKey, Key, KeyExport, KeyInit, KeySizeUser, TryKeyInit, typenum::consts, | ||
| }; | ||
|
|
||
| use common::array::{self, ArraySize}; | ||
| use core::{array::TryFromSliceError, convert::Infallible}; | ||
| use rand_core::TryCryptoRng; | ||
|
|
||
| #[cfg(feature = "getrandom")] | ||
| use {common::getrandom, rand_core::TryRngCore}; | ||
|
|
||
| /// Ciphertext message (a.k.a. "encapsulated key") produced by [`Encapsulate::encapsulate`] which is | ||
| /// an encrypted [`SharedSecret`] that can be decrypted using [`Decapsulate::decapsulate`]. | ||
| /// | ||
| /// `K` is expected to be a type that impls [`KemParams`], such as an encapsulator or decapsulator. | ||
| pub type Ciphertext<K> = array::Array<u8, <K as KemParams>::CiphertextSize>; | ||
|
|
||
| /// Shared secret: plaintext produced after decapsulation by [`Decapsulate::decapsulate`] which is | ||
| /// also returned by [`Encapsulate::encapsulate`]. | ||
| /// | ||
| /// `K` is expected to be a type that impls [`KemParams`], such as an encapsulator or decapsulator. | ||
| pub type SharedSecret<K> = array::Array<u8, <K as KemParams>::SharedSecretSize>; | ||
|
|
||
| /// Key encapsulation mechanism parameters: sizes of the ciphertext and decrypted plaintext. | ||
| /// | ||
| /// This trait is impl'd by types that impl either [`Encapsulate`] or [`Decapsulate`] and defines | ||
| /// the sizes of the encapsulated key and shared secret. | ||
| pub trait KemParams { | ||
| /// Size of the ciphertext (a.k.a. "encapsulated key") produced by [`Encapsulate::encapsulate`]. | ||
| type CiphertextSize: ArraySize; | ||
|
|
||
| /// Size of the shared secret after decapsulation by [`Decapsulate::decapsulate`]. | ||
| type SharedSecretSize: ArraySize; | ||
| } | ||
|
|
||
| /// Encapsulator for shared secrets. | ||
| /// | ||
| /// Often, this will just be a public key. However, it can also be a bundle of public keys, or it | ||
| /// can include a sender's private key for authenticated encapsulation. | ||
| pub trait Encapsulate<EK, SS>: TryKeyInit + KeyExport { | ||
| /// Encapsulates a fresh shared secret | ||
| fn encapsulate_with_rng<R>(&self, rng: &mut R) -> Result<(EK, SS), R::Error> | ||
| where | ||
| R: TryCryptoRng + ?Sized; | ||
| pub trait Encapsulate: KemParams + TryKeyInit + KeyExport { | ||
| /// Encapsulates a fresh [`SharedSecret`] generated using the supplied random number | ||
| /// generator `R`. | ||
| fn encapsulate_with_rng<R: TryCryptoRng + ?Sized>( | ||
| &self, | ||
| rng: &mut R, | ||
| ) -> Result<(Ciphertext<Self>, SharedSecret<Self>), R::Error>; | ||
|
|
||
| /// Encapsulate a fresh shared secret generated using the system's secure RNG. | ||
| #[cfg(feature = "getrandom")] | ||
| fn encapsulate(&self) -> (EK, SS) { | ||
| fn encapsulate(&self) -> (Ciphertext<Self>, SharedSecret<Self>) { | ||
| match self.encapsulate_with_rng(&mut getrandom::SysRng.unwrap_err()) { | ||
| Ok(ret) => ret, | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// Decapsulator for an encapsulated keys, with an associated encapsulator. | ||
| /// Trait for decapsulators, which is a supertrait bound of both [`Decapsulate`] and | ||
| /// [`TryDecapsulate`]. | ||
| pub trait Decapsulator: | ||
| KemParams< | ||
| CiphertextSize = <Self::Encapsulator as KemParams>::CiphertextSize, | ||
| SharedSecretSize = <Self::Encapsulator as KemParams>::SharedSecretSize, | ||
| > | ||
| { | ||
| /// Encapsulator which corresponds to this decapsulator. | ||
| type Encapsulator: Encapsulate + Clone + KemParams; | ||
|
|
||
| /// Retrieve the encapsulator associated with this decapsulator. | ||
| fn encapsulator(&self) -> &Self::Encapsulator; | ||
| } | ||
|
|
||
| impl<K: Decapsulator> KemParams for K { | ||
| type CiphertextSize = <K::Encapsulator as KemParams>::CiphertextSize; | ||
| type SharedSecretSize = <K::Encapsulator as KemParams>::SharedSecretSize; | ||
| } | ||
|
|
||
| /// Decapsulator for encapsulated keys, with an associated `Encapsulator` bounded by the | ||
| /// [`Encapsulate`] trait. | ||
| /// | ||
| /// Often, this will just be a secret key. But, as with [`Encapsulate`], it can be a bundle | ||
| /// of secret keys, or it can include a sender's private key for authenticated encapsulation. | ||
| /// It could also be a hardware device like an HSM, TPM, or SEP. | ||
| /// | ||
| /// When possible (i.e. for software / non-HSM implementations) types which impl this trait should | ||
| /// also impl the [`Generate`] trait to support key generation. | ||
| pub trait Decapsulate<EK, SS> { | ||
| /// Encapsulator which corresponds to this decapsulator. | ||
| type Encapsulator: Encapsulate<EK, SS>; | ||
| pub trait Decapsulate: Decapsulator + TryDecapsulate<Error = Infallible> { | ||
| /// Decapsulates the given [`Ciphertext`] a.k.a. "encapsulated key". | ||
| fn decapsulate(&self, ct: &Ciphertext<Self>) -> SharedSecret<Self>; | ||
|
|
||
| /// Decapsulates the given encapsulated key | ||
| fn decapsulate(&self, encapsulated_key: &EK) -> SS; | ||
| /// Decapsulate the given byte slice containing a [`Ciphertext`] a.k.a. "encapsulated key". | ||
| /// | ||
| /// # Errors | ||
| /// - If the length of `ct` is not equal to `<Self as Kem>::CiphertextSize`. | ||
| fn decapsulate_slice(&self, ct: &[u8]) -> Result<SharedSecret<Self>, TryFromSliceError> { | ||
| ct.try_into().map(|ct| self.decapsulate(&ct)) | ||
| } | ||
| } | ||
|
|
||
| /// Retrieve the encapsulator associated with this decapsulator. | ||
| fn encapsulator(&self) -> Self::Encapsulator; | ||
| /// Decapsulator for encapsulated keys with failure handling, with an associated `Encapsulator` | ||
| /// bounded by the [`Encapsulate`] trait. | ||
| /// | ||
| /// Prefer to implement the [`Decapsulate`] trait if possible. See that trait's documentation for | ||
| /// more information. | ||
| pub trait TryDecapsulate: Decapsulator { | ||
| /// Decapsulation error | ||
| type Error: core::error::Error; | ||
|
|
||
| /// Decapsulates the given [`Ciphertext`] a.k.a. "encapsulated key". | ||
| fn try_decapsulate(&self, ct: &Ciphertext<Self>) -> Result<SharedSecret<Self>, Self::Error>; | ||
|
|
||
| /// Decapsulate the given byte slice containing a [`Ciphertext`] a.k.a. "encapsulated key". | ||
| /// | ||
| /// # Errors | ||
| /// - If the length of `ct` is not equal to `<Self as Kem>::CiphertextSize`. | ||
| fn try_decapsulate_slice(&self, ct: &[u8]) -> Result<SharedSecret<Self>, Self::Error> | ||
| where | ||
| Self::Error: From<TryFromSliceError>, | ||
| { | ||
| self.try_decapsulate(ct.try_into()?) | ||
| } | ||
| } | ||
|
|
||
| impl<D> TryDecapsulate for D | ||
| where | ||
| D: Decapsulate, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Decapsulate already implies TryDecapsulate with Error = Infallible, no? It’s in the trait def
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a blanket impl that always satisfies that bound. It means that any type that impls The explicit bound means we always know |
||
| { | ||
| type Error = Infallible; | ||
|
|
||
| fn try_decapsulate(&self, ct: &Ciphertext<Self>) -> Result<SharedSecret<Self>, Infallible> { | ||
| Ok(self.decapsulate(ct)) | ||
| } | ||
| } | ||
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.
Why not define this to do the try_decapsulate then unwrap?
Uh oh!
There was an error while loading. Please reload this page.
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.
Because that would introduce a panic.
The idea is that
Decapsulatecan be used as aTryDecapsulateif you want, but not the other way around (unlessError = Infallible). So if you have a mixture,TryDecapsulatebecomes the common abstraction.Think about it like
From/TryFrom.TryFromhas a blanket impl for types which implFromwhereError = Infallible. But you wouldn't want the other way around, forFromimpls to unwrapTryFrommeaning usingFrommight cause panics (this is giving megeneric-arrayflashbacks)