CH-J Toolsserver management over SSH
Menu
Published source

CH-J Tools

Browse directories and files for a specific application release.

Download source ZIP
CH-J / Server Manager 1704 files
0.1.2-beta Added: · Built:
key.rs Added: Date not recorded 5.2 KB · 173 lines
Code Download file
1use super::wire::*;
2use crate::core::error::CoreResult;
3use pgp::{
4 composed::KeyType,
5 crypto::ecc_curve::ECCCurve,
6 ser::Serialize,
7 types::{KeyVersion, SecretParams},
8};
9use zeroize::Zeroizing;
11#[derive(Clone)]
12pub struct Key {
13 pub version: u8,
14 pub created: u32,
15 pub days: u16,
16 pub algorithm: u8,
17 pub public: Vec<u8>,
18 pub material: Vec<u8>,
19 pub secret: Option<Zeroizing<Vec<u8>>>,
20 pub tag: u8,
22impl Key {
23 pub fn parse(packet: &Packet) -> CoreResult<Self> {
24 if ![5, 6, 7, 14].contains(&packet.tag) {
25 return Err(invalid());
26 }
27 let mut r = Reader::new(&packet.body);
28 let version = r.u8()?;
29 if ![2, 3, 5].contains(&version) {
30 return Err(invalid());
31 }
32 let created = r.u32()?;
33 let days = if version <= 3 { r.u16()? } else { 0 };
34 let algorithm = r.u8()?;
35 let start = r.pos;
36 let material = if version == 5 {
37 let len = r.u32()? as usize;
38 r.take(len)?.to_vec()
39 } else {
40 if algorithm != 1 {
41 return Err(invalid());
42 }
43 r.mpi()?;
44 r.mpi()?;
45 packet.body[start..r.pos].to_vec()
46 };
47 Parameters::public(algorithm, created, &material)?;
48 let public = packet.body[..r.pos].to_vec();
49 let secret = if [5, 7].contains(&packet.tag) {
50 {
51 if r.rest().is_empty() {
52 return Err(invalid());
53 }
54 Some(Zeroizing::new(r.rest().to_vec()))
55 }
56 } else {
57 r.done()?;
58 None
59 };
60 Ok(Self {
61 version,
62 created,
63 days,
64 algorithm,
65 public,
66 material,
67 secret,
68 tag: packet.tag,
69 })
70 }
71 pub fn prefix(&self) -> CoreResult<Vec<u8>> {
72 let mut out = vec![if self.version == 5 { 0x9a } else { 0x99 }];
73 if self.version == 5 {
74 out.extend((self.public.len() as u32).to_be_bytes())
75 } else {
76 out.extend(
77 u16::try_from(self.public.len())
78 .map_err(|_| invalid())?
79 .to_be_bytes(),
80 )
81 }
82 out.extend(&self.public);
83 Ok(out)
84 }
85 pub fn fingerprint(&self) -> CoreResult<Vec<u8>> {
86 if self.version == 5 {
87 hash(8, &[&self.prefix()?])
88 } else {
89 let mut r = Reader::new(&self.material);
90 let n = r.mpi()?;
91 let e = r.mpi()?;
92 r.done()?;
93 hash(1, &[n, e])
94 }
95 }
96 pub fn key_id(&self) -> CoreResult<Vec<u8>> {
97 if self.version == 5 {
98 Ok(self.fingerprint()?[..8].to_vec())
99 } else {
100 let n = Reader::new(&self.material).mpi()?;
101 if n.len() < 8 {
102 return Err(invalid());
103 }
104 Ok(n[n.len() - 8..].to_vec())
105 }
106 }
107 pub fn parameters(&self) -> CoreResult<Parameters> {
108 Parameters::public(self.algorithm, self.created, &self.material)
109 }
111pub struct Generated {
112 pub key: Key,
113 pub parameters: Parameters,
114 pub plain: Zeroizing<Vec<u8>>,
116pub fn generate(version: u8, created: u32, days: u16, algorithm: &str) -> CoreResult<Generated> {
117 crate::core::openpgp_algorithms::validate(
118 version,
119 algorithm,
120 if algorithm == "curve25519" { "E" } else { "S" },
121 )?;
122 let typ = match algorithm {
123 "rsa1024" if version <= 3 => KeyType::Rsa(1024),
124 "rsa2048" if version <= 3 => KeyType::Rsa(2048),
125 "rsa3072" if version == 5 => KeyType::Rsa(3072),
126 "rsa4096" if version == 5 => KeyType::Rsa(4096),
127 "ed25519" if version == 5 => KeyType::Ed25519Legacy,
128 "curve25519" if version == 5 => KeyType::ECDH(ECCCurve::Curve25519Legacy),
129 _ if crate::core::openpgp_algorithms::is_dsa(algorithm) => {
130 pgp::composed::KeyType::Dsa(pgp::composed::DsaKeySize::B2048)
131 }
132 _ => return Err(invalid()),
133 };
134 let (public, secret) = if crate::core::openpgp_algorithms::is_dsa(algorithm) {
135 crate::core::openpgp_algorithms::generate_dsa(version, algorithm)?
136 } else {
137 crypto(typ.generate(&mut rand::thread_rng()))?
138 };
139 let material = crypto(public.to_bytes())?;
140 let alg: u8 = typ.to_alg().into();
141 let mut body = vec![version];
142 body.extend(created.to_be_bytes());
143 if version <= 3 {
144 body.extend(days.to_be_bytes())
145 }
146 body.push(alg);
147 if version == 5 {
148 body.extend((material.len() as u32).to_be_bytes())
149 }
150 body.extend(&material);
151 let mut plain = Zeroizing::new(Vec::new());
152 let SecretParams::Plain(ref private) = secret else {
153 return Err(invalid());
154 };
155 // V6 here selects parameter bytes without a checksum, not a serialized key format.
156 crypto(private.to_writer(&mut *plain, KeyVersion::V6))?;
157 let parameters = Parameters::public(alg, created, &material)?.with_secret(alg, &plain)?;
158 let key = Key {
159 version,
160 created,
161 days,
162 algorithm: alg,
163 public: body,
164 material,
165 secret: None,
166 tag: 6,
167 };
168 Ok(Generated {
169 key,
170 parameters,
171 plain,
172 })
SHA-256595d5454d691dcdc12e5d648c1c0cc9eb35bc378c30612bfd7749287258eede2

CH-J Proprietary Software License 1.14 · Source is provided under the CH-J Proprietary Software License 1.14. Its availability does not change the license terms or grant additional rights.

Archive SHA-256ac8fe790f4ba60fc098f8c985fc2656cfcc6cdc21fb34b30e308a2b54e62258f
Files