signify 0.4.1

Create cryptographic signatures for files and verify them
use std::mem;
use std::io::prelude::*;
use std::io::Cursor;

use errors::*;

use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};

use ring::signature::{self, Ed25519KeyPair};
use untrusted;

pub const KEYNUMLEN : usize = 8;
pub const PUBLICBYTES : usize = 32;
pub const SECRETBYTES : usize = 64;
pub const SIGBYTES : usize = 64;

pub const PKGALG : [u8; 2] = *b"Ed";
pub const KDFALG : [u8; 2] = *b"BK";

pub const COMMENTHDR : &'static str = "untrusted comment: ";
pub const COMMENTHDRLEN : usize = 19;
pub const COMMENTMAXLEN : usize = 1024;

pub struct PublicKey {
    pkgalg: [u8; 2],
    pub keynum: [u8; KEYNUMLEN],
    publkey: [u8; PUBLICBYTES],
}

pub struct PrivateKey {
   pub pkgalg: [u8; 2],
   pub kdfalg: [u8; 2],
   pub kdfrounds: u32,
   pub salt: [u8; 16],
   pub checksum: [u8; 8],
   pub keynum: [u8; KEYNUMLEN],
   pub seckey: [u8; SECRETBYTES],
}

pub struct Signature {
    pkgalg: [u8; 2],
    pub keynum: [u8; KEYNUMLEN],
    sig: [u8; SIGBYTES],
}

impl PublicKey {
    pub fn with_key_and_keynum(key: [u8; PUBLICBYTES], keynum: [u8; KEYNUMLEN]) -> PublicKey {
        PublicKey {
            pkgalg: PKGALG,
            keynum: keynum,
            publkey: key,
        }
    }

    pub fn write<W: Write>(&self, mut w: W) -> Result<()> {
        w.write(&self.pkgalg)?;
        w.write(&self.keynum)?;
        w.write(&self.publkey)?;

        Ok(())
    }

    pub fn from_buf(buf: &[u8]) -> Result<PublicKey> {
        assert!(buf.len() >= mem::size_of::<Self>());

        let mut buf = Cursor::new(buf);

        let mut pkgalg = [0; 2];
        let mut keynum = [0; KEYNUMLEN];
        let mut publkey = [0; PUBLICBYTES];

        buf.read(&mut pkgalg)?;
        buf.read(&mut keynum)?;
        buf.read(&mut publkey)?;

        Ok(PublicKey {
            pkgalg: pkgalg,
            keynum: keynum,
            publkey: publkey,
        })
    }
}

impl PrivateKey {
    pub fn write<W: Write>(&self, mut w: W) -> Result<()> {
        w.write(&self.pkgalg)?;
        w.write(&self.kdfalg)?;
        w.write_u32::<BigEndian>(self.kdfrounds)?;
        w.write(&self.salt)?;
        w.write(&self.checksum)?;
        w.write(&self.keynum)?;
        w.write(&self.seckey)?;

        Ok(())
    }

    pub fn from_buf(buf: &[u8]) -> Result<PrivateKey> {
        assert!(buf.len() >= mem::size_of::<Self>());

        let mut buf = Cursor::new(buf);

        let mut pkgalg = [0; 2];
        let mut kdfalg = [0; 2];
        let kdfrounds;
        let mut salt = [0; 16];
        let mut checksum = [0; 8];
        let mut keynum = [0; KEYNUMLEN];
        let mut seckey = [0; SECRETBYTES];

        buf.read(&mut pkgalg)?;
        buf.read(&mut kdfalg)?;
        kdfrounds = buf.read_u32::<BigEndian>()?;
        buf.read(&mut salt)?;
        buf.read(&mut checksum)?;
        buf.read(&mut keynum)?;
        buf.read(&mut seckey)?;

        Ok(PrivateKey {
            pkgalg: pkgalg,
            kdfalg: kdfalg,
            kdfrounds: kdfrounds,
            salt: salt,
            checksum: checksum,
            keynum: keynum,
            seckey: seckey,
        })
    }

    pub fn sign(&self, msg: &[u8]) -> Result<Signature> {
        let seed = untrusted::Input::from(&self.seckey[0..32]);
        let pubkey = untrusted::Input::from(&self.seckey[32..]);
        let keypair = Ed25519KeyPair::from_seed_and_public_key(seed, pubkey)?;
        let signature = keypair.sign(msg);
        let mut sig = [0; 64];
        sig.copy_from_slice(signature.as_ref());
        Ok(Signature {
            pkgalg: PKGALG,
            keynum: self.keynum,
            sig: sig
        })
    }
}

impl Signature {
    pub fn write<W: Write>(&self, mut w: W) -> Result<()> {
        w.write(&self.pkgalg)?;
        w.write(&self.keynum)?;
        w.write(&self.sig)?;

        Ok(())
    }

    pub fn from_buf(buf: &[u8]) -> Result<Signature> {
        assert!(buf.len() >= mem::size_of::<Self>());

        let mut buf = Cursor::new(buf);

        let mut pkgalg = [0; 2];
        let mut keynum = [0; KEYNUMLEN];
        let mut sig = [0; SIGBYTES];

        buf.read(&mut pkgalg)?;
        buf.read(&mut keynum)?;
        buf.read(&mut sig)?;

        Ok(Signature {
            pkgalg: pkgalg,
            keynum: keynum,
            sig: sig,
        })
    }

    pub fn verify(&self, msg: &[u8], pkey: &PublicKey) -> bool {
        let public_key = untrusted::Input::from(&pkey.publkey);
        let sig = untrusted::Input::from(&self.sig);
        let msg = untrusted::Input::from(msg);

        signature::verify(&signature::ED25519,
                          public_key, msg, sig).is_ok()
    }
}