1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
use secrecy::SecretString;
use std::io::Read;
use super::{v1_payload_key, Callbacks, NoCallbacks};
use crate::{
error::Error,
format::{Header, RecipientLine},
keys::{FileKey, Identity},
primitives::{
armor::ArmoredReader,
stream::{Stream, StreamReader},
},
};
struct BaseDecryptor<R: Read> {
input: ArmoredReader<R>,
header: Header,
}
impl<R: Read> BaseDecryptor<R> {
fn obtain_payload_key<F>(&mut self, filter: F) -> Result<[u8; 32], Error>
where
F: FnMut(&RecipientLine) -> Option<Result<FileKey, Error>>,
{
match &self.header {
Header::V1(header) => {
let mut nonce = [0; 16];
self.input.read_exact(&mut nonce)?;
header
.recipients
.iter()
.find_map(filter)
.unwrap_or(Err(Error::NoMatchingKeys))
.and_then(|file_key| v1_payload_key(header, file_key, nonce))
}
Header::Unknown(_) => unreachable!(),
}
}
}
pub struct RecipientsDecryptor<R: Read>(BaseDecryptor<R>);
impl<R: Read> RecipientsDecryptor<R> {
pub(super) fn new(input: ArmoredReader<R>, header: Header) -> Self {
RecipientsDecryptor(BaseDecryptor { input, header })
}
pub fn decrypt(self, identities: &[Identity]) -> Result<StreamReader<R>, Error> {
self.decrypt_with_callbacks(identities, &NoCallbacks)
}
pub fn decrypt_with_callbacks(
mut self,
identities: &[Identity],
callbacks: &dyn Callbacks,
) -> Result<StreamReader<R>, Error> {
self.0
.obtain_payload_key(|r| {
identities
.iter()
.find_map(|key| key.unwrap_file_key(r, callbacks))
})
.map(|payload_key| Stream::decrypt(&payload_key, self.0.input))
}
}
pub struct PassphraseDecryptor<R: Read>(BaseDecryptor<R>);
impl<R: Read> PassphraseDecryptor<R> {
pub(super) fn new(input: ArmoredReader<R>, header: Header) -> Self {
PassphraseDecryptor(BaseDecryptor { input, header })
}
pub fn decrypt(
mut self,
passphrase: &SecretString,
max_work_factor: Option<u8>,
) -> Result<StreamReader<R>, Error> {
self.0
.obtain_payload_key(|r| {
if let RecipientLine::Scrypt(s) = r {
s.unwrap_file_key(passphrase, max_work_factor).transpose()
} else {
None
}
})
.map(|payload_key| Stream::decrypt(&payload_key, self.0.input))
}
}