sequoia_openpgp/packet/skesk/
v6.rs1#[cfg(test)]
10use quickcheck::{Arbitrary, Gen};
11
12use crate::Result;
13use crate::crypto::{
14 self,
15 S2K,
16 Password,
17 SessionKey,
18 backend::{Backend, interface::Kdf},
19};
20use crate::Error;
21use crate::types::{
22 AEADAlgorithm,
23 SymmetricAlgorithm,
24};
25use crate::packet::{
26 Packet,
27 SKESK,
28 skesk::SKESK4,
29};
30
31#[derive(Clone, Debug, PartialEq, Eq, Hash)]
39pub struct SKESK6 {
40 pub(crate) skesk4: SKESK4,
42
43 aead_algo: AEADAlgorithm,
45
46 aead_iv: Box<[u8]>,
48}
49assert_send_and_sync!(SKESK6);
50
51impl SKESK6 {
52 pub fn new(sym_algo: SymmetricAlgorithm,
57 aead_algo: AEADAlgorithm,
58 s2k: S2K,
59 aead_iv: Box<[u8]>,
60 esk: Box<[u8]>)
61 -> Result<Self> {
62 Ok(SKESK6 {
63 skesk4: SKESK4 {
64 common: Default::default(),
65 version: 6,
66 sym_algo,
67 s2k,
68 esk: Ok(Some(esk)),
69 },
70 aead_algo,
71 aead_iv,
72 })
73 }
74
75 pub fn with_password(payload_algo: SymmetricAlgorithm,
89 esk_algo: SymmetricAlgorithm,
90 esk_aead: AEADAlgorithm, s2k: S2K,
91 session_key: &SessionKey, password: &Password)
92 -> Result<Self> {
93 if session_key.len() != payload_algo.key_size()? {
94 return Err(Error::InvalidArgument(format!(
95 "Invalid size of session key, got {} want {}",
96 session_key.len(), payload_algo.key_size()?)).into());
97 }
98
99 let ad = [0xc3, 6, esk_algo.into(), esk_aead.into()];
101 let key = s2k.derive_key(password, esk_algo.key_size()?)?;
102
103 let mut kek: SessionKey = vec![0; esk_algo.key_size()?].into();
104 Backend::hkdf_sha256(&key, None, &ad, &mut kek)?;
105
106
107 let mut iv = vec![0u8; esk_aead.nonce_size()?];
109 crypto::random(&mut iv)?;
110 let mut ctx =
111 esk_aead.context(esk_algo, &kek, &ad, &iv)?.for_encryption()?;
112 let mut esk_digest =
113 vec![0u8; session_key.len() + esk_aead.digest_size()?];
114 ctx.encrypt_seal(&mut esk_digest, session_key)?;
115
116 SKESK6::new(esk_algo, esk_aead, s2k, iv.into_boxed_slice(),
118 esk_digest.into())
119 }
120
121 pub fn decrypt(&self, password: &Password)
128 -> Result<SessionKey> {
129 let key = self.s2k().derive_key(password,
130 self.symmetric_algo().key_size()?)?;
131
132 let mut kek: SessionKey =
133 vec![0; self.symmetric_algo().key_size()?].into();
134 let ad = [0xc3,
135 6 ,
136 self.symmetric_algo().into(),
137 self.aead_algo.into()];
138 Backend::hkdf_sha256(&key, None, &ad, &mut kek)?;
139
140 let mut cipher = self.aead_algo.context(
142 self.symmetric_algo(), &kek, &ad, self.aead_iv())?
143 .for_decryption()?;
144
145 let digest_size = self.aead_algo.digest_size()?;
146
147 if self.esk().len() < digest_size {
148 return Err(Error::InvalidArgument(format!(
149 "Encryption session key too small, got {} bytes",
150 self.esk().len())).into());
151 }
152
153 let mut plain: SessionKey =
154 vec![0; self.esk().len() - digest_size].into();
155 cipher.decrypt_verify(&mut plain, self.esk())?;
156 Ok(plain)
157 }
158
159 pub fn symmetric_algo(&self) -> SymmetricAlgorithm {
161 self.skesk4.sym_algo
162 }
163
164 pub fn set_symmetric_algo(&mut self, algo: SymmetricAlgorithm) -> SymmetricAlgorithm {
166 ::std::mem::replace(&mut self.skesk4.sym_algo, algo)
167 }
168
169 pub fn s2k(&self) -> &S2K {
171 &self.skesk4.s2k
172 }
173
174 pub fn set_s2k(&mut self, s2k: S2K) -> S2K {
176 ::std::mem::replace(&mut self.skesk4.s2k, s2k)
177 }
178
179 pub fn aead_algo(&self) -> AEADAlgorithm {
181 self.aead_algo
182 }
183
184 pub fn set_aead_algo(&mut self, algo: AEADAlgorithm) -> AEADAlgorithm {
186 ::std::mem::replace(&mut self.aead_algo, algo)
187 }
188
189 pub fn aead_iv(&self) -> &[u8] {
191 &self.aead_iv
192 }
193
194 pub fn set_aead_iv(&mut self, iv: Box<[u8]>) -> Box<[u8]> {
196 ::std::mem::replace(&mut self.aead_iv, iv)
197 }
198
199 pub fn esk(&self) -> &[u8] {
201 self.skesk4.raw_esk()
202 }
203
204 pub fn set_esk(&mut self, esk: Box<[u8]>) -> Box<[u8]> {
206 ::std::mem::replace(&mut self.skesk4.esk, Ok(Some(esk)))
207 .expect("v6 SKESK can always be parsed")
208 .expect("v6 SKESK packets always have an ESK")
209 }
210}
211
212impl From<SKESK6> for super::SKESK {
213 fn from(p: SKESK6) -> Self {
214 super::SKESK::V6(p)
215 }
216}
217
218impl From<SKESK6> for Packet {
219 fn from(s: SKESK6) -> Self {
220 Packet::SKESK(SKESK::V6(s))
221 }
222}
223
224#[cfg(test)]
225impl Arbitrary for SKESK6 {
226 fn arbitrary(g: &mut Gen) -> Self {
227 let symm = SymmetricAlgorithm::arbitrary(g);
228 let aead = AEADAlgorithm::arbitrary(g);
229 let mut iv = vec![0u8; aead.nonce_size().unwrap_or(16)];
230 for b in iv.iter_mut() {
231 *b = u8::arbitrary(g);
232 }
233 let esk_len =
234 symm.key_size().unwrap_or(16) + aead.digest_size().unwrap_or(16);
235 let mut esk = vec![0u8; esk_len];
236 for b in esk.iter_mut() {
237 *b = u8::arbitrary(g);
238 }
239 SKESK6::new(symm,
240 aead,
241 S2K::arbitrary(g),
242 iv.into(),
243 esk.into())
244 .unwrap()
245 }
246}
247
248#[cfg(test)]
249mod test {
250 use super::*;
251 use crate::PacketPile;
252 use crate::parse::Parse;
253 use crate::serialize::MarshalInto;
254
255 quickcheck! {
256 fn roundtrip_v6(p: SKESK6) -> bool {
257 let p = SKESK::from(p);
258 let q = SKESK::from_bytes(&p.to_vec().unwrap()).unwrap();
259 assert_eq!(p, q);
260 true
261 }
262 }
263
264 #[test]
266 fn v6skesk_aes128_ocb() -> Result<()> {
267 sample_skesk6_packet(
268 SymmetricAlgorithm::AES128,
269 AEADAlgorithm::OCB,
270 "crypto-refresh/v6skesk-aes128-ocb.pgp",
271 b"\xe8\x0d\xe2\x43\xa3\x62\xd9\x3b\
272 \x9d\xc6\x07\xed\xe9\x6a\x73\x56",
273 b"\x28\xe7\x9a\xb8\x23\x97\xd3\xc6\
274 \x3d\xe2\x4a\xc2\x17\xd7\xb7\x91")
275 }
276
277 #[test]
279 fn v6skesk_aes128_eax() -> Result<()> {
280 sample_skesk6_packet(
281 SymmetricAlgorithm::AES128,
282 AEADAlgorithm::EAX,
283 "crypto-refresh/v6skesk-aes128-eax.pgp",
284 b"\x15\x49\x67\xe5\x90\xaa\x1f\x92\
285 \x3e\x1c\x0a\xc6\x4c\x88\xf2\x3d",
286 b"\x38\x81\xba\xfe\x98\x54\x12\x45\
287 \x9b\x86\xc3\x6f\x98\xcb\x9a\x5e")
288 }
289
290 #[test]
292 fn v6skesk_aes128_gcm() -> Result<()> {
293 sample_skesk6_packet(
294 SymmetricAlgorithm::AES128,
295 AEADAlgorithm::GCM,
296 "crypto-refresh/v6skesk-aes128-gcm.pgp",
297 b"\x25\x02\x81\x71\x5b\xba\x78\x28\
298 \xef\x71\xef\x64\xc4\x78\x47\x53",
299 b"\x19\x36\xfc\x85\x68\x98\x02\x74\
300 \xbb\x90\x0d\x83\x19\x36\x0c\x77")
301 }
302
303 fn sample_skesk6_packet(cipher: SymmetricAlgorithm,
304 aead: AEADAlgorithm,
305 name: &str,
306 derived_key: &[u8],
307 session_key: &[u8])
308 -> Result<()> {
309 let password: Password = String::from("password").into();
310 let packets: Vec<Packet> =
311 PacketPile::from_bytes(
312 crate::tests::file(name))?
313 .into_children().collect();
314 assert_eq!(packets.len(), 2);
315 if let Packet::SKESK(SKESK::V6(ref s)) = packets[0] {
316 let derived = s.s2k().derive_key(
317 &password, s.symmetric_algo().key_size()?)?;
318 eprintln!("derived: {:x?}", &derived[..]);
319 assert_eq!(&derived[..], derived_key);
320
321 use crate::crypto::backend::{Backend, interface::Aead};
322 if Backend::supports_algo_with_symmetric(aead, cipher)
323 {
324 let sk = s.decrypt(&password)?;
325 eprintln!("sk: {:x?}", &sk[..]);
326 assert_eq!(&sk[..], session_key);
327 } else {
328 eprintln!("{}-{} is not supported, skipping decryption.",
329 cipher, aead);
330 }
331 } else {
332 panic!("bad packet, expected v6 SKESK: {:?}", packets[0]);
333 }
334
335 Ok(())
336 }
337
338 #[test]
341 fn short_esk() {
342 use crate::packet::SKESK;
343
344 let sym_algo = SymmetricAlgorithm::AES128;
346 let aead_algo = AEADAlgorithm::OCB;
347 if ! aead_algo.is_supported() {
348 eprintln!("{} not supported, skipping test", aead_algo);
349 }
350 let s2k = S2K::Argon2 { salt: [0u8; 16], t: 1, p: 1, m: 8 };
351
352 let iv_len = aead_algo.nonce_size()
353 .expect("algorithm is supported");
354 let digest_len = aead_algo.digest_size()
355 .expect("algorithm is supported");
356 let iv = vec![0u8; iv_len].into_boxed_slice();
357 let esk = vec![0u8; digest_len - 1].into_boxed_slice();
359
360 let skesk6 = SKESK6::new(sym_algo, aead_algo, s2k, iv, esk)
361 .expect("Can create SKESK6");
362 let skesk = SKESK::V6(skesk6);
363
364 skesk.decrypt(&Password::from("pw"))
367 .expect_err("Should fail to decrypt");
368 }
369}