99 lines
3.1 KiB
Rust
99 lines
3.1 KiB
Rust
extern crate sequoia_openpgp as openpgp;
|
|
use crate::openpgp::armor;
|
|
use std::{
|
|
fs::File,
|
|
path::Path,
|
|
io::{ ErrorKind, Read, Write, BufWriter },
|
|
};
|
|
use rust_util::{ XResult, new_box_error };
|
|
use openpgp::{
|
|
Cert,
|
|
parse::Parse,
|
|
types::KeyFlags,
|
|
serialize::stream::{
|
|
Message,
|
|
Encryptor2,
|
|
LiteralWriter,
|
|
},
|
|
policy::StandardPolicy as P,
|
|
};
|
|
use indicatif::{ ProgressBar, ProgressStyle };
|
|
|
|
const BUFF_SIZE: usize = 512 * 1024;
|
|
const PB_PROGRESS: &str = "#-";
|
|
const PB_TEMPLATE: &str = "{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({eta})";
|
|
|
|
pub struct OpenPGPTool {
|
|
pub cert: Cert,
|
|
}
|
|
|
|
impl OpenPGPTool {
|
|
pub fn from_file(file: &str) -> XResult<OpenPGPTool> {
|
|
Ok(OpenPGPTool{
|
|
cert: Cert::from_file(Path::new(file))?,
|
|
})
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
pub fn from_bytes(bs: &[u8]) -> XResult<OpenPGPTool> {
|
|
Ok(OpenPGPTool{
|
|
cert: Cert::from_bytes(&bs)?,
|
|
})
|
|
}
|
|
|
|
pub fn encrypt_file(&self, from_file: &str, to_file: &str, armor: bool) -> XResult<()> {
|
|
if !Path::new(from_file).exists() {
|
|
return Err(new_box_error(&format!("From file NOT exists: {}", from_file)));
|
|
}
|
|
if Path::new(to_file).exists() {
|
|
return Err(new_box_error(&format!("To file exists: {}", to_file)));
|
|
}
|
|
|
|
// https://gitlab.com/sequoia-pgp/sequoia/-/blob/master/openpgp/examples/encrypt-for.rs
|
|
let p = &P::new();
|
|
let mode = KeyFlags::empty().set_storage_encryption();
|
|
let recipients = self.cert.keys()
|
|
.with_policy(p, None).alive().revoked(false).key_flags(&mode)
|
|
.map(|ka| ka.key())
|
|
.collect::<Vec<_>>();
|
|
if recipients.is_empty() {
|
|
return Err(new_box_error("Cannot find any encrypt key in pgp key file."));
|
|
}
|
|
let bw = BufWriter::new(File::create(to_file)?);
|
|
let message = if armor {
|
|
Message::new(armor::Writer::new(bw, armor::Kind::Message)?)
|
|
} else {
|
|
Message::new(bw)
|
|
};
|
|
let encryptor = Encryptor2::for_recipients(message, recipients).build()?;
|
|
let mut pgp_encrypt_writer = LiteralWriter::new(encryptor).build()?;
|
|
let mut from = File::open(from_file)?;
|
|
encrypt_read_write(&mut from, &mut pgp_encrypt_writer)?;
|
|
pgp_encrypt_writer.finalize()?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
fn encrypt_read_write(file: &mut File, write: &mut dyn Write) -> XResult<()> {
|
|
let mut buf: [u8; BUFF_SIZE] = [0u8; BUFF_SIZE];
|
|
let file_len = file.metadata()?.len();
|
|
let mut read = 0_u64;
|
|
|
|
let pb = ProgressBar::new(file_len);
|
|
pb.set_style(ProgressStyle::default_bar().template(PB_TEMPLATE)?.progress_chars(PB_PROGRESS));
|
|
|
|
loop {
|
|
let len = match file.read(&mut buf) {
|
|
Ok(0) => { pb.finish_and_clear(); return Ok(()); },
|
|
Ok(len) => len,
|
|
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
|
|
Err(e) => return Err(Box::new(e)),
|
|
};
|
|
write.write_all(&buf[..len])?;
|
|
read += len as u64;
|
|
pb.set_position(read);
|
|
}
|
|
}
|
|
|