Files
pdfcraft/crates/cos/examples/protect.rs
T
aiongg b72c730a95 fix(cos): give the protect example a fresh key on every run
The example passed a constant seed to set_encryption. AES-256 derives the
file key from the seed alone, so anyone could rebuild the key and read a
file it protected without either password. The seed now comes from the
operating system's randomness through RandomState, as in the engine.
2026-10-22 12:13:16 -04:00

36 lines
1.5 KiB
Rust

//! Encrypt a PDF: `cargo run -p pdfcraft-cos --example protect in.pdf out.pdf rc4-40|rc4-128|aes-128|aes-256 USER OWNER`
/// 32 fresh bytes for the file key. `RandomState` is seeded by the operating system (as the
/// engine's `entropy` uses it), so every run encrypts with a different key.
fn seed() -> [u8; 32] {
use std::hash::{BuildHasher, Hasher};
let mut out = [0u8; 32];
for (i, chunk) in out.chunks_mut(8).enumerate() {
let mut h = std::collections::hash_map::RandomState::new().build_hasher();
h.write_usize(i);
chunk.copy_from_slice(&h.finish().to_le_bytes());
}
out
}
fn main() {
let a: Vec<String> = std::env::args().skip(1).collect();
let [input, output, alg, user, owner] = &a[..] else { panic!("usage: protect in out alg user owner") };
let algorithm = match alg.as_str() {
"rc4-40" => pdfcraft_cos::Algorithm::Rc4_40,
"rc4-128" => pdfcraft_cos::Algorithm::Rc4_128,
"aes-128" => pdfcraft_cos::Algorithm::Aes128,
_ => pdfcraft_cos::Algorithm::Aes256,
};
let mut doc = pdfcraft_cos::Document::open(std::sync::Arc::new(std::fs::read(input).unwrap())).unwrap();
doc.set_encryption(&pdfcraft_cos::NewEncryption {
algorithm,
user_password: user,
owner_password: owner,
permissions: -1,
encrypt_metadata: true,
seed: seed(),
})
.unwrap();
std::fs::write(output, pdfcraft_cos::write_full(&doc, &Default::default()).unwrap()).unwrap();
}