wecanencrypt 0.1.0

Simple Rust OpenPGP library for encryption, signing, and key management (includes rpgp).
Documentation
use std::marker::PhantomData;

use digest::{typenum::Unsigned, OutputSizeUser};
use rsa::{
    pkcs1v15::{self, Signature},
    RsaPublicKey,
};
use sha2::Digest;
use signature::{hazmat::PrehashSigner, Keypair, SignatureEncoding};

use crate::pgp::{
    adapter::PublicKey as HPublicKey,
    crypto::{
        hash::{HashAlgorithm, KnownDigest},
        public_key::PublicKeyAlgorithm,
    },
    errors::{bail, Result},
    packet::{PubKeyInner, PublicKey},
    types::{
        Fingerprint, KeyDetails, KeyId, KeyVersion, Mpi, Password, PublicParams, RsaPublicParams,
        SignatureBytes, SigningKey, Timestamp, VerifyingKey,
    },
};

impl HPublicKey for RsaPublicKey {
    const PGP_ALGORITHM: PublicKeyAlgorithm = PublicKeyAlgorithm::RSA;

    fn pgp_parameters(&self) -> PublicParams {
        let key = self.clone();
        PublicParams::RSA(RsaPublicParams { key })
    }
}

/// [`signature::Signer`] backed signer for PGP.
#[derive(derive_more::Debug)]
#[debug("RsaSigner({public_key:?})")]
pub struct RsaSigner<T, D> {
    inner: T,
    public_key: PublicKey,
    _digest: PhantomData<D>,
}

impl<T, D> RsaSigner<T, D>
where
    D: Digest,
    T: Keypair<VerifyingKey = pkcs1v15::VerifyingKey<D>>,
{
    /// Create a new signer with a given public key
    pub fn new(inner: T, version: KeyVersion, created_at: Timestamp) -> Result<Self> {
        let public_key = PubKeyInner::new(
            version,
            RsaPublicKey::PGP_ALGORITHM,
            created_at,
            None,
            inner.verifying_key().as_ref().pgp_parameters(),
        )?;
        let public_key = PublicKey::from_inner(public_key)?;

        Ok(Self {
            inner,
            public_key,
            _digest: PhantomData,
        })
    }

    /// Return the public key
    pub fn public_key(&self) -> &PublicKey {
        &self.public_key
    }
}

impl<D, T> RsaSigner<T, D>
where
    D: Digest + KnownDigest,
    T: PrehashSigner<Signature>,
{
    fn sign_prehash(&self, hash: HashAlgorithm, prehash: &[u8]) -> Result<Vec<Vec<u8>>> {
        if D::HASH_ALGORITHM != hash {
            bail!(
                "Signer only support {expected:?}, found {found:?}",
                expected = D::HASH_ALGORITHM,
                found = hash
            );
        }

        if <D as OutputSizeUser>::OutputSize::USIZE != prehash.len() {
            bail!(
                "Signer expected a hash of length ({expected} bytes), found ({found} bytes)",
                expected = <D as OutputSizeUser>::OutputSize::USIZE,
                found = prehash.len()
            );
        }

        let sig = self.inner.sign_prehash(prehash)?;

        Ok(vec![sig.to_vec()])
    }
}

impl<D, T> Keypair for RsaSigner<T, D>
where
    T: Keypair,
{
    type VerifyingKey = T::VerifyingKey;

    fn verifying_key(&self) -> Self::VerifyingKey {
        self.inner.verifying_key()
    }
}

impl<D, T> SigningKey for RsaSigner<T, D>
where
    T: PrehashSigner<Signature>,
    D: Digest + KnownDigest,
{
    fn sign(
        &self,
        _key_pw: &Password,
        hash: HashAlgorithm,
        prehashed_data: &[u8],
    ) -> Result<SignatureBytes> {
        let sig = self.sign_prehash(hash, prehashed_data)?;

        // MPI format:
        // strip leading zeros, to match parse results from MPIs
        let mpis = sig
            .iter()
            .map(|v| Mpi::from_slice(&v[..]))
            .collect::<Vec<_>>();

        Ok(SignatureBytes::Mpis(mpis))
    }

    fn hash_alg(&self) -> HashAlgorithm {
        D::HASH_ALGORITHM
    }
}

impl<D, T> KeyDetails for RsaSigner<T, D> {
    fn version(&self) -> KeyVersion {
        self.public_key.version()
    }

    fn fingerprint(&self) -> Fingerprint {
        self.public_key.fingerprint()
    }

    fn legacy_key_id(&self) -> KeyId {
        self.public_key.legacy_key_id()
    }

    fn algorithm(&self) -> PublicKeyAlgorithm {
        self.public_key.algorithm()
    }

    fn created_at(&self) -> Timestamp {
        self.public_key.created_at()
    }

    fn expiration(&self) -> Option<u16> {
        self.public_key.expiration()
    }

    fn public_params(&self) -> &PublicParams {
        self.public_key.public_params()
    }
}

impl<D, T> VerifyingKey for RsaSigner<T, D> {
    fn verify(&self, hash: HashAlgorithm, data: &[u8], sig: &SignatureBytes) -> Result<()> {
        self.public_key.verify(hash, data, sig)
    }
}