From 0831002acbc60b4d787bc60d46992cf18bd367c2 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Fri, 21 Nov 2025 13:56:48 -0700 Subject: [PATCH] crypto-common: add `TryKeyInit` trait Adds a trait providing fallible key initialization, similar to the existing `KeyInit` trait, but designed to handle the case that not all bytestrings of a given length represent valid keys. This is primarily useful in the context of public-key cryptography, e.g. scalars representing elliptic curve private keys. The API and method names are duplicated from `KeyInit`. It is assumed that `KeyInit` and `TryKeyInit` have an either-or relationship, i.e. types will not impl both `KeyInit` and `TryKeyInit`, and consumers of code which is generic over these traits will not be attempting to abstract over the `KeyInit`/`TryKeyInit` distinction, but one or the other will make sense in a given context (e.g. symmetric cryptography uses `KeyInit`, ECC uses `TryKeyInit`) --- crypto-common/src/lib.rs | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/crypto-common/src/lib.rs b/crypto-common/src/lib.rs index bb6d4758e..6349c61f3 100644 --- a/crypto-common/src/lib.rs +++ b/crypto-common/src/lib.rs @@ -153,7 +153,7 @@ pub trait AlgorithmName { fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result; } -/// Types which can be initialized from key. +/// Types which can be initialized from a key. pub trait KeyInit: KeySizeUser + Sized { /// Create new value from fixed size key. fn new(key: &Key) -> Self; @@ -209,7 +209,7 @@ pub trait KeyInit: KeySizeUser + Sized { } } -/// Types which can be initialized from key and initialization vector (nonce). +/// Types which can be initialized from a key and initialization vector (nonce). pub trait KeyIvInit: KeySizeUser + IvSizeUser + Sized { /// Create new value from fixed length key and nonce. fn new(key: &Key, iv: &Iv) -> Self; @@ -323,6 +323,27 @@ pub trait KeyIvInit: KeySizeUser + IvSizeUser + Sized { } } +/// Types which can be fallibly initialized from a key. +pub trait TryKeyInit: KeySizeUser + Sized { + /// Create new value from a fixed-size key. + /// + /// # Errors + /// - if the key is considered invalid according to rules specific to the implementing type + fn new(key: &Key) -> Result; + + /// Create new value from a variable size key. + /// + /// # Errors + /// - if the provided slice is the wrong length + /// - if the key is considered invalid by [`TryKeyInit::new`] + #[inline] + fn new_from_slice(key: &[u8]) -> Result { + <&Key>::try_from(key) + .map_err(|_| InvalidKey) + .and_then(Self::new) + } +} + /// Types which can be initialized from another type (usually block ciphers). /// /// Usually used for initializing types from block ciphers. @@ -462,6 +483,20 @@ where } */ +/// Error type for [`TryKeyInit`] for cases where the provided bytes do not correspond to a +/// valid key. +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub struct InvalidKey; + +impl fmt::Display for InvalidKey { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str("WeakKey") + } +} + +impl core::error::Error for InvalidKey {} + /// The error type returned when key and/or IV used in the [`KeyInit`], /// [`KeyIvInit`], and [`InnerIvInit`] slice-based methods had /// an invalid length.