It seems that sequoia provides all the necessary functionality for sett. I was able to crate a short PoC for the encryption workflow in Rust using sequoia. As with the transfer workflow it's possible to expose this encrypt workflow to Python and replace the original workflow implementation. I expect that the decrypt workflow and key management can be also implemented with sequoia. One thing I didn't explore was key signature verification. However, since we are going to move to a different key verification process, key signature verification is not needed any more. In summary, we should be able completely drop gnupg in favor of sequoia.
I was not able to find multi-threading support for encryption, but it should be possible to add multi-threading to the compression step using gzp, a library inspired by pigz. Which should significantly improve the overall encryption workflow speed.
Clone sett-rs and add the code below to sett-rs/examples/encrypt.rs (note: you could also create an empty project, but using sett-rs is probably faster since the file structure is already present).
In the current working directory (sett-rs repo root) create a data directory with some files (and/or directories) inside.
Run the command below to test the PoC.
# Create a new PGP keysq key generate --userid"Chuck <chuck@example.org>"--export chuck.key.pgp# Extract the public keysq key extract-cert --output chuck.cert.pgp chuck.key.pgp# Run the PoC encryption workflow: tar and compress files inside of the `data`# directory, encrypt the archive using the generated public key, and store# the encrypted archive in a zip filecargo run --release--example encrypt -- chuck.cert.pgp# Confirm that compression and encryption workedunzip dpkg.zipsq inspect data.tar.gz.pgpsq decrypt --recipient-key chuck.key.pgp -o data.tar.gz data.tar.gz.pgptar--list-f data.tar.gz
The PoC (place the code in the examples directory).
usestd::fs::File;usestd::path::Path;externcratesequoia_openpgpasopenpgp;useflate2::write::GzEncoder;useflate2::Compression;useopenpgp::parse::Parse;useopenpgp::policy::{Policy,StandardPolicy};useopenpgp::serialize::stream::{Encryptor,LiteralWriter,Message};usezip::{write::FileOptions,CompressionMethod,ZipWriter};fncompress_and_encrypt(input:&str,output:&str,policy:&dynPolicy,recipient:&openpgp::Cert,)->openpgp::Result<()>{letrecipients=recipient.keys().with_policy(policy,None).supported().alive().revoked(false).for_transport_encryption();letpackage_file=File::create(output)?;letmutzip=ZipWriter::new(package_file);letoptions=FileOptions::default().compression_method(CompressionMethod::Stored);zip.start_file("data.tar.gz.pgp",options)?;// Start streaming an OpenPGP message.letmessage=Message::new(&mutzip);letmessage=Encryptor::for_recipients(message,recipients).build()?;letmutwriter=LiteralWriter::new(message).build()?;// Encrypt the data.{letenc=GzEncoder::new(&mutwriter,Compression::default());letmuttar=tar::Builder::new(enc);tar.append_dir_all(input,input)?;}// Finalize the OpenPGP message to make sure that all data is written.writer.finalize()?;// Finish the last file and write all other zip-structureszip.finish()?;Ok(())}fnmain()->Result<(),String>{letcertificate=std::env::args().nth(1).ok_or("No key passed".to_string())?;letkey=openpgp::Cert::from_file(Path::new(&certificate)).unwrap();letpolicy=&StandardPolicy::new();compress_and_encrypt("data","dpkg.zip",policy,&key).unwrap();Ok(())}