pgp/packet/
secret_key_parser.rs1use std::io::BufRead;
2
3use chrono::{DateTime, TimeZone, Utc};
4use log::debug;
5
6use crate::{
7 crypto::public_key::PublicKeyAlgorithm,
8 errors::{ensure, format_err, unsupported_err, Result},
9 parsing_reader::BufReadParsing,
10 types::{KeyVersion, PublicParams, SecretParams},
11};
12
13fn parse_pub_priv_fields<B: BufRead>(
15 key_ver: KeyVersion,
16 typ: PublicKeyAlgorithm,
17 pub_len: Option<usize>,
18 mut i: B,
19) -> Result<(PublicParams, SecretParams)> {
20 debug!("KeyVersion: {key_ver:?}, alg: {typ:?}, len {pub_len:?}");
21 let pub_params = match pub_len {
22 Some(pub_len) => {
23 let mut public = i.read_take(pub_len);
25 let pp = PublicParams::try_from_reader(typ, Some(pub_len), &mut public)?;
26
27 ensure!(
28 !public.has_remaining()?,
29 "PublicParams::try_from_reader didn't consume all data"
30 );
31 pp
32 }
33 None => PublicParams::try_from_reader(typ, None, &mut i)?,
34 };
35
36 let v = i.rest()?;
37 debug!("rest: {}", hex::encode(&v));
38
39 let secret_params = SecretParams::from_slice(&v, key_ver, typ, &pub_params)?;
40 Ok((pub_params, secret_params))
41}
42
43fn private_key_parser_v4_v6<B: BufRead>(
44 key_ver: &KeyVersion,
45 mut i: B,
46) -> Result<(
47 KeyVersion,
48 PublicKeyAlgorithm,
49 DateTime<Utc>,
50 Option<u16>,
51 PublicParams,
52 SecretParams,
53)> {
54 let created_at = i
55 .read_be_u32()
56 .map(|v| Utc.timestamp_opt(i64::from(v), 0).single())?
57 .ok_or_else(|| format_err!("invalid timestamp"))?;
58
59 let alg = i.read_u8().map(PublicKeyAlgorithm::from)?;
60
61 let pub_len = if *key_ver == KeyVersion::V6 {
62 let pub_len = i.read_be_u32()?;
64
65 Some(pub_len as usize)
66 } else {
67 None
68 };
69
70 let params = parse_pub_priv_fields(*key_ver, alg, pub_len, i)?;
71 Ok((*key_ver, alg, created_at, None, params.0, params.1))
72}
73
74fn private_key_parser_v2_v3<B: BufRead>(
75 key_ver: &KeyVersion,
76 mut i: B,
77) -> Result<(
78 KeyVersion,
79 PublicKeyAlgorithm,
80 DateTime<Utc>,
81 Option<u16>,
82 PublicParams,
83 SecretParams,
84)> {
85 let created_at = i
86 .read_be_u32()
87 .map(|v| Utc.timestamp_opt(i64::from(v), 0).single())?
88 .ok_or_else(|| format_err!("invalid imestamp"))?;
89
90 let exp = i.read_be_u16()?;
91 let alg = i.read_u8().map(PublicKeyAlgorithm::from)?;
92 let params = parse_pub_priv_fields(*key_ver, alg, None, i)?;
93
94 Ok((*key_ver, alg, created_at, Some(exp), params.0, params.1))
95}
96
97#[allow(clippy::type_complexity)]
100pub(crate) fn parse<B: BufRead>(
101 mut i: B,
102) -> Result<(
103 KeyVersion,
104 PublicKeyAlgorithm,
105 DateTime<Utc>,
106 Option<u16>,
107 PublicParams,
108 SecretParams,
109)> {
110 let key_ver = i.read_u8().map(KeyVersion::from)?;
111 let key = match key_ver {
112 KeyVersion::V2 | KeyVersion::V3 => private_key_parser_v2_v3(&key_ver, i)?,
113 KeyVersion::V4 | KeyVersion::V6 => private_key_parser_v4_v6(&key_ver, i)?,
114 KeyVersion::V5 | KeyVersion::Other(_) => {
115 unsupported_err!("key version {:?}", key_ver);
116 }
117 };
118 Ok(key)
119}