use core::fmt::Debug;
#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(all(not(feature = "std"), any(feature = "signature", feature = "aead")))]
use alloc::{boxed::Box, sync::Arc, vec::Vec};
#[cfg(any(feature = "signature", feature = "aead"))]
use core::marker::PhantomData;
#[cfg(any(feature = "signature", feature = "aead"))]
use core::future::Future;
#[cfg(any(feature = "signature", feature = "aead"))]
use core::pin::Pin;
#[cfg(all(feature = "std", any(feature = "signature", feature = "aead")))]
use std::sync::Arc;
#[cfg(feature = "signature")]
mod signing {
pub use crate::crypto::sign::ecdsa::{
DigestPrimitive, Secp256k1, Secp256k1Signature, Secp256k1SigningKey, SignPrimitive, Signature, SignatureSize,
SigningKey, VerifyPrimitive,
};
pub use crate::crypto::sign::elliptic_curve::generic_array::{ArrayLength, GenericArray};
pub use crate::crypto::sign::elliptic_curve::ops::{Invert, Reduce};
pub use crate::crypto::sign::elliptic_curve::point::PointCompression;
pub use crate::crypto::sign::elliptic_curve::scalar::Scalar;
pub use crate::crypto::sign::elliptic_curve::sec1::ModulusSize;
pub use crate::crypto::sign::elliptic_curve::sec1::{FromEncodedPoint, ToEncodedPoint};
pub use crate::crypto::sign::elliptic_curve::subtle::CtOption;
pub use crate::crypto::sign::elliptic_curve::{
AffinePoint, CurveArithmetic, Error as EllipticCurveError, FieldBytesSize, PrimeCurve,
};
pub use crate::crypto::sign::{
Error as SignatureError, Keypair, PrehashSigner, SignatureAlgorithmIdentifier, SignatureEncoding,
};
#[cfg(feature = "ecdh")]
pub use crate::crypto::sign::elliptic_curve::ecdh::diffie_hellman;
#[cfg(feature = "ecdh")]
pub use crate::crypto::sign::elliptic_curve::PublicKey;
}
#[cfg(feature = "signature")]
use signing::*;
#[cfg(feature = "aead")]
mod encryption {
pub use crate::crypto::aead::{
Aead, AeadCore, Aes128Gcm, Aes128GcmOid, Aes256Gcm, Aes256GcmOid, Error as AeadError, Nonce,
};
pub use crate::crypto::common::typenum::Unsigned;
}
#[cfg(feature = "aead")]
use encryption::*;
#[cfg(any(feature = "signature", feature = "aead"))]
mod common {
pub use crate::der::oid::AssociatedOid;
pub use crate::spki::AlgorithmIdentifierOwned;
#[cfg(feature = "signature")]
pub use crate::spki::EncodePublicKey;
}
#[cfg(any(feature = "signature", feature = "aead"))]
use common::*;
#[cfg(feature = "signature")]
use crate::crypto::secret::SecretSlice;
#[derive(Debug)]
pub enum KeyError {
SpkiError(crate::spki::Error),
#[cfg(feature = "signature")]
EllipticCurveError(EllipticCurveError),
#[cfg(feature = "signature")]
SignatureError(SignatureError),
#[cfg(feature = "aead")]
AeadError(AeadError),
#[cfg(feature = "aead")]
NonceLengthError(crate::error::ReceivedExpectedError<usize, usize>),
UnsupportedOperation,
}
crate::impl_error_display!(unconditional KeyError {
SpkiError(e) => "SPKI error: {e}",
#[cfg(feature = "signature")]
EllipticCurveError(e) => "Elliptic curve error: {e}",
#[cfg(feature = "signature")]
SignatureError(e) => "Signature error: {e}",
#[cfg(feature = "aead")]
AeadError(e) => "AEAD error: {e}",
#[cfg(feature = "aead")]
NonceLengthError(e) => "Nonce length mismatch: {e}",
UnsupportedOperation => "Operation not supported by this key provider",
});
crate::impl_from!(crate::spki::Error => KeyError::SpkiError);
crate::impl_from!(#[cfg(feature = "signature")] EllipticCurveError => KeyError::EllipticCurveError);
crate::impl_from!(#[cfg(feature = "signature")] SignatureError => KeyError::SignatureError);
crate::impl_from!(#[cfg(feature = "aead")] AeadError => KeyError::AeadError);
#[cfg(feature = "signature")]
#[derive(Debug, Clone)]
pub enum SigningKeySpec {
Bytes(&'static [u8]),
Provider(Arc<dyn SigningKeyProvider>),
}
#[cfg(feature = "signature")]
impl SigningKeySpec {
pub fn to_provider<C>(&self) -> Result<Arc<dyn SigningKeyProvider>, KeyError>
where
C: PrimeCurve + CurveArithmetic + DigestPrimitive + PointCompression + AssociatedOid + Send + Sync + 'static,
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C> + Reduce<C::Uint>,
SignatureSize<C>: ArrayLength<u8>,
FieldBytesSize<C>: ModulusSize,
AffinePoint<C>: VerifyPrimitive<C> + FromEncodedPoint<C> + ToEncodedPoint<C>,
SigningKey<C>: PrehashSigner<Signature<C>> + Keypair + Send + Sync + Debug + 'static,
<SigningKey<C> as Keypair>::VerifyingKey: EncodePublicKey,
Signature<C>: SignatureEncoding + SignatureAlgorithmIdentifier + Send + Sync + 'static,
{
match self {
SigningKeySpec::Bytes(bytes) => {
let field_bytes = GenericArray::from_slice(bytes);
let signing_key = SigningKey::<C>::from_bytes(field_bytes)?;
Ok(Arc::new(EcdsaKeyProvider::from(signing_key)))
}
SigningKeySpec::Provider(provider) => Ok(Arc::clone(provider)),
}
}
}
#[cfg(feature = "signature")]
pub trait SigningKeyProvider: Send + Sync + Debug {
fn algorithm(&self) -> AlgorithmIdentifierOwned;
fn to_public_key_bytes(&self) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, KeyError>> + Send + '_>>;
fn sign_prehash(&self, prehash: &[u8]) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, KeyError>> + Send + '_>>;
fn key_agreement(
&self,
_peer_public_key: &[u8],
) -> Pin<Box<dyn Future<Output = Result<SecretSlice<u8>, KeyError>> + Send + '_>> {
Box::pin(async { Err(KeyError::UnsupportedOperation) })
}
}
#[cfg(feature = "signature")]
pub struct InMemorySigningKeyProvider<K, S>
where
K: PrehashSigner<S> + Keypair,
S: SignatureEncoding,
{
signing_key: K,
_sig: PhantomData<S>,
}
#[cfg(feature = "signature")]
impl<K, S> From<K> for InMemorySigningKeyProvider<K, S>
where
K: PrehashSigner<S> + Keypair,
S: SignatureEncoding,
{
fn from(signing_key: K) -> Self {
InMemorySigningKeyProvider { signing_key, _sig: PhantomData }
}
}
#[cfg(feature = "signature")]
impl<K, S> Debug for InMemorySigningKeyProvider<K, S>
where
K: PrehashSigner<S> + Keypair + Debug,
S: SignatureEncoding,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("InMemoryKeyProvider")
.field("signing_key", &self.signing_key)
.finish()
}
}
#[cfg(feature = "signature")]
impl<K, S> SigningKeyProvider for InMemorySigningKeyProvider<K, S>
where
K: PrehashSigner<S> + Keypair + Send + Sync + Debug + 'static,
K::VerifyingKey: EncodePublicKey,
S: SignatureEncoding + SignatureAlgorithmIdentifier + Send + Sync + 'static,
{
fn algorithm(&self) -> AlgorithmIdentifierOwned {
AlgorithmIdentifierOwned { oid: S::ALGORITHM_OID, parameters: None }
}
fn to_public_key_bytes(&self) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, KeyError>> + Send + '_>> {
let result = self
.signing_key
.verifying_key()
.to_public_key_der()
.map(|der| der.into_vec())
.map_err(KeyError::from);
Box::pin(async move { result })
}
fn sign_prehash(&self, prehash: &[u8]) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, KeyError>> + Send + '_>> {
let result = self
.signing_key
.sign_prehash(prehash)
.map(|signature: S| signature.to_bytes().as_ref().to_vec())
.map_err(KeyError::from);
Box::pin(async move { result })
}
}
#[cfg(feature = "signature")]
impl<K, S> SigningKeyProvider for Arc<InMemorySigningKeyProvider<K, S>>
where
K: PrehashSigner<S> + Keypair + Send + Sync + Debug + 'static,
K::VerifyingKey: EncodePublicKey,
S: SignatureEncoding + SignatureAlgorithmIdentifier + Send + Sync + 'static,
{
fn algorithm(&self) -> AlgorithmIdentifierOwned {
self.as_ref().algorithm()
}
fn to_public_key_bytes(&self) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, KeyError>> + Send + '_>> {
self.as_ref().to_public_key_bytes()
}
fn sign_prehash(&self, prehash: &[u8]) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, KeyError>> + Send + '_>> {
self.as_ref().sign_prehash(prehash)
}
}
#[cfg(all(feature = "signature", feature = "secp256k1"))]
pub type Secp256k1Provider = InMemorySigningKeyProvider<Secp256k1SigningKey, Secp256k1Signature>;
#[cfg(all(feature = "signature", feature = "secp256k1"))]
pub struct EcdsaKeyProvider<C>
where
C: PrimeCurve + CurveArithmetic,
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
SignatureSize<C>: ArrayLength<u8>,
{
signing_key: SigningKey<C>,
}
#[cfg(all(feature = "signature", feature = "secp256k1"))]
impl<C> From<SigningKey<C>> for EcdsaKeyProvider<C>
where
C: PrimeCurve + CurveArithmetic,
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
SignatureSize<C>: ArrayLength<u8>,
{
fn from(signing_key: SigningKey<C>) -> Self {
EcdsaKeyProvider { signing_key }
}
}
#[cfg(all(feature = "signature", feature = "secp256k1"))]
impl<C> Debug for EcdsaKeyProvider<C>
where
C: PrimeCurve + CurveArithmetic,
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
SignatureSize<C>: ArrayLength<u8>,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("EcdsaKeyProvider")
.field("curve", &core::any::type_name::<C>())
.finish_non_exhaustive()
}
}
#[cfg(all(feature = "signature", feature = "secp256k1"))]
impl<C> SigningKeyProvider for EcdsaKeyProvider<C>
where
C: PrimeCurve + CurveArithmetic + DigestPrimitive + PointCompression + AssociatedOid + Send + Sync + 'static,
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C> + Reduce<C::Uint>,
SignatureSize<C>: ArrayLength<u8>,
FieldBytesSize<C>: ModulusSize,
AffinePoint<C>: VerifyPrimitive<C> + FromEncodedPoint<C> + ToEncodedPoint<C>,
SigningKey<C>: PrehashSigner<Signature<C>> + Keypair + Send + Sync + Debug,
<SigningKey<C> as Keypair>::VerifyingKey: EncodePublicKey,
Signature<C>: SignatureEncoding + SignatureAlgorithmIdentifier + Send + Sync,
{
fn algorithm(&self) -> AlgorithmIdentifierOwned {
AlgorithmIdentifierOwned { oid: Signature::<C>::ALGORITHM_OID, parameters: None }
}
fn to_public_key_bytes(&self) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, KeyError>> + Send + '_>> {
let result = self
.signing_key
.verifying_key()
.to_public_key_der()
.map(|der| der.into_vec())
.map_err(KeyError::from);
Box::pin(async move { result })
}
fn sign_prehash(&self, prehash: &[u8]) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, KeyError>> + Send + '_>> {
let result = self
.signing_key
.sign_prehash(prehash)
.map(|signature: Signature<C>| signature.to_bytes().as_ref().to_vec())
.map_err(KeyError::from);
Box::pin(async move { result })
}
#[cfg(feature = "ecdh")]
fn key_agreement(
&self,
peer_public_key: &[u8],
) -> Pin<Box<dyn Future<Output = Result<SecretSlice<u8>, KeyError>> + Send + '_>> {
let pk_result = PublicKey::<C>::from_sec1_bytes(peer_public_key);
let secret_key = *self.signing_key.as_nonzero_scalar();
Box::pin(async move {
let pk = pk_result?;
let shared_secret = diffie_hellman(secret_key, pk.as_affine());
Ok(SecretSlice::from(shared_secret.raw_secret_bytes().to_vec()))
})
}
}
#[cfg(all(feature = "signature", feature = "secp256k1"))]
impl<C> SigningKeyProvider for Arc<EcdsaKeyProvider<C>>
where
C: PrimeCurve + CurveArithmetic + DigestPrimitive + PointCompression + AssociatedOid + Send + Sync + 'static,
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C> + Reduce<C::Uint>,
SignatureSize<C>: ArrayLength<u8>,
FieldBytesSize<C>: ModulusSize,
AffinePoint<C>: VerifyPrimitive<C> + FromEncodedPoint<C> + ToEncodedPoint<C>,
SigningKey<C>: PrehashSigner<Signature<C>> + Keypair + Send + Sync + Debug,
<SigningKey<C> as Keypair>::VerifyingKey: EncodePublicKey,
Signature<C>: SignatureEncoding + SignatureAlgorithmIdentifier + Send + Sync,
{
fn algorithm(&self) -> AlgorithmIdentifierOwned {
self.as_ref().algorithm()
}
fn to_public_key_bytes(&self) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, KeyError>> + Send + '_>> {
self.as_ref().to_public_key_bytes()
}
fn sign_prehash(&self, prehash: &[u8]) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, KeyError>> + Send + '_>> {
self.as_ref().sign_prehash(prehash)
}
fn key_agreement(
&self,
peer_public_key: &[u8],
) -> Pin<Box<dyn Future<Output = Result<SecretSlice<u8>, KeyError>> + Send + '_>> {
self.as_ref().key_agreement(peer_public_key)
}
}
#[cfg(feature = "signature")]
pub type Secp256k1KeyProvider = EcdsaKeyProvider<Secp256k1>;
#[cfg(feature = "aead")]
pub trait EncryptingKeyProvider: Send + Sync + Debug {
fn algorithm(&self) -> AlgorithmIdentifierOwned;
fn encrypt(
&self,
nonce: &[u8],
plaintext: &[u8],
) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, KeyError>> + Send + '_>>;
fn decrypt(
&self,
nonce: &[u8],
ciphertext: &[u8],
) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, KeyError>> + Send + '_>>;
}
#[cfg(feature = "aead")]
pub struct InMemoryEncryptingKeyProvider<A, O>
where
A: Aead + Send + Sync + 'static,
O: AssociatedOid + Send + Sync,
{
cipher: A,
_oid: PhantomData<O>,
}
#[cfg(feature = "aead")]
impl<A, O> From<A> for InMemoryEncryptingKeyProvider<A, O>
where
A: Aead + Send + Sync + 'static,
O: AssociatedOid + Send + Sync,
{
fn from(cipher: A) -> Self {
InMemoryEncryptingKeyProvider { cipher, _oid: PhantomData }
}
}
#[cfg(feature = "aead")]
impl<A, O> Debug for InMemoryEncryptingKeyProvider<A, O>
where
A: Aead + Send + Sync + 'static,
O: AssociatedOid + Send + Sync,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("InMemoryEncryptingKeyProvider")
.field("algorithm", &O::OID)
.finish_non_exhaustive()
}
}
#[cfg(feature = "aead")]
impl<A, O> EncryptingKeyProvider for InMemoryEncryptingKeyProvider<A, O>
where
A: Aead + Send + Sync + 'static,
O: AssociatedOid + Send + Sync,
{
fn algorithm(&self) -> AlgorithmIdentifierOwned {
AlgorithmIdentifierOwned { oid: O::OID, parameters: None }
}
fn encrypt(
&self,
nonce: &[u8],
plaintext: &[u8],
) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, KeyError>> + Send + '_>> {
let nonce_size = <<A as AeadCore>::NonceSize as Unsigned>::USIZE;
let received_len = nonce.len();
if received_len != nonce_size {
return Box::pin(async move {
Err(KeyError::NonceLengthError(crate::error::ReceivedExpectedError::from((
received_len,
nonce_size,
))))
});
}
let nonce_ref = Nonce::<A>::from_slice(nonce);
let result = self.cipher.encrypt(nonce_ref, plaintext).map_err(KeyError::from);
Box::pin(async move { result })
}
fn decrypt(
&self,
nonce: &[u8],
ciphertext: &[u8],
) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, KeyError>> + Send + '_>> {
let nonce_size = <<A as AeadCore>::NonceSize as Unsigned>::USIZE;
let received_len = nonce.len();
if received_len != nonce_size {
return Box::pin(async move {
Err(KeyError::NonceLengthError(crate::error::ReceivedExpectedError::from((
received_len,
nonce_size,
))))
});
}
let nonce_ref = Nonce::<A>::from_slice(nonce);
let result = self.cipher.decrypt(nonce_ref, ciphertext).map_err(KeyError::from);
Box::pin(async move { result })
}
}
#[cfg(feature = "aead")]
impl<A, O> EncryptingKeyProvider for Arc<InMemoryEncryptingKeyProvider<A, O>>
where
A: Aead + Send + Sync + 'static,
O: AssociatedOid + Send + Sync,
{
fn algorithm(&self) -> AlgorithmIdentifierOwned {
self.as_ref().algorithm()
}
fn encrypt(
&self,
nonce: &[u8],
plaintext: &[u8],
) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, KeyError>> + Send + '_>> {
self.as_ref().encrypt(nonce, plaintext)
}
fn decrypt(
&self,
nonce: &[u8],
ciphertext: &[u8],
) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, KeyError>> + Send + '_>> {
self.as_ref().decrypt(nonce, ciphertext)
}
}
#[cfg(all(feature = "aead", feature = "aes-gcm"))]
pub type Aes256GcmKeyProvider = InMemoryEncryptingKeyProvider<Aes256Gcm, Aes256GcmOid>;
#[cfg(all(feature = "aead", feature = "aes-gcm"))]
pub type Aes128GcmKeyProvider = InMemoryEncryptingKeyProvider<Aes128Gcm, Aes128GcmOid>;
#[cfg(test)]
mod tests {
use rand_core::OsRng;
use super::*;
use crate::crypto::hash::{Digest, Sha3_256};
use crate::crypto::secret::ToInsecure;
use crate::crypto::sign::ecdsa::k256::ecdsa::SigningKey;
use crate::crypto::sign::PrehashVerifier;
fn prehash(data: &[u8]) -> Vec<u8> {
let mut hasher = Sha3_256::new();
hasher.update(data);
hasher.finalize().to_vec()
}
#[tokio::test]
async fn test_secp256k1_provider_public_key() -> Result<(), Box<dyn std::error::Error>> {
let signing_key = SigningKey::random(&mut OsRng);
let provider = Secp256k1KeyProvider::from(signing_key);
let public_key_bytes = provider.to_public_key_bytes().await?;
assert_eq!(public_key_bytes.len(), 88);
Ok(())
}
#[tokio::test]
async fn test_secp256k1_provider_sign() -> Result<(), Box<dyn std::error::Error>> {
let signing_key = SigningKey::random(&mut OsRng);
let provider = Secp256k1KeyProvider::from(signing_key.clone());
let digest = prehash(b"test data to sign");
let signature_bytes = provider.sign_prehash(&digest).await?;
let signature = Secp256k1Signature::from_slice(&signature_bytes)?;
signing_key.verifying_key().verify_prehash(&digest, &signature)?;
Ok(())
}
#[tokio::test]
async fn test_secp256k1_provider_key_agreement() -> Result<(), Box<dyn std::error::Error>> {
let signing_key1 = SigningKey::random(&mut OsRng);
let signing_key2 = SigningKey::random(&mut OsRng);
let provider1 = Secp256k1KeyProvider::from(signing_key1.clone());
let provider2 = Secp256k1KeyProvider::from(signing_key2.clone());
let public1 = signing_key1.verifying_key().to_encoded_point(false).as_bytes().to_vec();
let public2 = signing_key2.verifying_key().to_encoded_point(false).as_bytes().to_vec();
let shared1 = provider1.key_agreement(&public2).await?.to_insecure()?;
let shared2 = provider2.key_agreement(&public1).await?.to_insecure()?;
assert_eq!(shared1, shared2);
assert_eq!(shared1.len(), 32); Ok(())
}
#[tokio::test]
async fn test_generic_provider_sign() -> Result<(), Box<dyn std::error::Error>> {
let signing_key = SigningKey::random(&mut OsRng);
let provider: Secp256k1Provider = InMemorySigningKeyProvider::from(signing_key.clone());
let digest = prehash(b"test data to sign");
let signature_bytes = provider.sign_prehash(&digest).await?;
let signature = Secp256k1Signature::from_slice(&signature_bytes)?;
signing_key.verifying_key().verify_prehash(&digest, &signature)?;
Ok(())
}
#[tokio::test]
async fn test_arc_secp256k1_provider() -> Result<(), Box<dyn std::error::Error>> {
let signing_key = SigningKey::random(&mut OsRng);
let provider = Arc::new(Secp256k1KeyProvider::from(signing_key.clone()));
let public_key_bytes = provider.to_public_key_bytes().await?;
assert_eq!(public_key_bytes.len(), 88);
let digest = prehash(b"test");
let signature_bytes = provider.sign_prehash(&digest).await?;
let signature = Secp256k1Signature::from_slice(&signature_bytes)?;
signing_key.verifying_key().verify_prehash(&digest, &signature)?;
Ok(())
}
#[tokio::test]
async fn test_algorithm_identifier() -> Result<(), Box<dyn std::error::Error>> {
let signing_key = SigningKey::random(&mut OsRng);
let provider = Secp256k1KeyProvider::from(signing_key);
let alg = provider.algorithm();
assert_eq!(alg.oid, Secp256k1Signature::ALGORITHM_OID);
Ok(())
}
}