sequoia_openpgp/packet/skesk/
v4.rs1#[cfg(test)]
10use quickcheck::{Arbitrary, Gen};
11
12use crate::Result;
13use crate::crypto::{
14 S2K,
15 Password,
16 SessionKey,
17};
18
19use crate::Error;
20use crate::types::{
21 SymmetricAlgorithm,
22};
23use crate::packet::{self, SKESK};
24use crate::Packet;
25
26#[derive(Clone, Debug)]
34pub struct SKESK4 {
35 pub(crate) common: packet::Common,
37
38 pub(crate) version: u8,
43
44 pub(crate) sym_algo: SymmetricAlgorithm,
46
47 pub(crate) s2k: S2K,
49
50 pub(crate) esk: std::result::Result<Option<Box<[u8]>>, Box<[u8]>>, }
60assert_send_and_sync!(SKESK4);
61
62impl PartialEq for SKESK4 {
66 fn eq(&self, other: &SKESK4) -> bool {
67 self.version == other.version
68 && self.sym_algo == other.sym_algo
69 && {
71 use crate::serialize::MarshalInto;
73 let mut a = self.s2k.to_vec().unwrap();
74 let mut b = other.s2k.to_vec().unwrap();
75 a.extend_from_slice(self.raw_esk());
76 b.extend_from_slice(other.raw_esk());
77 a == b
78 }
79 }
80}
81
82impl Eq for SKESK4 {}
83
84impl std::hash::Hash for SKESK4 {
85 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
86 self.version.hash(state);
87 self.sym_algo.hash(state);
88 use crate::serialize::MarshalInto;
91 let mut a = self.s2k.to_vec().unwrap();
92 a.extend_from_slice(self.raw_esk());
93 a.hash(state);
94 }
95}
96
97impl SKESK4 {
98 pub fn new(esk_algo: SymmetricAlgorithm, s2k: S2K,
103 esk: Option<Box<[u8]>>) -> Result<SKESK4> {
104 Self::new_raw(esk_algo, s2k, Ok(esk.and_then(|esk| {
105 if esk.len() == 0 { None } else { Some(esk) }
106 })))
107 }
108
109 pub(crate) fn new_raw(esk_algo: SymmetricAlgorithm, s2k: S2K,
114 esk: std::result::Result<Option<Box<[u8]>>,
115 Box<[u8]>>)
116 -> Result<SKESK4> {
117 Ok(SKESK4{
118 common: Default::default(),
119 version: 4,
120 sym_algo: esk_algo,
121 s2k,
122 esk,
123 })
124 }
125
126 pub fn with_password(payload_algo: SymmetricAlgorithm,
140 esk_algo: SymmetricAlgorithm,
141 s2k: S2K,
142 session_key: &SessionKey, password: &Password)
143 -> Result<SKESK4> {
144 if session_key.len() != payload_algo.key_size()? {
145 return Err(Error::InvalidArgument(format!(
146 "Invalid size of session key, got {} want {}",
147 session_key.len(), payload_algo.key_size()?)).into());
148 }
149
150 let key = s2k.derive_key(password, esk_algo.key_size()?)?;
152 let block_size = esk_algo.block_size()?;
153
154 use crate::crypto::symmetric::BlockCipherMode;
155 use crate::crypto::backend::{Backend, interface::Symmetric};
156 let mut cipher = Backend::encryptor(esk_algo, BlockCipherMode::CFB,
157 key.as_protected(), None)?;
158
159 let mut psk: SessionKey = vec![0; 1 + session_key.len()].into();
161 psk[0] = payload_algo.into();
162 psk[1..].copy_from_slice(session_key);
163 let mut esk = vec![0u8; psk.len()];
164
165 for (pt, ct) in psk[..].chunks(block_size)
166 .zip(esk.chunks_mut(block_size)) {
167 cipher.encrypt(ct, pt)?;
168 }
169
170 SKESK4::new(esk_algo, s2k, Some(esk.into()))
171 }
172
173 pub fn symmetric_algo(&self) -> SymmetricAlgorithm {
175 self.sym_algo
176 }
177
178 pub fn set_symmetric_algo(&mut self, algo: SymmetricAlgorithm) -> SymmetricAlgorithm {
180 ::std::mem::replace(&mut self.sym_algo, algo)
181 }
182
183 pub fn s2k(&self) -> &S2K {
185 &self.s2k
186 }
187
188 pub fn set_s2k(&mut self, s2k: S2K) -> S2K {
190 ::std::mem::replace(&mut self.s2k, s2k)
191 }
192
193 pub fn esk(&self) -> Result<Option<&[u8]>> {
202 self.esk.as_ref()
203 .map(|esko| esko.as_ref().map(|esk| &esk[..]))
204 .map_err(|_| Error::MalformedPacket(
205 format!("Unknown S2K: {:?}", self.s2k)).into())
206 }
207
208 pub(crate) fn raw_esk(&self) -> &[u8] {
211 match self.esk.as_ref() {
212 Ok(Some(esk)) => &esk[..],
213 Ok(None) => &[][..],
214 Err(s2k_esk) => &s2k_esk[..],
215 }
216 }
217
218 pub fn set_esk(&mut self, esk: Option<Box<[u8]>>) -> Option<Box<[u8]>> {
220 ::std::mem::replace(
221 &mut self.esk,
222 Ok(esk.and_then(|esk| {
223 if esk.len() == 0 { None } else { Some(esk) }
224 })))
225 .unwrap_or(None)
226 }
227
228 pub fn decrypt(&self, password: &Password)
233 -> Result<(SymmetricAlgorithm, SessionKey)>
234 {
235 let key = self.s2k.derive_key(password, self.sym_algo.key_size()?)?;
236
237 if let Some(esk) = self.esk()? {
238 let blk_sz = self.sym_algo.block_size()?;
241
242 use crate::crypto::symmetric::BlockCipherMode;
243 use crate::crypto::backend::{Backend, interface::Symmetric};
244 let mut dec = Backend::decryptor(self.sym_algo, BlockCipherMode::CFB,
245 key.as_protected(), None)?;
246
247 let mut plain: SessionKey = vec![0u8; esk.len()].into();
248 let cipher = esk;
249
250 for (pl, ct)
251 in plain[..].chunks_mut(blk_sz).zip(cipher.chunks(blk_sz))
252 {
253 dec.decrypt(pl, ct)?;
254 }
255
256 let sym = SymmetricAlgorithm::from(plain[0]);
258 Ok((sym, plain[1..].into()))
259 } else {
260 Ok((self.sym_algo, key))
262 }
263 }
264}
265
266impl From<SKESK4> for super::SKESK {
267 fn from(p: SKESK4) -> Self {
268 super::SKESK::V4(p)
269 }
270}
271
272impl From<SKESK4> for Packet {
273 fn from(s: SKESK4) -> Self {
274 Packet::SKESK(SKESK::V4(s))
275 }
276}
277
278#[cfg(test)]
279impl Arbitrary for SKESK4 {
280 fn arbitrary(g: &mut Gen) -> Self {
281 SKESK4::new(SymmetricAlgorithm::arbitrary(g),
282 S2K::arbitrary(g),
283 Option::<Vec<u8>>::arbitrary(g).map(|v| v.into()))
284 .unwrap()
285 }
286}
287
288#[cfg(test)]
289mod test {
290 use super::*;
291 use crate::parse::Parse;
292 use crate::serialize::MarshalInto;
293
294 quickcheck! {
295 fn roundtrip_v4(p: SKESK4) -> bool {
296 let p = SKESK::from(p);
297 let q = SKESK::from_bytes(&p.to_vec().unwrap()).unwrap();
298 assert_eq!(p, q);
299 true
300 }
301 }
302
303 #[test]
306 fn skesk4_s2k_variants() -> Result<()> {
307 use std::io::Read;
308 use crate::{
309 Cert,
310 packet::{SKESK, PKESK},
311 parse::stream::*,
312 };
313
314 struct H();
315 impl VerificationHelper for H {
316 fn get_certs(&mut self, _ids: &[crate::KeyHandle])
317 -> Result<Vec<Cert>> {
318 Ok(Vec::new())
319 }
320
321 fn check(&mut self, _m: MessageStructure)
322 -> Result<()> {
323 Ok(())
324 }
325 }
326
327 impl DecryptionHelper for H {
328 fn decrypt(&mut self, _: &[PKESK], skesks: &[SKESK],
329 _: Option<SymmetricAlgorithm>,
330 decrypt: &mut dyn FnMut(Option<SymmetricAlgorithm>, &SessionKey) -> bool)
331 -> Result<Option<Cert>>
332 {
333 assert_eq!(skesks.len(), 1);
334 let (cipher, sk) = skesks[0].decrypt(&"password".into())?;
335 assert_eq!(cipher, Some(SymmetricAlgorithm::AES256));
336 let r = decrypt(cipher, &sk);
337 assert!(r);
338 Ok(None)
339 }
340 }
341
342 let p = &crate::policy::StandardPolicy::new();
343 for variant in &["simple", "salted", "iterated.min", "iterated.max"] {
344 for esk in &["", ".esk"] {
345 let name = format!("s2k/{}{}.pgp", variant, esk);
346 eprintln!("{}", name);
347 let mut verifier = DecryptorBuilder::from_bytes(
348 crate::tests::message(&name))?
349 .with_policy(p, None, H())?;
350 let mut b = Vec::new();
351 verifier.read_to_end(&mut b)?;
352 assert_eq!(&b, b"Hello World :)");
353 }
354 }
355
356 Ok(())
357 }
358}