1 //! Symmetric-Key Encrypted Session Key Packets. 2 //! 3 //! SKESK packets hold symmetrically encrypted session keys. The 4 //! session key is needed to decrypt the actual ciphertext. See 5 //! [Section 5.3 of RFC 4880] for details. 6 //! 7 //! [Section 5.3 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.3 8 9 use std::ops::{Deref, DerefMut}; 10 11 #[cfg(any(test, feature = "quickcheck"))] 12 use quickcheck::{Arbitrary, Gen}; 13 14 use crate::Result; 15 use crate::crypto; 16 use crate::crypto::S2K; 17 use crate::Error; 18 use crate::types::{ 19 AEADAlgorithm, 20 SymmetricAlgorithm, 21 }; 22 use crate::packet::{self, SKESK}; 23 use crate::Packet; 24 use crate::crypto::Password; 25 use crate::crypto::SessionKey; 26 27 impl SKESK { 28 /// Derives the key inside this SKESK from `password`. Returns a 29 /// tuple of the symmetric cipher to use with the key and the key 30 /// itself. decrypt(&self, password: &Password) -> Result<(SymmetricAlgorithm, SessionKey)>31 pub fn decrypt(&self, password: &Password) 32 -> Result<(SymmetricAlgorithm, SessionKey)> 33 { 34 match self { 35 &SKESK::V4(ref s) => s.decrypt(password), 36 &SKESK::V5(ref s) => s.decrypt(password), 37 SKESK::__Nonexhaustive => unreachable!(), 38 } 39 } 40 } 41 42 #[cfg(any(test, feature = "quickcheck"))] 43 impl Arbitrary for SKESK { arbitrary<G: Gen>(g: &mut G) -> Self44 fn arbitrary<G: Gen>(g: &mut G) -> Self { 45 if bool::arbitrary(g) { 46 SKESK::V4(SKESK4::arbitrary(g)) 47 } else { 48 SKESK::V5(SKESK5::arbitrary(g)) 49 } 50 } 51 } 52 53 /// Holds an symmetrically encrypted session key version 4. 54 /// 55 /// Holds an symmetrically encrypted session key. The session key is 56 /// needed to decrypt the actual ciphertext. See [Section 5.3 of RFC 57 /// 4880] for details. 58 /// 59 /// [Section 5.3 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.3 60 #[derive(Clone, Debug)] 61 pub struct SKESK4 { 62 /// CTB header fields. 63 pub(crate) common: packet::Common, 64 /// Packet version. Must be 4 or 5. 65 /// 66 /// This struct is also used by SKESK5, hence we have a version 67 /// field. 68 version: u8, 69 /// Symmetric algorithm used to encrypt the session key. 70 sym_algo: SymmetricAlgorithm, 71 /// Key derivation method for the symmetric key. 72 s2k: S2K, 73 /// The encrypted session key. 74 /// 75 /// If we recognized the S2K object during parsing, we can 76 /// successfully parse the data into S2K and ciphertext. However, 77 /// if we do not recognize the S2K type, we do not know how large 78 /// its parameters are, so we cannot cleanly parse it, and have to 79 /// accept that the S2K's body bleeds into the rest of the data. 80 esk: std::result::Result<Option<Box<[u8]>>, // optional ciphertext. 81 Box<[u8]>>, // S2K body + maybe ciphertext. 82 } 83 84 // Because the S2K and ESK cannot be cleanly separated at parse time, 85 // we need to carefully compare and hash SKESK4 packets. 86 87 impl PartialEq for SKESK4 { eq(&self, other: &SKESK4) -> bool88 fn eq(&self, other: &SKESK4) -> bool { 89 self.version == other.version 90 && self.sym_algo == other.sym_algo 91 // Treat S2K and ESK as opaque blob. 92 && { 93 // XXX: This would be nicer without the allocations. 94 use crate::serialize::MarshalInto; 95 let mut a = self.s2k.to_vec().unwrap(); 96 let mut b = other.s2k.to_vec().unwrap(); 97 a.extend_from_slice(self.raw_esk()); 98 b.extend_from_slice(other.raw_esk()); 99 a == b 100 } 101 } 102 } 103 104 impl Eq for SKESK4 {} 105 106 impl std::hash::Hash for SKESK4 { hash<H: std::hash::Hasher>(&self, state: &mut H)107 fn hash<H: std::hash::Hasher>(&self, state: &mut H) { 108 self.version.hash(state); 109 self.sym_algo.hash(state); 110 // Treat S2K and ESK as opaque blob. 111 // XXX: This would be nicer without the allocations. 112 use crate::serialize::MarshalInto; 113 let mut a = self.s2k.to_vec().unwrap(); 114 a.extend_from_slice(self.raw_esk()); 115 a.hash(state); 116 } 117 } 118 119 impl SKESK4 { 120 /// Creates a new SKESK version 4 packet. 121 /// 122 /// The given symmetric algorithm is the one used to encrypt the 123 /// session key. new(esk_algo: SymmetricAlgorithm, s2k: S2K, esk: Option<Box<[u8]>>) -> Result<SKESK4>124 pub fn new(esk_algo: SymmetricAlgorithm, s2k: S2K, 125 esk: Option<Box<[u8]>>) -> Result<SKESK4> { 126 Self::new_raw(esk_algo, s2k, Ok(esk.and_then(|esk| { 127 if esk.len() == 0 { None } else { Some(esk) } 128 }))) 129 } 130 131 /// Creates a new SKESK version 4 packet. 132 /// 133 /// The given symmetric algorithm is the one used to encrypt the 134 /// session key. new_raw(esk_algo: SymmetricAlgorithm, s2k: S2K, esk: std::result::Result<Option<Box<[u8]>>, Box<[u8]>>) -> Result<SKESK4>135 pub(crate) fn new_raw(esk_algo: SymmetricAlgorithm, s2k: S2K, 136 esk: std::result::Result<Option<Box<[u8]>>, 137 Box<[u8]>>) 138 -> Result<SKESK4> { 139 Ok(SKESK4{ 140 common: Default::default(), 141 version: 4, 142 sym_algo: esk_algo, 143 s2k, 144 esk, 145 }) 146 } 147 148 /// Creates a new SKESK4 packet with the given password. 149 /// 150 /// This function takes two [`SymmetricAlgorithm`] arguments: The 151 /// first, `payload_algo`, is the algorithm used to encrypt the 152 /// message's payload (i.e. the one used in the [`SEIP`] or 153 /// [`AED`] packet), and the second, `esk_algo`, is used to 154 /// encrypt the session key. Usually, one should use the same 155 /// algorithm, but if they differ, the `esk_algo` should be at 156 /// least as strong as the `payload_algo` as not to weaken the 157 /// security of the payload encryption. 158 /// 159 /// [`SymmetricAlgorithm`]: ../../types/enum.SymmetricAlgorithm.html 160 /// [`SEIP`]: ../enum.SEIP.html 161 /// [`AED`]: ../enum.AED.html with_password(payload_algo: SymmetricAlgorithm, esk_algo: SymmetricAlgorithm, s2k: S2K, session_key: &SessionKey, password: &Password) -> Result<SKESK4>162 pub fn with_password(payload_algo: SymmetricAlgorithm, 163 esk_algo: SymmetricAlgorithm, 164 s2k: S2K, 165 session_key: &SessionKey, password: &Password) 166 -> Result<SKESK4> { 167 if session_key.len() != payload_algo.key_size()? { 168 return Err(Error::InvalidArgument(format!( 169 "Invalid size of session key, got {} want {}", 170 session_key.len(), payload_algo.key_size()?)).into()); 171 } 172 173 // Derive key and make a cipher. 174 let key = s2k.derive_key(password, esk_algo.key_size()?)?; 175 let mut cipher = esk_algo.make_encrypt_cfb(&key[..])?; 176 let block_size = esk_algo.block_size()?; 177 let mut iv = vec![0u8; block_size]; 178 179 // We need to prefix the cipher specifier to the session key. 180 let mut psk: SessionKey = vec![0; 1 + session_key.len()].into(); 181 psk[0] = payload_algo.into(); 182 psk[1..].copy_from_slice(&session_key); 183 let mut esk = vec![0u8; psk.len()]; 184 185 for (pt, ct) in psk[..].chunks(block_size) 186 .zip(esk.chunks_mut(block_size)) { 187 cipher.encrypt(&mut iv[..], ct, pt)?; 188 } 189 190 SKESK4::new(esk_algo, s2k, Some(esk.into())) 191 } 192 193 /// Gets the symmetric encryption algorithm. symmetric_algo(&self) -> SymmetricAlgorithm194 pub fn symmetric_algo(&self) -> SymmetricAlgorithm { 195 self.sym_algo 196 } 197 198 /// Sets the symmetric encryption algorithm. set_symmetric_algo(&mut self, algo: SymmetricAlgorithm) -> SymmetricAlgorithm199 pub fn set_symmetric_algo(&mut self, algo: SymmetricAlgorithm) -> SymmetricAlgorithm { 200 ::std::mem::replace(&mut self.sym_algo, algo) 201 } 202 203 /// Gets the key derivation method. s2k(&self) -> &S2K204 pub fn s2k(&self) -> &S2K { 205 &self.s2k 206 } 207 208 /// Sets the key derivation method. set_s2k(&mut self, s2k: S2K) -> S2K209 pub fn set_s2k(&mut self, s2k: S2K) -> S2K { 210 ::std::mem::replace(&mut self.s2k, s2k) 211 } 212 213 /// Gets the encrypted session key. 214 /// 215 /// If the [`S2K`] mechanism is not supported by Sequoia, this 216 /// function will fail. Note that the information is not lost, 217 /// but stored in the packet. If the packet is serialized again, 218 /// it is written out. 219 /// 220 /// [`S2K`]: ../../crypto/enum.S2K.html esk(&self) -> Result<Option<&[u8]>>221 pub fn esk(&self) -> Result<Option<&[u8]>> { 222 self.esk.as_ref() 223 .map(|esko| esko.as_ref().map(|esk| &esk[..])) 224 .map_err(|_| Error::MalformedPacket( 225 format!("Unknown S2K: {:?}", self.s2k)).into()) 226 } 227 228 /// Returns the encrypted session key, possibly including the body 229 /// of the S2K object. raw_esk(&self) -> &[u8]230 pub(crate) fn raw_esk(&self) -> &[u8] { 231 match self.esk.as_ref() { 232 Ok(Some(esk)) => &esk[..], 233 Ok(None) => &[][..], 234 Err(s2k_esk) => &s2k_esk[..], 235 } 236 } 237 238 /// Sets the encrypted session key. set_esk(&mut self, esk: Option<Box<[u8]>>) -> Option<Box<[u8]>>239 pub fn set_esk(&mut self, esk: Option<Box<[u8]>>) -> Option<Box<[u8]>> { 240 ::std::mem::replace( 241 &mut self.esk, 242 Ok(esk.and_then(|esk| { 243 if esk.len() == 0 { None } else { Some(esk) } 244 }))) 245 .unwrap_or(None) 246 } 247 248 /// Derives the key inside this SKESK4 from `password`. 249 /// 250 /// Returns a tuple of the symmetric cipher to use with the key 251 /// and the key itself. decrypt(&self, password: &Password) -> Result<(SymmetricAlgorithm, SessionKey)>252 pub fn decrypt(&self, password: &Password) 253 -> Result<(SymmetricAlgorithm, SessionKey)> 254 { 255 let key = self.s2k.derive_key(password, self.sym_algo.key_size()?)?; 256 257 if let Some(ref esk) = self.esk()? { 258 // Use the derived key to decrypt the ESK. Unlike SEP & 259 // SEIP we have to use plain CFB here. 260 let blk_sz = self.sym_algo.block_size()?; 261 let mut iv = vec![0u8; blk_sz]; 262 let mut dec = self.sym_algo.make_decrypt_cfb(&key[..])?; 263 let mut plain: SessionKey = vec![0u8; esk.len()].into(); 264 let cipher = &esk[..]; 265 266 for (pl, ct) 267 in plain[..].chunks_mut(blk_sz).zip(cipher.chunks(blk_sz)) 268 { 269 dec.decrypt(&mut iv[..], pl, ct)?; 270 } 271 272 // Get the algorithm from the front. 273 let sym = SymmetricAlgorithm::from(plain[0]); 274 Ok((sym, plain[1..].into())) 275 } else { 276 // No ESK, we return the derived key. 277 278 #[allow(deprecated)] 279 match self.s2k { 280 S2K::Simple{ .. } => 281 Err(Error::InvalidOperation( 282 "SKESK4: Cannot use Simple S2K without ESK".into()) 283 .into()), 284 _ => Ok((self.sym_algo, key)), 285 } 286 } 287 } 288 } 289 290 impl From<SKESK4> for super::SKESK { from(p: SKESK4) -> Self291 fn from(p: SKESK4) -> Self { 292 super::SKESK::V4(p) 293 } 294 } 295 296 impl From<SKESK4> for Packet { from(s: SKESK4) -> Self297 fn from(s: SKESK4) -> Self { 298 Packet::SKESK(SKESK::V4(s)) 299 } 300 } 301 302 #[cfg(any(test, feature = "quickcheck"))] 303 impl Arbitrary for SKESK4 { arbitrary<G: Gen>(g: &mut G) -> Self304 fn arbitrary<G: Gen>(g: &mut G) -> Self { 305 SKESK4::new(SymmetricAlgorithm::arbitrary(g), 306 S2K::arbitrary(g), 307 Option::<Vec<u8>>::arbitrary(g).map(|v| v.into())) 308 .unwrap() 309 } 310 } 311 312 /// Holds an symmetrically encrypted session key version 5. 313 /// 314 /// Holds an symmetrically encrypted session key. The session key is 315 /// needed to decrypt the actual ciphertext. See [Section 5.3 of RFC 316 /// 4880bis] for details. 317 /// 318 /// [Section 5.3 of RFC 4880]: https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-05#section-5.3 319 /// 320 /// This feature is [experimental](../../index.html#experimental-features). 321 #[derive(Clone, Debug)] 322 pub struct SKESK5 { 323 /// Common fields. 324 pub(crate) skesk4: SKESK4, 325 /// AEAD algorithm. 326 aead_algo: AEADAlgorithm, 327 /// Initialization vector for the AEAD algorithm. 328 /// 329 /// If we recognized the S2K object during parsing, we can 330 /// successfully parse the data into S2K, AEAED IV, and 331 /// ciphertext. However, if we do not recognize the S2K type, we 332 /// do not know how large its parameters are, so we cannot cleanly 333 /// parse it, and have to accept that the S2K's body bleeds into 334 /// the rest of the data. In this case, the raw data is put into 335 /// the `esk` field, and `aead_iv` is set to `None`. 336 aead_iv: Option<Box<[u8]>>, 337 /// Digest for the AEAD algorithm. 338 aead_digest: Box<[u8]>, 339 } 340 341 // Because the S2K, IV, and ESK cannot be cleanly separated at parse 342 // time, we need to carefully compare and hash SKESK5 packets. 343 344 impl PartialEq for SKESK5 { eq(&self, other: &SKESK5) -> bool345 fn eq(&self, other: &SKESK5) -> bool { 346 self.skesk4.version == other.skesk4.version 347 && self.skesk4.sym_algo == other.skesk4.sym_algo 348 && self.aead_digest == other.aead_digest 349 // Treat S2K, IV, and ESK as opaque blob. 350 && { 351 // XXX: This would be nicer without the allocations. 352 use crate::serialize::MarshalInto; 353 let mut a = self.skesk4.s2k.to_vec().unwrap(); 354 let mut b = other.skesk4.s2k.to_vec().unwrap(); 355 if let Ok(iv) = self.aead_iv() { 356 a.extend_from_slice(iv); 357 } 358 if let Ok(iv) = other.aead_iv() { 359 b.extend_from_slice(iv); 360 } 361 a.extend_from_slice(self.skesk4.raw_esk()); 362 b.extend_from_slice(other.skesk4.raw_esk()); 363 a == b 364 } 365 } 366 } 367 368 impl Eq for SKESK5 {} 369 370 impl std::hash::Hash for SKESK5 { hash<H: std::hash::Hasher>(&self, state: &mut H)371 fn hash<H: std::hash::Hasher>(&self, state: &mut H) { 372 self.skesk4.version.hash(state); 373 self.skesk4.sym_algo.hash(state); 374 self.aead_digest.hash(state); 375 // Treat S2K, IV, and ESK as opaque blob. 376 // XXX: This would be nicer without the allocations. 377 use crate::serialize::MarshalInto; 378 let mut a = self.skesk4.s2k.to_vec().unwrap(); 379 if let Some(iv) = self.aead_iv.as_ref() { 380 a.extend_from_slice(iv); 381 } 382 a.extend_from_slice(self.skesk4.raw_esk()); 383 a.hash(state); 384 } 385 } 386 387 impl Deref for SKESK5 { 388 type Target = SKESK4; 389 deref(&self) -> &Self::Target390 fn deref(&self) -> &Self::Target { 391 &self.skesk4 392 } 393 } 394 395 impl DerefMut for SKESK5 { deref_mut(&mut self) -> &mut Self::Target396 fn deref_mut(&mut self) -> &mut Self::Target { 397 &mut self.skesk4 398 } 399 } 400 401 impl SKESK5 { 402 /// Creates a new SKESK version 5 packet. 403 /// 404 /// The given symmetric algorithm is the one used to encrypt the 405 /// session key. new(esk_algo: SymmetricAlgorithm, esk_aead: AEADAlgorithm, s2k: S2K, iv: Box<[u8]>, esk: Box<[u8]>, digest: Box<[u8]>) -> Result<Self>406 pub fn new(esk_algo: SymmetricAlgorithm, esk_aead: AEADAlgorithm, 407 s2k: S2K, iv: Box<[u8]>, esk: Box<[u8]>, digest: Box<[u8]>) 408 -> Result<Self> { 409 Self::new_raw(esk_algo, esk_aead, s2k, Ok((iv, esk)), digest) 410 } 411 412 /// Creates a new SKESK version 5 packet. 413 /// 414 /// The given symmetric algorithm is the one used to encrypt the 415 /// session key. new_raw(esk_algo: SymmetricAlgorithm, esk_aead: AEADAlgorithm, s2k: S2K, iv_esk: std::result::Result<(Box<[u8]>, Box<[u8]>), Box<[u8]>>, digest: Box<[u8]>) -> Result<Self>416 pub(crate) fn new_raw(esk_algo: SymmetricAlgorithm, esk_aead: AEADAlgorithm, 417 s2k: S2K, 418 iv_esk: std::result::Result<(Box<[u8]>, Box<[u8]>), 419 Box<[u8]>>, 420 digest: Box<[u8]>) 421 -> Result<Self> { 422 let (iv, esk) = match iv_esk { 423 Ok((iv, esk)) => (Some(iv), Ok(Some(esk))), 424 Err(raw) => (None, Err(raw)), 425 }; 426 427 Ok(SKESK5{ 428 skesk4: SKESK4{ 429 common: Default::default(), 430 version: 5, 431 sym_algo: esk_algo, 432 s2k, 433 esk, 434 }, 435 aead_algo: esk_aead, 436 aead_iv: iv, 437 aead_digest: digest, 438 }) 439 } 440 441 /// Creates a new SKESK version 5 packet with the given password. 442 /// 443 /// This function takes two [`SymmetricAlgorithm`] arguments: The 444 /// first, `payload_algo`, is the algorithm used to encrypt the 445 /// message's payload (i.e. the one used in the [`SEIP`] or 446 /// [`AED`] packet), and the second, `esk_algo`, is used to 447 /// encrypt the session key. Usually, one should use the same 448 /// algorithm, but if they differ, the `esk_algo` should be at 449 /// least as strong as the `payload_algo` as not to weaken the 450 /// security of the payload encryption. 451 /// 452 /// [`SymmetricAlgorithm`]: ../../types/enum.SymmetricAlgorithm.html 453 /// [`SEIP`]: ../enum.SEIP.html 454 /// [`AED`]: ../enum.AED.html with_password(payload_algo: SymmetricAlgorithm, esk_algo: SymmetricAlgorithm, esk_aead: AEADAlgorithm, s2k: S2K, session_key: &SessionKey, password: &Password) -> Result<Self>455 pub fn with_password(payload_algo: SymmetricAlgorithm, 456 esk_algo: SymmetricAlgorithm, 457 esk_aead: AEADAlgorithm, s2k: S2K, 458 session_key: &SessionKey, password: &Password) 459 -> Result<Self> { 460 if session_key.len() != payload_algo.key_size()? { 461 return Err(Error::InvalidArgument(format!( 462 "Invalid size of session key, got {} want {}", 463 session_key.len(), payload_algo.key_size()?)).into()); 464 } 465 466 // Derive key and make a cipher. 467 let key = s2k.derive_key(password, esk_algo.key_size()?)?; 468 let mut iv = vec![0u8; esk_aead.iv_size()?]; 469 crypto::random(&mut iv); 470 let mut ctx = esk_aead.context(esk_algo, &key, &iv)?; 471 472 // Prepare associated data. 473 let ad = [0xc3, 5, esk_algo.into(), esk_aead.into()]; 474 ctx.update(&ad); 475 476 // We need to prefix the cipher specifier to the session key. 477 let mut esk = vec![0u8; session_key.len()]; 478 ctx.encrypt(&mut esk, &session_key); 479 480 // Digest. 481 let mut digest = vec![0u8; esk_aead.digest_size()?]; 482 ctx.digest(&mut digest); 483 484 SKESK5::new(esk_algo, esk_aead, s2k, iv.into_boxed_slice(), esk.into(), 485 digest.into_boxed_slice()) 486 } 487 488 /// Derives the key inside this `SKESK5` from `password`. 489 /// 490 /// Returns a tuple containing a placeholder symmetric cipher and 491 /// the key itself. `SKESK5` packets do not contain the symmetric 492 /// cipher algorithm and instead rely on the `AED` packet that 493 /// contains it. 494 // XXX: This function should return Result<SessionKey>, but then 495 // SKESK::decrypt must return an 496 // Result<(Option<SymmetricAlgorithm>, _)> and 497 // DecryptionHelper::decrypt and PacketParser::decrypt must be 498 // adapted as well. decrypt(&self, password: &Password) -> Result<(SymmetricAlgorithm, SessionKey)>499 pub fn decrypt(&self, password: &Password) 500 -> Result<(SymmetricAlgorithm, SessionKey)> { 501 let key = self.s2k().derive_key(password, 502 self.symmetric_algo().key_size()?)?; 503 504 if let Some(ref esk) = self.esk()? { 505 // Use the derived key to decrypt the ESK. 506 let mut cipher = self.aead_algo.context( 507 self.symmetric_algo(), &key, &self.aead_iv()?)?; 508 509 let ad = [0xc3, 5 /* Version. */, self.symmetric_algo().into(), 510 self.aead_algo.into()]; 511 cipher.update(&ad); 512 let mut plain: SessionKey = vec![0; esk.len()].into(); 513 let mut digest = vec![0; self.aead_algo.digest_size()?]; 514 cipher.decrypt(&mut plain, esk); 515 cipher.digest(&mut digest); 516 if &digest[..] == &self.aead_digest[..] { 517 Ok((SymmetricAlgorithm::Unencrypted, plain)) 518 } else { 519 Err(Error::ManipulatedMessage.into()) 520 } 521 } else { 522 Err(Error::MalformedPacket( 523 "No encrypted session key in v5 SKESK packet".into()) 524 .into()) 525 } 526 } 527 528 /// Gets the AEAD algorithm. aead_algo(&self) -> AEADAlgorithm529 pub fn aead_algo(&self) -> AEADAlgorithm { 530 self.aead_algo 531 } 532 533 /// Sets the AEAD algorithm. set_aead_algo(&mut self, algo: AEADAlgorithm) -> AEADAlgorithm534 pub fn set_aead_algo(&mut self, algo: AEADAlgorithm) -> AEADAlgorithm { 535 ::std::mem::replace(&mut self.aead_algo, algo) 536 } 537 538 /// Gets the AEAD initialization vector. 539 /// 540 /// If the [`S2K`] mechanism is not supported by Sequoia, this 541 /// function will fail. Note that the information is not lost, 542 /// but stored in the packet. If the packet is serialized again, 543 /// it is written out. 544 /// 545 /// [`S2K`]: ../../crypto/enum.S2K.html aead_iv(&self) -> Result<&[u8]>546 pub fn aead_iv(&self) -> Result<&[u8]> { 547 self.aead_iv.as_ref() 548 .map(|iv| &iv[..]) 549 .ok_or_else(|| Error::MalformedPacket( 550 format!("Unknown S2K: {:?}", self.s2k)).into()) 551 } 552 553 /// Sets the AEAD initialization vector. set_aead_iv(&mut self, iv: Box<[u8]>) -> Option<Box<[u8]>>554 pub fn set_aead_iv(&mut self, iv: Box<[u8]>) -> Option<Box<[u8]>> { 555 ::std::mem::replace(&mut self.aead_iv, Some(iv)) 556 } 557 558 /// Gets the AEAD digest. aead_digest(&self) -> &[u8]559 pub fn aead_digest(&self) -> &[u8] { 560 &self.aead_digest 561 } 562 563 /// Sets the AEAD digest. set_aead_digest(&mut self, digest: Box<[u8]>) -> Box<[u8]>564 pub fn set_aead_digest(&mut self, digest: Box<[u8]>) -> Box<[u8]> { 565 ::std::mem::replace(&mut self.aead_digest, digest) 566 } 567 } 568 569 impl From<SKESK5> for super::SKESK { from(p: SKESK5) -> Self570 fn from(p: SKESK5) -> Self { 571 super::SKESK::V5(p) 572 } 573 } 574 575 impl From<SKESK5> for Packet { from(s: SKESK5) -> Self576 fn from(s: SKESK5) -> Self { 577 Packet::SKESK(SKESK::V5(s)) 578 } 579 } 580 581 #[cfg(any(test, feature = "quickcheck"))] 582 impl Arbitrary for SKESK5 { arbitrary<G: Gen>(g: &mut G) -> Self583 fn arbitrary<G: Gen>(g: &mut G) -> Self { 584 let algo = AEADAlgorithm::EAX; // The only one we dig. 585 let mut iv = vec![0u8; algo.iv_size().unwrap()]; 586 for b in iv.iter_mut() { 587 *b = u8::arbitrary(g); 588 } 589 let mut digest = vec![0u8; algo.digest_size().unwrap()]; 590 for b in digest.iter_mut() { 591 *b = u8::arbitrary(g); 592 } 593 SKESK5::new(SymmetricAlgorithm::arbitrary(g), 594 algo, 595 S2K::arbitrary(g), 596 iv.into_boxed_slice(), 597 Vec::<u8>::arbitrary(g).into(), 598 digest.into_boxed_slice()) 599 .unwrap() 600 } 601 } 602 603 #[cfg(test)] 604 mod test { 605 use super::*; 606 use crate::PacketPile; 607 use crate::parse::Parse; 608 use crate::serialize::{Marshal, MarshalInto}; 609 610 quickcheck! { 611 fn roundtrip(p: SKESK) -> bool { 612 let q = SKESK::from_bytes(&p.to_vec().unwrap()).unwrap(); 613 assert_eq!(p, q); 614 true 615 } 616 } 617 618 #[test] sample_skesk5_packet()619 fn sample_skesk5_packet() { 620 // This sample packet is from RFC4880bis-05, section A.3. 621 let password: Password = String::from("password").into(); 622 let raw = [ 623 // Packet header: 624 0xc3, 0x3e, 625 626 // Version, algorithms, S2K fields: 627 0x05, 0x07, 0x01, 0x03, 0x08, 0xcd, 0x5a, 0x9f, 628 0x70, 0xfb, 0xe0, 0xbc, 0x65, 0x90, 629 630 // AEAD IV: 631 0xbc, 0x66, 0x9e, 0x34, 0xe5, 0x00, 0xdc, 0xae, 632 0xdc, 0x5b, 0x32, 0xaa, 0x2d, 0xab, 0x02, 0x35, 633 634 // AEAD encrypted CEK: 635 0x9d, 0xee, 0x19, 0xd0, 0x7c, 0x34, 0x46, 0xc4, 636 0x31, 0x2a, 0x34, 0xae, 0x19, 0x67, 0xa2, 0xfb, 637 638 // Authentication tag: 639 0x7e, 0x92, 0x8e, 0xa5, 0xb4, 0xfa, 0x80, 0x12, 640 0xbd, 0x45, 0x6d, 0x17, 0x38, 0xc6, 0x3c, 0x36, 641 ]; 642 let packets: Vec<Packet> = 643 PacketPile::from_bytes(&raw[..]).unwrap().into_children().collect(); 644 assert_eq!(packets.len(), 1); 645 if let Packet::SKESK(SKESK::V5(ref s)) = packets[0] { 646 assert_eq!(&s.s2k().derive_key( 647 &password, s.symmetric_algo().key_size().unwrap()).unwrap()[..], 648 &[0xb2, 0x55, 0x69, 0xb9, 0x54, 0x32, 0x45, 0x66, 649 0x45, 0x27, 0xc4, 0x97, 0x6e, 0x7a, 0x5d, 0x6e][..]); 650 651 assert_eq!(&s.decrypt(&password).unwrap().1[..], 652 &[0x86, 0xf1, 0xef, 0xb8, 0x69, 0x52, 0x32, 0x9f, 653 0x24, 0xac, 0xd3, 0xbf, 0xd0, 0xe5, 0x34, 0x6d][..]); 654 } else { 655 panic!("bad packet"); 656 } 657 658 let mut serialized = Vec::new(); 659 packets[0].serialize(&mut serialized).unwrap(); 660 assert_eq!(&raw[..], &serialized[..]); 661 } 662 } 663