1use std::io;
2
3use byteorder::WriteBytesExt;
4use nom::bytes::streaming::take;
5use nom::combinator::{map, map_res};
6use nom::number::streaming::be_u8;
7use nom::sequence::pair;
8use rand::{CryptoRng, Rng};
9use zeroize::Zeroizing;
10
11use crate::crypto::checksum;
12use crate::crypto::public_key::PublicKeyAlgorithm;
13use crate::crypto::sym::SymmetricKeyAlgorithm;
14use crate::errors::{IResult, Result};
15use crate::packet::PacketTrait;
16use crate::ser::Serialize;
17use crate::types::{
18 mpi, EskType, Fingerprint, KeyId, KeyVersion, PkeskBytes, PkeskVersion, PublicKeyTrait,
19 PublicParams, Tag, Version,
20};
21
22#[derive(Debug, Clone, PartialEq, Eq)]
33pub enum PublicKeyEncryptedSessionKey {
34 V3 {
35 packet_version: Version,
36 id: KeyId,
37 pk_algo: PublicKeyAlgorithm,
38 values: PkeskBytes,
39 },
40
41 V6 {
42 packet_version: Version,
43 fingerprint: Option<Fingerprint>,
44 pk_algo: PublicKeyAlgorithm,
45 values: PkeskBytes,
46 },
47
48 Other {
49 packet_version: Version,
50 version: u8,
51 },
52}
53
54impl PublicKeyEncryptedSessionKey {
55 pub fn from_slice(version: Version, input: &[u8]) -> Result<Self> {
57 let (_, pk) = parse(version)(input)?;
58
59 Ok(pk)
60 }
61
62 fn prepare_session_key_for_encryption(
66 alg: Option<SymmetricKeyAlgorithm>, sk: &[u8],
68 pp: &PublicParams,
69 ) -> Zeroizing<Vec<u8>> {
70 let mut data = Zeroizing::new(Vec::with_capacity(1 + sk.len() + 2)); if let Some(alg) = alg {
74 data.push(u8::from(alg));
75 }
76
77 data.extend_from_slice(sk);
79
80 match pp {
82 PublicParams::X25519 { .. } | PublicParams::X448 { .. } => {}
83 _ => data.extend_from_slice(&checksum::calculate_simple(sk).to_be_bytes()),
84 }
85
86 data
87 }
88
89 pub fn from_session_key_v3<R: CryptoRng + Rng>(
91 rng: R,
92 session_key: &[u8],
93 alg: SymmetricKeyAlgorithm,
94 pkey: &impl PublicKeyTrait,
95 ) -> Result<Self> {
96 let data =
98 Self::prepare_session_key_for_encryption(Some(alg), session_key, pkey.public_params());
99
100 let values = pkey.encrypt(rng, &data, EskType::V3_4)?;
101
102 Ok(PublicKeyEncryptedSessionKey::V3 {
103 packet_version: Default::default(),
104 id: pkey.key_id(),
105 pk_algo: pkey.algorithm(),
106 values,
107 })
108 }
109
110 pub fn from_session_key_v6<R: CryptoRng + Rng>(
112 rng: R,
113 session_key: &[u8],
114 pkey: &impl PublicKeyTrait,
115 ) -> Result<Self> {
116 if pkey.algorithm() == PublicKeyAlgorithm::Elgamal {
119 bail!("ElGamal is not a legal encryption mechanism for v6 PKESK");
120 }
121
122 let data =
124 Self::prepare_session_key_for_encryption(None, session_key, pkey.public_params());
125
126 let values = pkey.encrypt(rng, &data, EskType::V6)?;
127
128 Ok(PublicKeyEncryptedSessionKey::V6 {
129 packet_version: Default::default(),
130 fingerprint: Some(pkey.fingerprint()),
131 pk_algo: pkey.algorithm(),
132 values,
133 })
134 }
135
136 pub fn match_identity(&self, pkey: &impl PublicKeyTrait) -> bool {
140 match self {
141 Self::V3 { id, .. } => id.is_wildcard() || (id == &pkey.key_id()),
142 Self::V6 { fingerprint, .. } => {
143 if let Some(fingerprint) = fingerprint {
144 fingerprint == &pkey.fingerprint()
145 } else {
146 true }
148 }
149 _ => false,
150 }
151 }
152
153 pub fn id(&self) -> Result<&KeyId> {
159 match self {
160 Self::V3 { id, .. } => Ok(id),
161 _ => bail!("KeyID is only available for V3 PKESK"),
162 }
163 }
164
165 pub fn fingerprint(&self) -> Result<Option<&Fingerprint>> {
171 match self {
172 Self::V6 { fingerprint, .. } => Ok(fingerprint.as_ref()),
173 _ => bail!("Fingerprint is only available for V6 PKESK"),
174 }
175 }
176
177 pub fn values(&self) -> Result<&PkeskBytes> {
183 match self {
184 Self::V3 { values, .. } | Self::V6 { values, .. } => Ok(values),
185 Self::Other { version, .. } => bail!("Unsupported PKESK version {}", version),
186 }
187 }
188
189 pub fn algorithm(&self) -> Result<PublicKeyAlgorithm> {
193 match self {
194 Self::V3 { pk_algo, .. } | Self::V6 { pk_algo, .. } => Ok(*pk_algo),
195 _ => bail!("PublicKeyAlgorithm unknown for {:?}", self),
196 }
197 }
198
199 pub fn version(&self) -> PkeskVersion {
201 match self {
202 Self::V3 { .. } => PkeskVersion::V3,
203 Self::V6 { .. } => PkeskVersion::V6,
204 Self::Other { version, .. } => PkeskVersion::Other(*version),
205 }
206 }
207}
208
209fn parse_esk<'i>(
210 alg: &PublicKeyAlgorithm,
211 i: &'i [u8],
212 version: u8,
213) -> IResult<&'i [u8], PkeskBytes> {
214 match alg {
215 PublicKeyAlgorithm::RSA | PublicKeyAlgorithm::RSASign | PublicKeyAlgorithm::RSAEncrypt => {
216 map(mpi, |v| PkeskBytes::Rsa { mpi: v.to_owned() })(i)
217 }
218 PublicKeyAlgorithm::Elgamal | PublicKeyAlgorithm::ElgamalSign => {
219 map(pair(mpi, mpi), |(first, second)| PkeskBytes::Elgamal {
220 first: first.to_owned(),
221 second: second.to_owned(),
222 })(i)
223 }
224 PublicKeyAlgorithm::ECDSA | PublicKeyAlgorithm::DSA | PublicKeyAlgorithm::DiffieHellman => {
225 Ok((i, PkeskBytes::Other))
226 }
227 PublicKeyAlgorithm::ECDH => {
228 let (i, a) = mpi(i)?;
229 let (i, blen) = be_u8(i)?;
230 let (i, b) = take(blen)(i)?;
231
232 Ok((
233 i,
234 PkeskBytes::Ecdh {
235 public_point: a.to_owned(),
236 encrypted_session_key: b.into(),
237 },
238 ))
239 }
240 PublicKeyAlgorithm::X25519 => {
241 let (i, ephemeral_public) = nom::bytes::complete::take(32u8)(i)?;
243
244 let (i, len) = be_u8(i)?;
246 if len == 0 {
247 return Err(nom::Err::Error(crate::errors::Error::InvalidInput));
248 }
249
250 let (i, sym_alg) = if version == 3 {
252 map(be_u8, SymmetricKeyAlgorithm::from)(i).map(|(i, alg)| (i, Some(alg)))?
253 } else {
254 (i, None)
255 };
256
257 let skey_len = if version == 3 { len - 1 } else { len };
258
259 let (i, esk) = nom::bytes::complete::take(skey_len)(i)?;
261
262 Ok((
263 i,
264 PkeskBytes::X25519 {
265 ephemeral: ephemeral_public.try_into().expect("32"),
266 sym_alg,
267 session_key: esk.to_vec(),
268 },
269 ))
270 }
271 PublicKeyAlgorithm::X448 => {
272 let (i, ephemeral_public) = nom::bytes::complete::take(56u8)(i)?;
274
275 let (i, len) = be_u8(i)?;
277 if len == 0 {
278 return Err(nom::Err::Error(crate::errors::Error::InvalidInput));
279 }
280
281 let (i, sym_alg) = if version == 3 {
283 map(be_u8, SymmetricKeyAlgorithm::from)(i).map(|(i, alg)| (i, Some(alg)))?
284 } else {
285 (i, None)
286 };
287
288 let skey_len = if version == 3 { len - 1 } else { len };
289
290 let (i, esk) = nom::bytes::complete::take(skey_len)(i)?;
292
293 Ok((
294 i,
295 PkeskBytes::X448 {
296 ephemeral: ephemeral_public.try_into().expect("56"),
297 sym_alg,
298 session_key: esk.to_vec(),
299 },
300 ))
301 }
302 PublicKeyAlgorithm::Unknown(_) => Ok((i, PkeskBytes::Other)), _ => Err(nom::Err::Error(crate::errors::Error::ParsingError(
304 nom::error::ErrorKind::Switch,
305 ))),
306 }
307}
308
309fn parse(
311 packet_version: Version,
312) -> impl Fn(&[u8]) -> IResult<&[u8], PublicKeyEncryptedSessionKey> {
313 move |i: &[u8]| {
314 let (i, version) = be_u8(i)?;
316
317 if version == 3 {
318 let (i, id) = map_res(take(8u8), KeyId::from_slice)(i)?;
320 let (i, pk_algo) = map(be_u8, PublicKeyAlgorithm::from)(i)?;
322
323 let (i, values) = parse_esk(&pk_algo, i, version)?;
325
326 Ok((
327 i,
328 PublicKeyEncryptedSessionKey::V3 {
329 packet_version,
330 id,
331 pk_algo,
332 values,
333 },
334 ))
335 } else if version == 6 {
336 let (i, len) = be_u8(i)?;
340
341 let (i, fingerprint) = match len {
342 0 => (i, None),
343 _ => {
344 let (i, v) = map(be_u8, KeyVersion::from)(i)?;
346
347 let (i, fp) = nom::bytes::complete::take(len - 1)(i)?;
351
352 let fp = Fingerprint::new(v, fp)?;
353
354 (i, Some(fp))
355 }
356 };
357
358 let (i, pk_algo) = map(be_u8, PublicKeyAlgorithm::from)(i)?;
360
361 let (i, values) = parse_esk(&pk_algo, i, version)?;
363
364 Ok((
365 i,
366 PublicKeyEncryptedSessionKey::V6 {
367 packet_version,
368 fingerprint,
369 pk_algo,
370 values,
371 },
372 ))
373 } else {
374 Ok((
375 i,
376 PublicKeyEncryptedSessionKey::Other {
377 packet_version,
378 version,
379 },
380 ))
381 }
382 }
383}
384
385impl Serialize for PublicKeyEncryptedSessionKey {
386 fn to_writer<W: io::Write>(&self, writer: &mut W) -> Result<()> {
387 writer.write_u8(self.version().into())?;
388
389 match self {
390 PublicKeyEncryptedSessionKey::V3 { id, .. } => writer.write_all(id.as_ref())?,
391 PublicKeyEncryptedSessionKey::V6 { fingerprint, .. } => {
392 match fingerprint {
396 Some(fingerprint) => {
397 let len = fingerprint.len() + 1;
398 writer.write_u8(len.try_into()?)?;
399
400 match fingerprint.version() {
402 Some(version) => writer.write_u8(version.into())?,
403 None => {
404 bail!("Fingerprint without version information {:?}", fingerprint)
405 }
406 }
407
408 writer.write_all(fingerprint.as_bytes())?;
412 }
413 _ => writer.write_u8(0)?,
414 }
415 }
416 PublicKeyEncryptedSessionKey::Other { .. } => todo!(),
417 }
418
419 let algorithm = self.algorithm()?;
420 writer.write_u8(algorithm.into())?;
421
422 match (algorithm, self.values()?) {
423 (
424 PublicKeyAlgorithm::RSA
425 | PublicKeyAlgorithm::RSASign
426 | PublicKeyAlgorithm::RSAEncrypt,
427 PkeskBytes::Rsa { mpi },
428 ) => {
429 mpi.to_writer(writer)?;
430 }
431 (
432 PublicKeyAlgorithm::Elgamal | PublicKeyAlgorithm::ElgamalSign,
433 PkeskBytes::Elgamal { first, second },
434 ) => {
435 first.to_writer(writer)?;
436 second.to_writer(writer)?;
437 }
438 (
439 PublicKeyAlgorithm::ECDH,
440 PkeskBytes::Ecdh {
441 public_point,
442 encrypted_session_key,
443 },
444 ) => {
445 public_point.to_writer(writer)?;
446
447 writer.write_u8(encrypted_session_key.len().try_into()?)?;
449
450 writer.write_all(encrypted_session_key)?;
451 }
452 (
453 PublicKeyAlgorithm::X25519,
454 PkeskBytes::X25519 {
455 ephemeral,
456 sym_alg,
457 session_key,
458 },
459 ) => {
460 writer.write_all(ephemeral)?;
461
462 if let Some(sym_alg) = sym_alg {
467 ensure!(
468 matches!(self, PublicKeyEncryptedSessionKey::V3 { .. }),
469 "Inconsistent: X25519 SymmetricKeyAlgorithm is set for {:?} PKESK",
470 self.version()
471 );
472
473 writer.write_u8((session_key.len() + 1).try_into()?)?;
475
476 writer.write_u8((*sym_alg).into())?;
477 } else {
478 ensure!(
479 matches!(self, PublicKeyEncryptedSessionKey::V6 { .. }),
480 "Inconsistent: X25519 SymmetricKeyAlgorithm is unset for {:?} PKESK",
481 self.version()
482 );
483
484 writer.write_u8(session_key.len().try_into()?)?;
486
487 }
489
490 writer.write_all(session_key)?; }
492 (
493 PublicKeyAlgorithm::X448,
494 PkeskBytes::X448 {
495 ephemeral,
496 sym_alg,
497 session_key,
498 },
499 ) => {
500 writer.write_all(ephemeral)?;
501
502 if let Some(sym_alg) = sym_alg {
507 ensure!(
508 matches!(self, PublicKeyEncryptedSessionKey::V3 { .. }),
509 "Inconsistent: X448 SymmetricKeyAlgorithm is set for {:?} PKESK",
510 self.version()
511 );
512
513 writer.write_u8((session_key.len() + 1).try_into()?)?;
515
516 writer.write_u8((*sym_alg).into())?;
517 } else {
518 ensure!(
519 matches!(self, PublicKeyEncryptedSessionKey::V6 { .. }),
520 "Inconsistent: X448 SymmetricKeyAlgorithm is unset for {:?} PKESK",
521 self.version()
522 );
523
524 writer.write_u8(session_key.len().try_into()?)?;
526
527 }
529
530 writer.write_all(session_key)?; }
532 (alg, _) => {
533 bail!("failed to write EskBytes for {:?}", alg);
534 }
535 }
536
537 Ok(())
538 }
539}
540
541impl PacketTrait for PublicKeyEncryptedSessionKey {
542 fn packet_version(&self) -> Version {
543 match self {
544 Self::V3 { packet_version, .. }
545 | Self::V6 { packet_version, .. }
546 | Self::Other { packet_version, .. } => *packet_version,
547 }
548 }
549 fn tag(&self) -> Tag {
550 Tag::PublicKeyEncryptedSessionKey
551 }
552}