use std::io::{self, Write};
extern crate sequoia_openpgp as openpgp;
use crate::openpgp::cert::prelude::*;
use crate::openpgp::serialize::stream::*;
use crate::openpgp::parse::{Parse, stream::*};
use crate::openpgp::policy::Policy;
use crate::openpgp::policy::StandardPolicy as P;
const MESSAGE: &'static str = "дружба";
fn main() {
let p = &P::new();
let key = generate().unwrap();
let mut signed_message = Vec::new();
sign(p, &mut signed_message, MESSAGE, &key).unwrap();
let mut plaintext = Vec::new();
verify(p, &mut plaintext, &signed_message, &key).unwrap();
assert_eq!(MESSAGE.as_bytes(), &plaintext[..]);
}
fn generate() -> openpgp::Result<openpgp::Cert> {
let (cert, _revocation) = CertBuilder::new()
.add_userid("someone@example.org")
.add_signing_subkey()
.generate()?;
Ok(cert)
}
fn sign(p: &dyn Policy, sink: &mut dyn Write, plaintext: &str, tsk: &openpgp::Cert)
-> openpgp::Result<()> {
let keypair = tsk
.keys().unencrypted_secret()
.with_policy(p, None).alive().revoked(false).for_signing()
.nth(0).unwrap().key().clone().into_keypair()?;
let message = Message::new(sink);
let signer = Signer::new(message, keypair).build()?;
let mut literal_writer = LiteralWriter::new(signer).build()?;
literal_writer.write_all(plaintext.as_bytes())?;
literal_writer.finalize()?;
Ok(())
}
fn verify(p: &dyn Policy, sink: &mut dyn Write,
signed_message: &[u8], sender: &openpgp::Cert)
-> openpgp::Result<()> {
let helper = Helper {
cert: sender,
};
let mut verifier = VerifierBuilder::from_bytes(signed_message)?
.with_policy(p, None, helper)?;
io::copy(&mut verifier, sink)?;
Ok(())
}
struct Helper<'a> {
cert: &'a openpgp::Cert,
}
impl<'a> VerificationHelper for Helper<'a> {
fn get_certs(&mut self, _ids: &[openpgp::KeyHandle])
-> openpgp::Result<Vec<openpgp::Cert>> {
Ok(vec![self.cert.clone()])
}
fn check(&mut self, structure: MessageStructure)
-> openpgp::Result<()> {
let mut good = false;
for (i, layer) in structure.into_iter().enumerate() {
match (i, layer) {
(0, MessageLayer::SignatureGroup { results }) => {
match results.into_iter().next() {
Some(Ok(_)) =>
good = true,
Some(Err(e)) =>
return Err(openpgp::Error::from(e).into()),
None =>
return Err(anyhow::anyhow!("No signature")),
}
},
_ => return Err(anyhow::anyhow!(
"Unexpected message structure")),
}
}
if good {
Ok(()) } else {
Err(anyhow::anyhow!("Signature verification failed"))
}
}
}