use super::Algorithm;
use crate::error::{Error, Result};
use crate::object::Object;
use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum CertSubFilter {
Pkcs7S4,
#[default]
Pkcs7S5,
}
impl CertSubFilter {
pub fn as_pdf_name(&self) -> &'static str {
match self {
CertSubFilter::Pkcs7S4 => "adbe.pkcs7.s4",
CertSubFilter::Pkcs7S5 => "adbe.pkcs7.s5",
}
}
pub fn from_pdf_name(name: &str) -> Option<Self> {
match name {
"adbe.pkcs7.s4" => Some(CertSubFilter::Pkcs7S4),
"adbe.pkcs7.s5" => Some(CertSubFilter::Pkcs7S5),
_ => None,
}
}
pub fn algorithm(&self) -> Algorithm {
match self {
CertSubFilter::Pkcs7S4 => Algorithm::Aes128,
CertSubFilter::Pkcs7S5 => Algorithm::Aes256,
}
}
pub fn key_length(&self) -> usize {
match self {
CertSubFilter::Pkcs7S4 => 16, CertSubFilter::Pkcs7S5 => 32, }
}
}
#[derive(Debug, Clone)]
pub struct RecipientInfo {
pub certificate: Vec<u8>,
pub permissions: RecipientPermissions,
pub key_transport: KeyTransportAlgorithm,
}
impl RecipientInfo {
pub fn from_der(certificate: &[u8]) -> Result<Self> {
if certificate.is_empty() {
return Err(Error::InvalidPdf("Empty certificate data".to_string()));
}
if certificate[0] != 0x30 {
return Err(Error::InvalidPdf("Invalid certificate format".to_string()));
}
Ok(Self {
certificate: certificate.to_vec(),
permissions: RecipientPermissions::default(),
key_transport: KeyTransportAlgorithm::default(),
})
}
pub fn with_permissions(mut self, permissions: RecipientPermissions) -> Self {
self.permissions = permissions;
self
}
pub fn with_key_transport(mut self, algo: KeyTransportAlgorithm) -> Self {
self.key_transport = algo;
self
}
#[cfg(feature = "signatures")]
pub fn public_key(&self) -> Result<Vec<u8>> {
Err(Error::InvalidPdf("X.509 certificate parsing not yet implemented".to_string()))
}
}
#[derive(Debug, Clone, Copy)]
pub struct RecipientPermissions {
pub print: bool,
pub modify: bool,
pub copy: bool,
pub annotate: bool,
pub fill_forms: bool,
pub accessibility: bool,
pub assemble: bool,
pub print_high_quality: bool,
}
impl Default for RecipientPermissions {
fn default() -> Self {
Self {
print: true,
modify: true,
copy: true,
annotate: true,
fill_forms: true,
accessibility: true,
assemble: true,
print_high_quality: true,
}
}
}
impl RecipientPermissions {
pub fn full_access() -> Self {
Self::default()
}
pub fn read_only() -> Self {
Self {
print: false,
modify: false,
copy: false,
annotate: false,
fill_forms: false,
accessibility: true, assemble: false,
print_high_quality: false,
}
}
pub fn print_only() -> Self {
Self {
print: true,
modify: false,
copy: false,
annotate: false,
fill_forms: false,
accessibility: true,
assemble: false,
print_high_quality: true,
}
}
pub fn to_bits(&self) -> i32 {
let mut bits: i32 = 0xFFFFF0C0u32 as i32; if self.print {
bits |= 1 << 2;
}
if self.modify {
bits |= 1 << 3;
}
if self.copy {
bits |= 1 << 4;
}
if self.annotate {
bits |= 1 << 5;
}
if self.fill_forms {
bits |= 1 << 8;
}
if self.accessibility {
bits |= 1 << 9;
}
if self.assemble {
bits |= 1 << 10;
}
if self.print_high_quality {
bits |= 1 << 11;
}
bits
}
pub fn from_bits(bits: i32) -> Self {
Self {
print: (bits & (1 << 2)) != 0,
modify: (bits & (1 << 3)) != 0,
copy: (bits & (1 << 4)) != 0,
annotate: (bits & (1 << 5)) != 0,
fill_forms: (bits & (1 << 8)) != 0,
accessibility: (bits & (1 << 9)) != 0,
assemble: (bits & (1 << 10)) != 0,
print_high_quality: (bits & (1 << 11)) != 0,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum KeyTransportAlgorithm {
#[default]
RsaOaep,
RsaPkcs1v15,
}
#[derive(Debug)]
pub struct CertificateEncryption {
recipients: Vec<RecipientInfo>,
sub_filter: CertSubFilter,
encrypt_metadata: bool,
file_key: Vec<u8>,
}
impl CertificateEncryption {
pub fn new() -> Self {
Self {
recipients: Vec::new(),
sub_filter: CertSubFilter::default(),
encrypt_metadata: true,
file_key: Vec::new(),
}
}
pub fn add_recipient(mut self, recipient: RecipientInfo) -> Self {
self.recipients.push(recipient);
self
}
pub fn add_recipients(mut self, recipients: impl IntoIterator<Item = RecipientInfo>) -> Self {
self.recipients.extend(recipients);
self
}
pub fn sub_filter(mut self, sub_filter: CertSubFilter) -> Self {
self.sub_filter = sub_filter;
self
}
pub fn encrypt_metadata(mut self, encrypt: bool) -> Self {
self.encrypt_metadata = encrypt;
self
}
pub fn build(mut self) -> Result<CertificateEncryptionHandler> {
if self.recipients.is_empty() {
return Err(Error::InvalidPdf(
"At least one recipient is required for certificate encryption".to_string(),
));
}
let key_length = self.sub_filter.key_length();
self.file_key = generate_random_key(key_length)?;
let recipient_entries = self.create_recipient_entries()?;
Ok(CertificateEncryptionHandler {
sub_filter: self.sub_filter,
encrypt_metadata: self.encrypt_metadata,
file_key: self.file_key,
recipient_entries,
algorithm: self.sub_filter.algorithm(),
})
}
fn create_recipient_entries(&self) -> Result<Vec<Vec<u8>>> {
let mut entries = Vec::new();
for recipient in &self.recipients {
let entry = self.create_recipient_entry(recipient)?;
entries.push(entry);
}
Ok(entries)
}
fn create_recipient_entry(&self, recipient: &RecipientInfo) -> Result<Vec<u8>> {
let _ = recipient;
Ok(Vec::new())
}
}
impl Default for CertificateEncryption {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug)]
pub struct CertificateEncryptionHandler {
sub_filter: CertSubFilter,
encrypt_metadata: bool,
file_key: Vec<u8>,
recipient_entries: Vec<Vec<u8>>,
algorithm: Algorithm,
}
impl CertificateEncryptionHandler {
pub fn encrypt_dict(&self) -> CertEncryptDict {
CertEncryptDict {
filter: "Adobe.PubSec".to_string(),
sub_filter: self.sub_filter,
version: match self.sub_filter {
CertSubFilter::Pkcs7S4 => 4,
CertSubFilter::Pkcs7S5 => 5,
},
revision: match self.sub_filter {
CertSubFilter::Pkcs7S4 => 4,
CertSubFilter::Pkcs7S5 => 6,
},
encrypt_metadata: self.encrypt_metadata,
recipients: self.recipient_entries.clone(),
}
}
pub fn encryption_key(&self) -> &[u8] {
&self.file_key
}
pub fn algorithm(&self) -> Algorithm {
self.algorithm
}
pub fn should_encrypt_metadata(&self) -> bool {
self.encrypt_metadata
}
pub fn encrypt_string(&self, data: &[u8], obj_num: u32, gen_num: u16) -> Vec<u8> {
use super::write_handler::EncryptionWriteHandler;
let handler = EncryptionWriteHandler::from_key(
self.file_key.clone(),
self.algorithm,
self.encrypt_metadata,
);
handler.encrypt_string(data, obj_num, gen_num)
}
pub fn encrypt_stream(&self, data: &[u8], obj_num: u32, gen_num: u16) -> Vec<u8> {
use super::write_handler::EncryptionWriteHandler;
let handler = EncryptionWriteHandler::from_key(
self.file_key.clone(),
self.algorithm,
self.encrypt_metadata,
);
handler.encrypt_stream(data, obj_num, gen_num)
}
}
#[derive(Debug, Clone)]
pub struct CertEncryptDict {
pub filter: String,
pub sub_filter: CertSubFilter,
pub version: u32,
pub revision: u32,
pub encrypt_metadata: bool,
pub recipients: Vec<Vec<u8>>,
}
impl CertEncryptDict {
pub fn to_object(&self) -> Object {
let mut dict: HashMap<String, Object> = HashMap::new();
dict.insert("Filter".to_string(), Object::Name(self.filter.clone()));
dict.insert(
"SubFilter".to_string(),
Object::Name(self.sub_filter.as_pdf_name().to_string()),
);
dict.insert("V".to_string(), Object::Integer(self.version as i64));
dict.insert("R".to_string(), Object::Integer(self.revision as i64));
if !self.encrypt_metadata {
dict.insert("EncryptMetadata".to_string(), Object::Boolean(false));
}
let recipients_array: Vec<Object> = self
.recipients
.iter()
.map(|r| Object::String(r.clone()))
.collect();
dict.insert("Recipients".to_string(), Object::Array(recipients_array));
if self.version >= 4 {
let cfm = match self.sub_filter {
CertSubFilter::Pkcs7S4 => "AESV2",
CertSubFilter::Pkcs7S5 => "AESV3",
};
let key_length = match self.sub_filter {
CertSubFilter::Pkcs7S4 => 16,
CertSubFilter::Pkcs7S5 => 32,
};
let mut cf_dict: HashMap<String, Object> = HashMap::new();
let mut std_cf: HashMap<String, Object> = HashMap::new();
std_cf.insert("CFM".to_string(), Object::Name(cfm.to_string()));
std_cf.insert("AuthEvent".to_string(), Object::Name("DocOpen".to_string()));
std_cf.insert("Length".to_string(), Object::Integer(key_length));
cf_dict.insert("DefaultCryptFilter".to_string(), Object::Dictionary(std_cf));
dict.insert("CF".to_string(), Object::Dictionary(cf_dict));
dict.insert("StmF".to_string(), Object::Name("DefaultCryptFilter".to_string()));
dict.insert("StrF".to_string(), Object::Name("DefaultCryptFilter".to_string()));
}
Object::Dictionary(dict)
}
}
fn generate_random_key(length: usize) -> Result<Vec<u8>> {
use std::time::{SystemTime, UNIX_EPOCH};
let mut key = Vec::with_capacity(length);
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default();
let time_nanos = now.as_nanos();
use md5::{Digest, Md5};
let mut hasher = Md5::new();
hasher.update(time_nanos.to_le_bytes());
hasher.update(std::process::id().to_le_bytes());
while key.len() < length {
let hash = hasher.finalize_reset();
key.extend_from_slice(&hash);
hasher.update(&key);
hasher.update(time_nanos.wrapping_add(key.len() as u128).to_le_bytes());
}
key.truncate(length);
Ok(key)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cert_sub_filter() {
assert_eq!(CertSubFilter::Pkcs7S4.as_pdf_name(), "adbe.pkcs7.s4");
assert_eq!(CertSubFilter::Pkcs7S5.as_pdf_name(), "adbe.pkcs7.s5");
assert_eq!(CertSubFilter::from_pdf_name("adbe.pkcs7.s4"), Some(CertSubFilter::Pkcs7S4));
assert_eq!(CertSubFilter::from_pdf_name("adbe.pkcs7.s5"), Some(CertSubFilter::Pkcs7S5));
assert_eq!(CertSubFilter::from_pdf_name("unknown"), None);
}
#[test]
fn test_recipient_permissions_bits() {
let perms = RecipientPermissions::full_access();
let bits = perms.to_bits();
assert!(bits & (1 << 2) != 0); assert!(bits & (1 << 3) != 0); assert!(bits & (1 << 4) != 0);
let restored = RecipientPermissions::from_bits(bits);
assert!(restored.print);
assert!(restored.modify);
assert!(restored.copy);
}
#[test]
fn test_recipient_permissions_read_only() {
let perms = RecipientPermissions::read_only();
assert!(!perms.print);
assert!(!perms.modify);
assert!(!perms.copy);
assert!(perms.accessibility); }
#[test]
fn test_recipient_info_creation() {
let mock_cert = vec![0x30, 0x82, 0x01, 0x00, 0x00]; let recipient = RecipientInfo::from_der(&mock_cert);
assert!(recipient.is_ok());
let invalid_cert = vec![0xFF, 0xFF];
let invalid = RecipientInfo::from_der(&invalid_cert);
assert!(invalid.is_err());
let empty = RecipientInfo::from_der(&[]);
assert!(empty.is_err());
}
#[test]
fn test_certificate_encryption_builder() {
let mock_cert = vec![0x30, 0x82, 0x01, 0x00, 0x00];
let recipient = RecipientInfo::from_der(&mock_cert).unwrap();
let encryptor = CertificateEncryption::new()
.add_recipient(recipient)
.sub_filter(CertSubFilter::Pkcs7S5)
.encrypt_metadata(true)
.build();
assert!(encryptor.is_ok());
}
#[test]
fn test_certificate_encryption_no_recipients() {
let result = CertificateEncryption::new().build();
assert!(result.is_err());
}
#[test]
fn test_cert_encrypt_dict_to_object() {
let dict = CertEncryptDict {
filter: "Adobe.PubSec".to_string(),
sub_filter: CertSubFilter::Pkcs7S5,
version: 5,
revision: 6,
encrypt_metadata: true,
recipients: vec![vec![1, 2, 3]],
};
let obj = dict.to_object();
if let Object::Dictionary(d) = obj {
assert!(d.contains_key("Filter"));
assert!(d.contains_key("SubFilter"));
assert!(d.contains_key("V"));
assert!(d.contains_key("R"));
assert!(d.contains_key("Recipients"));
assert!(d.contains_key("CF")); } else {
panic!("Expected dictionary");
}
}
#[test]
fn test_generate_random_key() {
let key16 = generate_random_key(16).unwrap();
assert_eq!(key16.len(), 16);
let key32 = generate_random_key(32).unwrap();
assert_eq!(key32.len(), 32);
let key1 = generate_random_key(16).unwrap();
let key2 = generate_random_key(16).unwrap();
}
#[test]
fn test_key_transport_algorithm_default() {
let algo = KeyTransportAlgorithm::default();
assert_eq!(algo, KeyTransportAlgorithm::RsaOaep);
}
}