Skip to content

Commit a5e3931

Browse files
committed
key: support serializing keys to bytes
1 parent fbbcfde commit a5e3931

File tree

1 file changed

+107
-0
lines changed

1 file changed

+107
-0
lines changed

src/key.rs

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::time::Duration;
22

3+
use byteorder::{BigEndian, WriteBytesExt};
34
use failure::Error;
45
use nom::{be_u16, be_u8, ErrorKind, IResult};
56
use nom::Err as NomErr;
@@ -239,6 +240,41 @@ impl Key {
239240

240241
Ok(key)
241242
}
243+
244+
pub fn to_bytes(&self) -> Result<Vec<u8>, Error> {
245+
let mut out = Vec::new();
246+
247+
out.push(4u8);
248+
out.write_u32::<BigEndian>(self.creation_time.as_secs() as u32)?;
249+
out.push(self.pubkey_algorithm as u8);
250+
out.extend(&self.key_material.public_to_bytes()?);
251+
252+
let private_bytes = self.key_material.private_to_bytes()?;
253+
if !private_bytes.is_empty() {
254+
match self.encryption_method {
255+
None => bail!(KeyError::InvalidEncryption),
256+
Some(KeyEncryptionMethod::Unencrypted) => {
257+
out.push(0u8);
258+
match self.privkey_checksum {
259+
None => bail!(KeyError::BadChecksum),
260+
Some(ref checksum) => {
261+
out.extend(&private_bytes);
262+
out.extend(checksum);
263+
}
264+
}
265+
}
266+
Some(ref e) => bail!(KeyError::UnimplementedEncryption {
267+
method: format!("{:?}", e),
268+
})
269+
}
270+
}
271+
272+
Ok(out)
273+
}
274+
275+
pub fn expiration_time(&self) -> Option<Duration> {
276+
self.expiration_time
277+
}
242278
}
243279

244280
#[derive(Clone, Debug)]
@@ -248,6 +284,71 @@ pub enum KeyMaterial {
248284
Elgamal(ElgamalPublicKey, Option<ElgamalPrivateKey>),
249285
}
250286

287+
impl KeyMaterial {
288+
pub fn public_to_bytes(&self) -> Result<Vec<u8>, Error> {
289+
let mut out = Vec::new();
290+
291+
match self {
292+
&KeyMaterial::Rsa(ref public, _) => {
293+
out.write_u16::<BigEndian>(public.n.bits() as u16)?;
294+
out.extend(&public.n.to_bytes_be());
295+
out.write_u16::<BigEndian>(public.e.bits() as u16)?;
296+
out.extend(&public.e.to_bytes_be());
297+
}
298+
&KeyMaterial::Dsa(ref public, _) => {
299+
out.write_u16::<BigEndian>(public.p.bits() as u16)?;
300+
out.extend(&public.p.to_bytes_be());
301+
out.write_u16::<BigEndian>(public.q.bits() as u16)?;
302+
out.extend(&public.q.to_bytes_be());
303+
out.write_u16::<BigEndian>(public.g.bits() as u16)?;
304+
out.extend(&public.g.to_bytes_be());
305+
out.write_u16::<BigEndian>(public.y.bits() as u16)?;
306+
out.extend(&public.y.to_bytes_be());
307+
}
308+
&KeyMaterial::Elgamal(ref public, _) => {
309+
out.write_u16::<BigEndian>(public.p.bits() as u16)?;
310+
out.extend(&public.p.to_bytes_be());
311+
out.write_u16::<BigEndian>(public.g.bits() as u16)?;
312+
out.extend(&public.g.to_bytes_be());
313+
out.write_u16::<BigEndian>(public.y.bits() as u16)?;
314+
out.extend(&public.y.to_bytes_be());
315+
}
316+
}
317+
318+
Ok(out)
319+
}
320+
321+
pub fn private_to_bytes(&self) -> Result<Vec<u8>, Error> {
322+
let mut out = Vec::new();
323+
324+
match self {
325+
&KeyMaterial::Rsa(_, Some(ref private)) => {
326+
out.write_u16::<BigEndian>(private.d.bits() as u16)?;
327+
out.extend(&private.d.to_bytes_be());
328+
out.write_u16::<BigEndian>(private.p.bits() as u16)?;
329+
out.extend(&private.p.to_bytes_be());
330+
out.write_u16::<BigEndian>(private.q.bits() as u16)?;
331+
out.extend(&private.q.to_bytes_be());
332+
out.write_u16::<BigEndian>(private.u.bits() as u16)?;
333+
out.extend(&private.u.to_bytes_be());
334+
}
335+
&KeyMaterial::Dsa(_, Some(DsaPrivateKey(ref private))) => {
336+
out.write_u16::<BigEndian>(private.bits() as u16)?;
337+
out.extend(&private.to_bytes_be());
338+
}
339+
&KeyMaterial::Elgamal(_, Some(ElgamalPrivateKey(ref private))) => {
340+
out.write_u16::<BigEndian>(private.bits() as u16)?;
341+
out.extend(&private.to_bytes_be());
342+
}
343+
&KeyMaterial::Rsa(_, None)
344+
| &KeyMaterial::Dsa(_, None)
345+
| &KeyMaterial::Elgamal(_, None) => {}
346+
}
347+
348+
Ok(out)
349+
}
350+
}
351+
251352
#[derive(Clone, Debug)]
252353
pub enum KeyEncryptionMethod {
253354
Unencrypted,
@@ -295,6 +396,12 @@ pub struct ElgamalPrivateKey(BigUint);
295396
pub enum KeyError {
296397
#[fail(display = "Invalid key format: {}", reason)]
297398
InvalidFormat { reason: String },
399+
#[fail(display = "Invalid/no encryption set")]
400+
InvalidEncryption,
401+
#[fail(display = "Bad checksum")]
402+
BadChecksum,
403+
#[fail(display = "Unimplemented key encryption method: {}", method)]
404+
UnimplementedEncryption { method: String },
298405
#[fail(display = "Malformed MPI payload")]
299406
MalformedMpi,
300407
}

0 commit comments

Comments
 (0)