zero4rs 2.0.0

zero4rs is a powerful, pragmatic, and extremely fast web framework for Rust
Documentation
extern crate sequoia_openpgp as openpgp;

use std::io::{self, Write};

use openpgp::cert::prelude::*;
use openpgp::crypto::SessionKey;
use openpgp::parse::{stream::*, Parse};
use openpgp::policy::Policy;
use openpgp::policy::StandardPolicy as P;
use openpgp::serialize::stream::*;
use openpgp::types::SymmetricAlgorithm;

/// Generates an encryption-capable key.
pub fn generate(email: &str) -> openpgp::Result<openpgp::Cert> {
    let (cert, _revocation) = CertBuilder::new()
        .add_userid(email)
        .add_transport_encryption_subkey()
        .generate()?;

    // Save the revocation certificate somewhere.

    Ok(cert)
}

/// Signs the given message.
pub fn sign(
    signed_message: &mut (dyn Write + Send + Sync),
    plaintext: &str,
    tsk: &openpgp::Cert,
) -> openpgp::Result<()> {
    let policy = &P::new();

    // Get the keypair to do the signing from the Cert.
    let keypair = tsk
        .keys()
        .unencrypted_secret()
        .with_policy(policy, None)
        .alive()
        .revoked(false)
        .for_signing()
        .next()
        .unwrap()
        .key()
        .clone()
        .into_keypair()?;

    // Start streaming an OpenPGP message.
    let message = Message::new(signed_message);

    // We want to sign a literal data packet.
    let message = Signer::new(message, keypair)?.build()?;

    // Emit a literal data packet.
    let mut message = LiteralWriter::new(message).build()?;

    // Sign the data.
    message.write_all(plaintext.as_bytes())?;

    // Finalize the OpenPGP message to make sure that all data is
    // written.
    message.finalize()?;

    Ok(())
}

/// Encrypts the given message.
pub fn encrypt(
    ciphertext: &mut (dyn Write + Send + Sync),
    plaintext: &str,
    recipient: &openpgp::Cert,
) -> openpgp::Result<()> {
    let policy = &P::new();

    let recipients = recipient
        .keys()
        .with_policy(policy, None)
        .supported()
        .alive()
        .revoked(false)
        .for_transport_encryption();

    // Start streaming an OpenPGP message.
    let message = Message::new(ciphertext);

    // We want to encrypt a literal data packet.
    let message = Encryptor::for_recipients(message, recipients).build()?;

    // Emit a literal data packet.
    let mut message = LiteralWriter::new(message).build()?;

    // Encrypt the data.
    message.write_all(plaintext.as_bytes())?;

    // Finalize the OpenPGP message to make sure that all data is
    // written.
    message.finalize()?;

    Ok(())
}

/// Decrypts the given message.
pub fn decrypt(
    plaintext: &mut dyn Write,
    ciphertext: &[u8],
    recipient: &openpgp::Cert,
) -> openpgp::Result<()> {
    let policy = &P::new();

    // Make a helper that that feeds the recipient's secret key to the
    // decryptor.
    let helper = Helper {
        policy,
        secret: recipient,
    };

    // Now, create a decryptor with a helper using the given Certs.
    let mut decryptor =
        DecryptorBuilder::from_bytes(ciphertext)?.with_policy(policy, None, helper)?;

    // Decrypt the data.
    io::copy(&mut decryptor, plaintext)?;

    Ok(())
}

struct Helper<'a> {
    policy: &'a dyn Policy,
    secret: &'a openpgp::Cert,
}

impl VerificationHelper for Helper<'_> {
    fn get_certs(&mut self, _ids: &[openpgp::KeyHandle]) -> openpgp::Result<Vec<openpgp::Cert>> {
        // Return public keys for signature verification here.
        Ok(Vec::new())
    }

    fn check(&mut self, _structure: MessageStructure) -> openpgp::Result<()> {
        // Implement your signature verification policy here.
        Ok(())
    }
}

impl DecryptionHelper for Helper<'_> {
    fn decrypt(
        &mut self,
        pkesks: &[openpgp::packet::PKESK],
        _skesks: &[openpgp::packet::SKESK],
        sym_algo: Option<SymmetricAlgorithm>,
        decrypt: &mut dyn FnMut(Option<SymmetricAlgorithm>, &SessionKey) -> bool,
    ) -> openpgp::Result<Option<Cert>> {
        // The encryption key is the first and only subkey.
        let key = self
            .secret
            .keys()
            .unencrypted_secret()
            .with_policy(self.policy, None)
            .for_transport_encryption()
            .nth(0)
            .unwrap()
            .key()
            .clone();

        // The secret key is not encrypted.
        let mut pair = key.into_keypair().unwrap();

        pkesks[0]
            .decrypt(&mut pair, sym_algo)
            .map(|(algo, session_key)| decrypt(algo, &session_key));

        // XXX: In production code, return the Fingerprint of the
        // recipient's Cert here
        Ok(None)
    }
}