//! Hold the implementation of [`Signer`] and [`Decryptor`] for [`KeyPair`].
//!
//! [`Signer`]: super::super::asymmetric::Signer
//! [`Decryptor`]: super::super::asymmetric::Decryptor
//! [`KeyPair`]: super::super::asymmetric::KeyPair
use std::time::SystemTime;
use botan::{
RandomNumberGenerator,
Pubkey,
Privkey,
};
use crate::{
Error,
Result,
crypto::{
asymmetric::KeyPair,
backend::interface::Asymmetric,
mem::Protected,
mpi::{self, MPI, ProtectedMPI, PublicKey},
SessionKey,
},
packet::{
key::{self, Key4, SecretParts},
Key,
},
types::{
Curve,
HashAlgorithm,
PublicKeyAlgorithm,
},
};
impl Asymmetric for super::Backend {
fn x25519_generate_key() -> Result<(Protected, [u8; 32])> {
let mut rng = RandomNumberGenerator::new_userspace()?;
let secret = Privkey::create("Curve25519", "", &mut rng)?;
let mut public = [0u8; 32];
public.copy_from_slice(&secret.pubkey()?.get_x25519_key()?);
let mut secret: Protected = secret.get_x25519_key()?.into();
// Clamp the scalar. X25519 does the clamping implicitly, but
// OpenPGP's ECDH over Curve25519 requires the secret to be
// clamped.
secret[0] &= 0b1111_1000;
secret[31] &= !0b1000_0000;
secret[31] |= 0b0100_0000;
Ok((secret, public))
}
fn x25519_derive_public(secret: &Protected) -> Result<[u8; 32]> {
let secret = Privkey::load_x25519(secret)?;
Ok(<[u8; 32]>::try_from(&secret.pubkey()?.get_x25519_key()?[..])?)
}
fn x25519_shared_point(secret: &Protected, public: &[u8; 32])
-> Result<Protected> {
let secret = Privkey::load_x25519(&secret)?;
Ok(secret.agree(public, 32, b"", "Raw")?.into())
}
fn ed25519_generate_key() -> Result<(Protected, [u8; 32])> {
let mut rng = RandomNumberGenerator::new_userspace()?;
let secret = Privkey::create("Ed25519", "", &mut rng)?;
let (public, secret) = secret.get_ed25519_key()?;
Ok((secret.into(), public.as_slice().try_into()?))
}
fn ed25519_derive_public(secret: &Protected) -> Result<[u8; 32]> {
let secret = Privkey::load_ed25519(secret)?;
let (public, secret) = secret.get_ed25519_key()?;
let _ = Protected::from(secret); // Securely dispose.
Ok(public.as_slice().try_into()?)
}
fn ed25519_sign(secret: &Protected, _public: &[u8; 32], digest: &[u8])
-> Result<[u8; 64]> {
let mut rng = RandomNumberGenerator::new_userspace()?;
let secret = Privkey::load_ed25519(&secret)?;
Ok(secret.sign(digest, "", &mut rng)?.as_slice().try_into()?)
}
fn ed25519_verify(public: &[u8; 32], digest: &[u8], signature: &[u8; 64])
-> Result<bool> {
let pk = Pubkey::load_ed25519(public)?;
Ok(pk.verify(digest, signature, "")?)
}
}
// CONFIDENTIALITY: Botan clears the MPIs after use.
impl TryFrom<&ProtectedMPI> for botan::MPI {
type Error<