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 mut plain: SessionKey =
146 vec![0; self.esk().len() - self.aead_algo.digest_size()?].into();
147 cipher.decrypt_verify(&mut plain, self.esk())?;
148 Ok(plain)
149 }
150
151 pub fn symmetric_algo(&self) -> SymmetricAlgorithm {
153 self.skesk4.sym_algo
154 }
155
156 pub fn set_symmetric_algo(&mut self, algo: SymmetricAlgorithm) -> SymmetricAlgorithm {
158 ::std::mem::replace(&mut self.skesk4.sym_algo, algo)
159 }
160
161 pub fn s2k(&self) -> &S2K {
163 &self.skesk4.s2k
164 }
165
166 pub fn set_s2k(&mut self, s2k: S2K) -> S2K {
168 ::std::mem::replace(&mut self.skesk4.s2k, s2k)
169 }
170
171 pub fn aead_algo(&self) -> AEADAlgorithm {
173 self.aead_algo
174 }
175
176 pub fn set_aead_algo(&mut self, algo: AEADAlgorithm) -> AEADAlgorithm {
178 ::std::mem::replace(&mut self.aead_algo, algo)
179 }
180
181 pub fn aead_iv(&self) -> &[u8] {
183 &self.aead_iv
184 }
185
186 pub fn set_aead_iv(&mut self, iv: Box<[u8]>) -> Box<[u8]> {
188 ::std::mem::replace(&mut self.aead_iv, iv)
189 }
190
191 pub fn esk(&self) -> &[u8] {
193 self.skesk4.raw_esk()
194 }
195
196 pub fn set_esk(&mut self, esk: Box<[u8]>) -> Box<[u8]> {
198 ::std::mem::replace(&mut self.skesk4.esk, Ok(Some(esk)))
199 .expect("v6 SKESK can always be parsed")
200 .expect("v6 SKESK packets always have an ESK")
201 }
202}
203
204impl From<SKESK6> for super::SKESK {
205 fn from(p: SKESK6) -> Self {
206 super::SKESK::V6(p)
207 }
208}
209
210impl From<SKESK6> for Packet {
211 fn from(s: SKESK6) -> Self {
212 Packet::SKESK(SKESK::V6(s))
213 }
214}
215
216#[cfg(test)]
217impl Arbitrary for SKESK6 {
218 fn arbitrary(g: &mut Gen) -> Self {
219 let symm = SymmetricAlgorithm::arbitrary(g);
220 let aead = AEADAlgorithm::arbitrary(g);
221 let mut iv = vec![0u8; aead.nonce_size().unwrap_or(16)];
222 for b in iv.iter_mut() {
223 *b = u8::arbitrary(g);
224 }
225 let esk_len =
226 symm.key_size().unwrap_or(16) + aead.digest_size().unwrap_or(16);
227 let mut esk = vec![0u8; esk_len];
228 for b in esk.iter_mut() {
229 *b = u8::arbitrary(g);
230 }
231 SKESK6::new(symm,
232 aead,
233 S2K::arbitrary(g),
234 iv.into(),
235 esk.into())
236 .unwrap()
237 }
238}
239
240#[cfg(test)]
241mod test {
242 use super::*;
243 use crate::PacketPile;
244 use crate::parse::Parse;
245 use crate::serialize::MarshalInto;
246
247 quickcheck! {
248 fn roundtrip_v6(p: SKESK6) -> bool {
249 let p = SKESK::from(p);
250 let q = SKESK::from_bytes(&p.to_vec().unwrap()).unwrap();
251 assert_eq!(p, q);
252 true
253 }
254 }
255
256 #[test]
258 fn v6skesk_aes128_ocb() -> Result<()> {
259 sample_skesk6_packet(
260 SymmetricAlgorithm::AES128,
261 AEADAlgorithm::OCB,
262 "crypto-refresh/v6skesk-aes128-ocb.pgp",
263 b"\xe8\x0d\xe2\x43\xa3\x62\xd9\x3b\
264 \x9d\xc6\x07\xed\xe9\x6a\x73\x56",
265 b"\x28\xe7\x9a\xb8\x23\x97\xd3\xc6\
266 \x3d\xe2\x4a\xc2\x17\xd7\xb7\x91")
267 }
268
269 #[test]
271 fn v6skesk_aes128_eax() -> Result<()> {
272 sample_skesk6_packet(
273 SymmetricAlgorithm::AES128,
274 AEADAlgorithm::EAX,
275 "crypto-refresh/v6skesk-aes128-eax.pgp",
276 b"\x15\x49\x67\xe5\x90\xaa\x1f\x92\
277 \x3e\x1c\x0a\xc6\x4c\x88\xf2\x3d",
278 b"\x38\x81\xba\xfe\x98\x54\x12\x45\
279 \x9b\x86\xc3\x6f\x98\xcb\x9a\x5e")
280 }
281
282 #[test]
284 fn v6skesk_aes128_gcm() -> Result<()> {
285 sample_skesk6_packet(
286 SymmetricAlgorithm::AES128,
287 AEADAlgorithm::GCM,
288 "crypto-refresh/v6skesk-aes128-gcm.pgp",
289 b"\x25\x02\x81\x71\x5b\xba\x78\x28\
290 \xef\x71\xef\x64\xc4\x78\x47\x53",
291 b"\x19\x36\xfc\x85\x68\x98\x02\x74\
292 \xbb\x90\x0d\x83\x19\x36\x0c\x77")
293 }
294
295 fn sample_skesk6_packet(cipher: SymmetricAlgorithm,
296 aead: AEADAlgorithm,
297 name: &str,
298 derived_key: &[u8],
299 session_key: &[u8])
300 -> Result<()> {
301 let password: Password = String::from("password").into();
302 let packets: Vec<Packet> =
303 PacketPile::from_bytes(
304 crate::tests::file(name))?
305 .into_children().collect();
306 assert_eq!(packets.len(), 2);
307 if let Packet::SKESK(SKESK::V6(ref s)) = packets[0] {
308 let derived = s.s2k().derive_key(
309 &password, s.symmetric_algo().key_size()?)?;
310 eprintln!("derived: {:x?}", &derived[..]);
311 assert_eq!(&derived[..], derived_key);
312
313 use crate::crypto::backend::{Backend, interface::Aead};
314 if Backend::supports_algo_with_symmetric(aead, cipher)
315 {
316 let sk = s.decrypt(&password)?;
317 eprintln!("sk: {:x?}", &sk[..]);
318 assert_eq!(&sk[..], session_key);
319 } else {
320 eprintln!("{}-{} is not supported, skipping decryption.",
321 cipher, aead);
322 }
323 } else {
324 panic!("bad packet, expected v6 SKESK: {:?}", packets[0]);
325 }
326
327 Ok(())
328 }
329}