1use std::time::Duration;
2
3use byteorder::{BigEndian, ByteOrder, WriteBytesExt};
4use digest::Digest;
5use failure::Error;
6use md5::Md5;
7use nom::{be_u16, be_u8, ErrorKind, IResult};
8use nom::Err as NomErr;
9use num::BigUint;
10use sha1::Sha1;
11
12use s2k::{StringToKey, s2k};
13use types::*;
14use util::{pgp_mpi, pgp_time};
15
16named!(
17 rsa_pubkey<RsaPublicKey>,
18 do_parse!(
19 n: pgp_mpi >>
20 e: pgp_mpi >>
21 (RsaPublicKey { n, e })
22 )
23);
24
25named!(
26 rsa_privkey<RsaPrivateKey>,
27 do_parse!(
28 d: pgp_mpi >>
29 p: pgp_mpi >>
30 q: pgp_mpi >>
31 u: pgp_mpi >>
32 (RsaPrivateKey { d, p, q, u })
33 )
34);
35
36named!(
37 dsa_pubkey<DsaPublicKey>,
38 do_parse!(
39 p: pgp_mpi >>
40 q: pgp_mpi >>
41 g: pgp_mpi >>
42 y: pgp_mpi >>
43 (DsaPublicKey { p, q, g, y })
44 )
45);
46
47named!(dsa_privkey<DsaPrivateKey>, map!(pgp_mpi, DsaPrivateKey));
48
49named!(
50 elgamal_pubkey<ElgamalPublicKey>,
51 do_parse!(
52 p: pgp_mpi >>
53 g: pgp_mpi >>
54 y: pgp_mpi >>
55 (ElgamalPublicKey { p, g, y })
56 )
57);
58
59named!(elgamal_privkey<ElgamalPrivateKey>, map!(pgp_mpi, ElgamalPrivateKey));
60
61named!(
62 v3_pubkey<Key>,
63 do_parse!(
64 alt!(tag!(&[2_u8]) | tag!(&[3_u8])) >>
65 created: pgp_time >>
66 expires_days: be_u16 >>
67 pubkey_algo: be_u8 >>
68 rsa_n: pgp_mpi >>
69 rsa_e: pgp_mpi >>
70 (Key {
71 version: KeyVersion::V3,
72 creation_time: created,
73 expiration_time: Some(Duration::from_secs(expires_days as u64 * 24 * 60 * 60)),
74 pubkey_algorithm: PublicKeyAlgorithm::from(pubkey_algo),
75 key_material: KeyMaterial::Rsa(RsaPublicKey { n: rsa_n, e: rsa_e }, None),
76 encryption_method: None,
77 privkey_checksum: None,
78 })
79 )
80);
81
82named!(
83 v4_pubkey<Key>,
84 do_parse!(
85 tag!(&[4_u8]) >>
86 created: pgp_time >>
87 pubkey_algorithm: peek!(be_u8) >>
88 pubkey_material: switch!(map!(be_u8, PublicKeyAlgorithm::from),
89 PublicKeyAlgorithm::Rsa => map!(call!(rsa_pubkey), |k| KeyMaterial::Rsa(k, None)) |
90 PublicKeyAlgorithm::RsaSignOnly => map!(
91 call!(rsa_pubkey),
92 |k| KeyMaterial::Rsa(k, None)
93 ) |
94 PublicKeyAlgorithm::RsaEncryptOnly => map!(
95 call!(rsa_pubkey),
96 |k| KeyMaterial::Rsa(k, None)
97 ) |
98 PublicKeyAlgorithm::Dsa => map!(call!(dsa_pubkey), |k| KeyMaterial::Dsa(k, None)) |
99 PublicKeyAlgorithm::Elgamal => map!(
100 call!(elgamal_pubkey),
101 |k| KeyMaterial::Elgamal(k, None)
102 ) |
103 PublicKeyAlgorithm::ElgamalEncryptOnly => map!(
104 call!(elgamal_pubkey),
105 |k| KeyMaterial::Elgamal(k, None)
106 )) >>
107 (Key {
108 version: KeyVersion::V4,
109 creation_time: created,
110 expiration_time: None,
111 pubkey_algorithm: PublicKeyAlgorithm::from(pubkey_algorithm),
112 key_material: pubkey_material,
113 encryption_method: None,
114 privkey_checksum: None,
115 })
116 )
117);
118
119named!(pubkey<Key>, alt!(v3_pubkey | v4_pubkey));
120
121named!(privkey_prefix_unencrypted<KeyEncryptionMethod>,
122 do_parse!(
123 tag!(&[0u8]) >>
124 (KeyEncryptionMethod::Unencrypted)
125 )
126);
127
128named!(privkey_prefix_symmetric<KeyEncryptionMethod>,
129 do_parse!(
130 enc_type: map!(be_u8, SymmetricKeyAlgorithm::from) >>
131 iv: take!(enc_type.block_bytes()) >>
132 (KeyEncryptionMethod::SymmetricKey(enc_type, Vec::from(iv)))
133 )
134);
135
136named!(privkey_prefix_s2k<KeyEncryptionMethod>,
137 do_parse!(
138 tag!(&[255u8]) >>
139 enc_type: map!(be_u8, SymmetricKeyAlgorithm::from) >>
140 s2k_specifier: s2k >>
141 iv: take!(enc_type.block_bytes()) >>
142 (KeyEncryptionMethod::StringToKey(enc_type, Vec::from(iv), s2k_specifier))
143 )
144);
145
146named!(privkey_prefix_s2k_sha1<KeyEncryptionMethod>,
147 do_parse!(
148 tag!(&[254u8]) >>
149 enc_type: map!(be_u8, SymmetricKeyAlgorithm::from) >>
150 s2k_specifier: s2k >>
151 iv: take!(enc_type.block_bytes()) >>
152 (KeyEncryptionMethod::StringToKeySha1(enc_type, Vec::from(iv), s2k_specifier))
153 )
154);
155
156named!(privkey_prefix<KeyEncryptionMethod>,
157 alt!(privkey_prefix_unencrypted |
158 privkey_prefix_s2k |
159 privkey_prefix_s2k_sha1 |
160 privkey_prefix_symmetric
161 )
162);
163
164fn parse_key(inp: &[u8]) -> IResult<&[u8], Key> {
165 let (remaining, mut key) = match pubkey(inp) {
166 IResult::Done(remaining, key) => (remaining, key),
167 IResult::Error(e) => return IResult::Error(e),
168 IResult::Incomplete(i) => return IResult::Incomplete(i),
169 };
170
171 let (remaining, privkey_prefix) = match privkey_prefix(remaining) {
172 IResult::Done(remaining, prefix) => (remaining, prefix),
173 IResult::Error(e) => return IResult::Error(e),
174 IResult::Incomplete(_) => return IResult::Done(remaining, key),
175 };
176
177 let (remaining, privkey_material) = match key.key_material {
178 KeyMaterial::Rsa(ref pub_material, _) => match rsa_privkey(remaining) {
179 IResult::Done(remaining, privkey) => (remaining, KeyMaterial::Rsa(pub_material.clone(), Some(privkey))),
180 IResult::Error(e) => return IResult::Error(e),
181 IResult::Incomplete(i) => return IResult::Incomplete(i),
182 },
183 KeyMaterial::Dsa(ref pub_material, _) => match dsa_privkey(remaining) {
184 IResult::Done(remaining, privkey) => (remaining, KeyMaterial::Dsa(pub_material.clone(), Some(privkey))),
185 IResult::Error(e) => return IResult::Error(e),
186 IResult::Incomplete(i) => return IResult::Incomplete(i),
187 },
188 KeyMaterial::Elgamal(ref pub_material, _) => match elgamal_privkey(remaining) {
189 IResult::Done(remaining, privkey) => (remaining, KeyMaterial::Elgamal(pub_material.clone(), Some(privkey))),
190 IResult::Error(e) => return IResult::Error(e),
191 IResult::Incomplete(i) => return IResult::Incomplete(i),
192 }
193 };
194
195 let (remaining, checksum) = match privkey_prefix {
196 KeyEncryptionMethod::Unencrypted
197 | KeyEncryptionMethod::SymmetricKey(_, _)
198 | KeyEncryptionMethod::StringToKey(_, _, _) => match take!(remaining, 2) {
199 IResult::Done(remaining, checksum) => (remaining, checksum),
200 IResult::Error(e) => return IResult::Error(e),
201 IResult::Incomplete(i) => return IResult::Incomplete(i),
202 }
203 KeyEncryptionMethod::StringToKeySha1(_, _, _) => match take!(remaining, 20) {
204 IResult::Done(remaining, checksum) => (remaining, checksum),
205 IResult::Error(e) => return IResult::Error(e),
206 IResult::Incomplete(i) => return IResult::Incomplete(i),
207 }
208 };
209
210 key.key_material = privkey_material;
211 key.encryption_method = Some(privkey_prefix);
212 key.privkey_checksum = Some(Vec::from(checksum));
213
214 IResult::Done(remaining, key)
215}
216
217#[derive(Clone, Debug)]
218pub struct Key {
219 version: KeyVersion,
220 pub creation_time: Duration,
221 expiration_time: Option<Duration>,
222 pub pubkey_algorithm: PublicKeyAlgorithm,
223 pub key_material: KeyMaterial,
224 pub encryption_method: Option<KeyEncryptionMethod>,
225 pub privkey_checksum: Option<Vec<u8>>,
226}
227
228impl Key {
229 pub fn from_bytes(bytes: &[u8]) -> Result<Key, Error> {
230 let (_, key) = match parse_key(bytes) {
231 IResult::Done(remaining, key) => (remaining, key),
232 IResult::Error(NomErr::Code(ErrorKind::Custom(e))) => {
233 let e = NomError::from(e);
234
235 bail!(KeyError::InvalidFormat {
236 reason: format!("{:?}", e),
237 })
238 }
239 IResult::Error(e) => bail!(KeyError::InvalidFormat {
240 reason: format!("{}", e),
241 }),
242 IResult::Incomplete(i) => bail!(KeyError::InvalidFormat {
243 reason: format!("{:?}", i),
244 }),
245 };
246
247 Ok(key)
248 }
249
250 pub fn to_bytes(&self) -> Result<Vec<u8>, Error> {
251 let mut out = Vec::new();
252
253 out.push(4u8);
254 out.write_u32::<BigEndian>(self.creation_time.as_secs() as u32)?;
255 out.push(self.pubkey_algorithm as u8);
256 out.extend(&self.key_material.public_to_bytes()?);
257
258 let private_bytes = self.key_material.private_to_bytes()?;
259 if !private_bytes.is_empty() {
260 match self.encryption_method {
261 None => bail!(KeyError::InvalidEncryption),
262 Some(KeyEncryptionMethod::Unencrypted) => {
263 out.push(0u8);
264 match self.privkey_checksum {
265 None => bail!(KeyError::BadChecksum),
266 Some(ref checksum) => {
267 out.extend(&private_bytes);
268 out.extend(checksum);
269 }
270 }
271 }
272 Some(ref e) => bail!(KeyError::UnimplementedEncryption {
273 method: format!("{:?}", e),
274 })
275 }
276 }
277
278 Ok(out)
279 }
280
281 pub fn expiration_time(&self) -> Option<Duration> {
282 self.expiration_time
283 }
284
285 pub fn fingerprint(&self) -> Result<Vec<u8>, Error> {
286 match self.version {
287 KeyVersion::V3 => {
288 let hash_payload = self.key_material.public_to_bytes()?;
289 Ok(Vec::from(Md5::digest(&hash_payload).as_ref()))
290 }
291 KeyVersion::V4 => {
292 let mut hash_payload = Vec::new();
293 hash_payload.push(0x99);
294
295 let mut key_data = Vec::new();
296 key_data.push(0x4);
297 key_data.write_u32::<BigEndian>(self.creation_time.as_secs() as u32)?;
298 key_data.push(self.pubkey_algorithm as u8);
299 key_data.extend(self.key_material.public_to_bytes()?);
300
301 hash_payload.write_u16::<BigEndian>(key_data.len() as u16)?;
302 hash_payload.extend(&key_data);
303
304 Ok(Vec::from(Sha1::digest(&hash_payload).as_ref()))
305 }
306 }
307 }
308
309 pub fn id(&self) -> Result<u64, Error> {
310 let bytes = match self.version {
311 KeyVersion::V3 => match self.key_material {
312 KeyMaterial::Rsa(ref pubkey, _) => {
313 let n = pubkey.n.to_bytes_be();
314 Ok(Vec::from(&n[n.len() - 8..]))
315 }
316 KeyMaterial::Dsa(_, _) => bail!("v3 DSA keys are unsupported"),
317 KeyMaterial::Elgamal(_, _) => bail!("v3 Elgamal keys are unsupported"),
318 },
319 KeyVersion::V4 => self.fingerprint().map(|mut f| {
320 let len = f.len();
321 f.split_off(len - 8)
322 }),
323 }?;
324
325 Ok(BigEndian::read_u64(&bytes))
326 }
327}
328
329#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
330enum KeyVersion {
331 V3,
332 V4,
333}
334
335#[derive(Clone, Debug)]
336pub enum KeyMaterial {
337 Rsa(RsaPublicKey, Option<RsaPrivateKey>),
338 Dsa(DsaPublicKey, Option<DsaPrivateKey>),
339 Elgamal(ElgamalPublicKey, Option<ElgamalPrivateKey>),
340}
341
342impl KeyMaterial {
343 pub fn public_to_bytes(&self) -> Result<Vec<u8>, Error> {
344 let mut out = Vec::new();
345
346 match self {
347 &KeyMaterial::Rsa(ref public, _) => {
348 out.write_u16::<BigEndian>(public.n.bits() as u16)?;
349 out.extend(&public.n.to_bytes_be());
350 out.write_u16::<BigEndian>(public.e.bits() as u16)?;
351 out.extend(&public.e.to_bytes_be());
352 }
353 &KeyMaterial::Dsa(ref public, _) => {
354 out.write_u16::<BigEndian>(public.p.bits() as u16)?;
355 out.extend(&public.p.to_bytes_be());
356 out.write_u16::<BigEndian>(public.q.bits() as u16)?;
357 out.extend(&public.q.to_bytes_be());
358 out.write_u16::<BigEndian>(public.g.bits() as u16)?;
359 out.extend(&public.g.to_bytes_be());
360 out.write_u16::<BigEndian>(public.y.bits() as u16)?;
361 out.extend(&public.y.to_bytes_be());
362 }
363 &KeyMaterial::Elgamal(ref public, _) => {
364 out.write_u16::<BigEndian>(public.p.bits() as u16)?;
365 out.extend(&public.p.to_bytes_be());
366 out.write_u16::<BigEndian>(public.g.bits() as u16)?;
367 out.extend(&public.g.to_bytes_be());
368 out.write_u16::<BigEndian>(public.y.bits() as u16)?;
369 out.extend(&public.y.to_bytes_be());
370 }
371 }
372
373 Ok(out)
374 }
375
376 pub fn private_to_bytes(&self) -> Result<Vec<u8>, Error> {
377 let mut out = Vec::new();
378
379 match self {
380 &KeyMaterial::Rsa(_, Some(ref private)) => {
381 out.write_u16::<BigEndian>(private.d.bits() as u16)?;
382 out.extend(&private.d.to_bytes_be());
383 out.write_u16::<BigEndian>(private.p.bits() as u16)?;
384 out.extend(&private.p.to_bytes_be());
385 out.write_u16::<BigEndian>(private.q.bits() as u16)?;
386 out.extend(&private.q.to_bytes_be());
387 out.write_u16::<BigEndian>(private.u.bits() as u16)?;
388 out.extend(&private.u.to_bytes_be());
389 }
390 &KeyMaterial::Dsa(_, Some(DsaPrivateKey(ref private))) => {
391 out.write_u16::<BigEndian>(private.bits() as u16)?;
392 out.extend(&private.to_bytes_be());
393 }
394 &KeyMaterial::Elgamal(_, Some(ElgamalPrivateKey(ref private))) => {
395 out.write_u16::<BigEndian>(private.bits() as u16)?;
396 out.extend(&private.to_bytes_be());
397 }
398 &KeyMaterial::Rsa(_, None)
399 | &KeyMaterial::Dsa(_, None)
400 | &KeyMaterial::Elgamal(_, None) => {}
401 }
402
403 Ok(out)
404 }
405}
406
407#[derive(Clone, Debug)]
408pub enum KeyEncryptionMethod {
409 Unencrypted,
410 SymmetricKey(SymmetricKeyAlgorithm, Vec<u8>),
411 StringToKey(SymmetricKeyAlgorithm, Vec<u8>, StringToKey),
412 StringToKeySha1(SymmetricKeyAlgorithm, Vec<u8>, StringToKey)
413}
414
415#[derive(Clone, Debug)]
416pub struct RsaPublicKey {
417 pub n: BigUint,
418 pub e: BigUint,
419}
420
421#[derive(Clone, Debug)]
422pub struct RsaPrivateKey {
423 pub d: BigUint,
424 pub p: BigUint,
425 pub q: BigUint,
426 pub u: BigUint,
427}
428
429#[derive(Clone, Debug)]
430pub struct DsaPublicKey {
431 pub p: BigUint,
432 pub q: BigUint,
433 pub g: BigUint,
434 pub y: BigUint,
435}
436
437#[derive(Clone, Debug)]
438pub struct DsaPrivateKey(pub BigUint);
439
440#[derive(Clone, Debug)]
441pub struct ElgamalPublicKey {
442 pub p: BigUint,
443 pub g: BigUint,
444 pub y: BigUint,
445}
446
447#[derive(Clone, Debug)]
448pub struct ElgamalPrivateKey(pub BigUint);
449
450#[derive(Debug, Fail)]
451pub enum KeyError {
452 #[fail(display = "Invalid key format: {}", reason)]
453 InvalidFormat { reason: String },
454 #[fail(display = "Invalid/no encryption set")]
455 InvalidEncryption,
456 #[fail(display = "Bad checksum")]
457 BadChecksum,
458 #[fail(display = "Unimplemented key encryption method: {}", method)]
459 UnimplementedEncryption { method: String },
460 #[fail(display = "Malformed MPI payload")]
461 MalformedMpi,
462}