use std::{
io,
io::{BufReader, Read, stdout},
};
use minipgp6::{keygen::generate_tsk, locking::try_unlock_with_passwords};
use minipgp6_armor::{DataType, read::Dearmorer, write::Armorer};
use minipgp6_encrypt::message::{MessageDecryptor, MessageEncryptor};
use minipgp6_packet::{
body::literal::{LiteralReader, LiteralWriter},
sequence::PacketSequence,
transferable::{Tpk, Tsk},
types::algorithm::PublicKeyAlgorithm,
};
use minipgp6_validity::Checked;
use rand::thread_rng;
fn encrypt(cert: &Tpk, mut data: &[u8]) -> Result<String, Box<dyn std::error::Error>> {
let mut rng = thread_rng();
let checked = Checked::from(cert);
let encryptors = checked.valid_for_encryption();
let mut armored = Vec::new();
{
let mut armorer = Armorer::new(&mut armored, DataType::Message)?;
{
let mut encryptor = MessageEncryptor::new(&mut rng, &mut armorer, &encryptors)?;
let mut literal = LiteralWriter::new(&mut encryptor)?;
let _ = io::copy(&mut data, &mut literal)?;
}
armorer.finalize()?;
}
Ok(String::from_utf8(armored)?)
}
fn decrypt(tsk: &Tsk, armored: String) -> Result<(), Box<dyn std::error::Error>> {
let checked = Checked::from(tsk);
let decryptors = checked.valid_for_decryption();
let unlocked_decryptors: Vec<_> = decryptors
.into_iter()
.flat_map(|s| try_unlock_with_passwords(s, &[]))
.collect();
let dearmor = Dearmorer::new(armored.as_bytes())?;
let sequence = PacketSequence::new(BufReader::new(dearmor));
let message = MessageDecryptor::new(sequence)?;
let mut payload_decryptor = message.decrypt(&unlocked_decryptors)?;
let mut plaintext: Vec<u8> = Vec::new();
let decrypted_sequence = PacketSequence::new(BufReader::new(&mut payload_decryptor));
match decrypted_sequence.next_streaming() {
Ok(stream) => {
let mut lit = LiteralReader::try_from(stream)?;
let _ = lit.read_to_end(&mut plaintext)?;
}
_ => return Err("failed to decrypt".into()),
}
eprintln!("Decrypted message: {:?}", String::from_utf8(plaintext)?);
Ok(())
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
const PAYLOAD: &str = "hello world";
let mut rng = thread_rng();
let tsk = generate_tsk(
&mut rng,
PublicKeyAlgorithm::Ed25519,
Some(PublicKeyAlgorithm::MlKem768X25519),
&["alice"],
None,
)?;
let cert = Tpk::from(tsk.clone());
let encrypted = encrypt(&cert, PAYLOAD.as_bytes())?;
eprintln!("Encrypted message:");
eprintln!("{encrypted}");
eprintln!();
eprintln!("OpenPGP TSK:");
let mut out = Armorer::new(stdout(), DataType::Private)?;
tsk.to_writer(&mut out)?;
out.finalize()?;
eprintln!();
decrypt(&tsk, encrypted)?;
Ok(())
}