1mod crypto;
34mod format;
35mod method;
36mod ole;
37
38use crypto::{AgileEncryptionInfo, StandardEncryptionInfo};
39use format::doc97;
40use ole::OleFile;
41use std::path::Path;
42use thiserror::Error;
43
44macro_rules! validate {
45 ($assert:expr, $err:expr) => {{
46 if ($assert) {
47 Ok(())
48 } else {
49 let error_code: DecryptError = $err;
50 Err(error_code)
51 }
52 }};
53}
54
55pub(crate) use validate;
56
57pub fn decrypt_from_file<P: AsRef<Path>>(path: P, password: &str) -> Result<Vec<u8>, DecryptError> {
61 let mut olefile = OleFile::from_file(path)?;
62 olefile.init()?;
63
64 decrypt(&mut olefile, password)
65}
66
67pub fn decrypt_from_bytes(raw: Vec<u8>, password: &str) -> Result<Vec<u8>, DecryptError> {
71 let mut olefile = OleFile::new(raw)?;
72 olefile.init()?;
73
74 decrypt(&mut olefile, password)
75}
76
77fn decrypt(olefile: &mut OleFile, password: &str) -> Result<Vec<u8>, DecryptError> {
78 if olefile.exists(&["EncryptionInfo".to_owned()])? {
80 decrypt_ooxml(olefile, password)
81 } else if olefile.exists(&["WordDocument".to_owned()])? {
82 doc97::decrypt_doc97(olefile, password)
83 } else if olefile.exists(&["Workbook".to_owned()])? {
84 Err(DecryptError::Unimplemented(
85 "Excel binary format (.xls) not yet supported".to_owned(),
86 ))
87 } else if olefile.exists(&["Current User".to_owned()])? {
88 Err(DecryptError::Unimplemented(
89 "PowerPoint binary format (.ppt) not yet supported".to_owned(),
90 ))
91 } else {
92 Err(DecryptError::InvalidStructure)
93 }
94}
95
96fn decrypt_ooxml(olefile: &mut OleFile, password: &str) -> Result<Vec<u8>, DecryptError> {
97 let encryption_info_stream = olefile.open_stream(&["EncryptionInfo".to_owned()])?;
98 let encrypted_package_stream = olefile.open_stream(&["EncryptedPackage".to_owned()])?;
99
100 match encryption_info_stream.stream.get(..4) {
101 Some([4, 0, 4, 0]) => {
102 let aei = AgileEncryptionInfo::new(&encryption_info_stream)?;
103 let secret_key = aei.key_from_password(password)?;
104
105 aei.decrypt(&secret_key, &encrypted_package_stream)
106 }
107 Some([2 | 3 | 4, 0, 2, 0]) => {
108 let sei = StandardEncryptionInfo::new(&encryption_info_stream)?;
109 let secret_key = sei.key_from_password(password)?;
110
111 sei.decrypt(&secret_key, &encrypted_package_stream)
112 }
113 _ => Err(DecryptError::InvalidStructure),
114 }
115}
116
117#[derive(Error, Debug)]
118pub enum DecryptError {
119 #[error("IO Error")]
120 IoError(std::io::Error),
121 #[error("Invalid Olefile Header")]
122 InvalidHeader,
123 #[error("Invalid File Structure")]
124 InvalidStructure,
125 #[error("File is not encrypted")]
126 NotEncrypted,
127 #[error("Unimplemented: `{0}`")]
128 Unimplemented(String),
129 #[error("Unknown Error")]
130 Unknown,
131}