Skip to main content

pgp/packet/
secret_key_parser.rs

1use std::io::BufRead;
2
3use log::debug;
4
5use crate::{
6    crypto::public_key::PublicKeyAlgorithm,
7    errors::{ensure, unsupported_err, Result},
8    parsing_reader::BufReadParsing,
9    types::{KeyVersion, PublicParams, SecretParams, Timestamp},
10};
11
12/// Parse the whole private key, both public and private fields.
13fn parse_pub_priv_fields<B: BufRead>(
14    key_ver: KeyVersion,
15    typ: PublicKeyAlgorithm,
16    pub_len: Option<usize>,
17    mut i: B,
18) -> Result<(PublicParams, SecretParams)> {
19    debug!("KeyVersion: {key_ver:?}, alg: {typ:?}, len {pub_len:?}");
20    let pub_params = match pub_len {
21        Some(pub_len) => {
22            // Use the pub_len hint to make sure we consume no more or less
23            let mut public = i.read_take(pub_len);
24            let pp = PublicParams::try_from_reader(typ, Some(pub_len), &mut public)?;
25
26            ensure!(
27                !public.has_remaining()?,
28                "PublicParams::try_from_reader didn't consume all data"
29            );
30            pp
31        }
32        None => PublicParams::try_from_reader(typ, None, &mut i)?,
33    };
34
35    let v = i.rest()?;
36    debug!("rest: {}", hex::encode(&v));
37
38    let secret_params = SecretParams::from_slice(&v, key_ver, typ, &pub_params)?;
39    Ok((pub_params, secret_params))
40}
41
42fn private_key_parser_v4_v6<B: BufRead>(
43    key_ver: &KeyVersion,
44    mut i: B,
45) -> Result<(
46    KeyVersion,
47    PublicKeyAlgorithm,
48    Timestamp,
49    Option<u16>,
50    PublicParams,
51    SecretParams,
52)> {
53    let created_at = i.read_timestamp()?;
54
55    let alg = i.read_u8().map(PublicKeyAlgorithm::from)?;
56
57    let pub_len = if *key_ver == KeyVersion::V6 {
58        // "scalar octet count for the following public key material" -> pass on for checking
59        let pub_len = i.read_be_u32()?;
60
61        Some(pub_len as usize)
62    } else {
63        None
64    };
65
66    let params = parse_pub_priv_fields(*key_ver, alg, pub_len, i)?;
67    Ok((*key_ver, alg, created_at, None, params.0, params.1))
68}
69
70fn private_key_parser_v2_v3<B: BufRead>(
71    key_ver: &KeyVersion,
72    mut i: B,
73) -> Result<(
74    KeyVersion,
75    PublicKeyAlgorithm,
76    Timestamp,
77    Option<u16>,
78    PublicParams,
79    SecretParams,
80)> {
81    let created_at = i.read_timestamp()?;
82    let exp = i.read_be_u16()?;
83    let alg = i.read_u8().map(PublicKeyAlgorithm::from)?;
84    let params = parse_pub_priv_fields(*key_ver, alg, None, i)?;
85
86    Ok((*key_ver, alg, created_at, Some(exp), params.0, params.1))
87}
88
89/// Parse a secret key packet (Tag 5)
90/// Ref: https://www.rfc-editor.org/rfc/rfc9580.html#name-secret-key-packet-formats
91#[allow(clippy::type_complexity)]
92pub(crate) fn parse<B: BufRead>(
93    mut i: B,
94) -> Result<(
95    KeyVersion,
96    PublicKeyAlgorithm,
97    Timestamp,
98    Option<u16>,
99    PublicParams,
100    SecretParams,
101)> {
102    let key_ver = i.read_u8().map(KeyVersion::from)?;
103    let key = match key_ver {
104        KeyVersion::V2 | KeyVersion::V3 => private_key_parser_v2_v3(&key_ver, i)?,
105        KeyVersion::V4 | KeyVersion::V6 => private_key_parser_v4_v6(&key_ver, i)?,
106        KeyVersion::V5 | KeyVersion::Other(_) => {
107            unsupported_err!("key version {:?}", key_ver);
108        }
109    };
110    Ok(key)
111}