rsign 0.1.2

A command-line tool to sign files and verify signatures.
Documentation
extern crate libsodium_sys as ffi;

use sodiumoxide::crypto::sign::*;
use sodiumoxide::crypto::pwhash::*;
use generichash::{self, BYTES};
use std::fmt::{self, Formatter};
use ::Result;
use std::cmp;
use std::io::{Cursor, Read};

pub const KEYNUMBYTES: usize = 8;
pub const TWOBYTES: usize = 2;
pub const TR_COMMENT_PREFIX_LEN: usize = 17;
pub const PK_B64_ENCODED_LEN: usize = 56;
pub const PASSWORDMAXBYTES: usize = 1024;
pub const COMMENTBYTES: usize = 1024;
pub const TRUSTEDCOMMENTMAXBYTES: usize = 8192;
pub const SIGALG: [u8; 2] = *b"Ed";
pub const SIGALG_HASHED: [u8; 2] = *b"ED";
pub const KDFALG: [u8; 2] = *b"Sc";
pub const CHKALG: [u8; 2] = *b"B2";
pub const COMMENT_PREFIX: &'static str = "untrusted comment: ";
pub const DEFAULT_COMMENT: &'static str = "signature from rsign secret key";
pub const SECRETKEY_DEFAULT_COMMENT: &'static str = "rsign encrypted secret key";
pub const TRUSTED_COMMENT_PREFIX: &'static str = "trusted comment: ";
pub const SIG_DEFAULT_CONFIG_DIR: &'static str = ".rsign";
pub const SIG_DEFAULT_CONFIG_DIR_ENV_VAR: &'static str = "RSIGN_CONFIG_DIR";
pub const SIG_DEFAULT_PKFILE: &'static str = "rsign.pub";
pub const SIG_DEFAULT_SKFILE: &'static str = "rsign.key";
pub const SIG_SUFFIX: &'static str = ".rsign";

pub struct KeynumSK {
    pub keynum: [u8; KEYNUMBYTES],
    pub sk: [u8; SECRETKEYBYTES],
    pub chk: [u8; BYTES],
}

impl Clone for KeynumSK {
    fn clone(&self) -> KeynumSK {
        KeynumSK {
            keynum: self.keynum,
            sk: self.sk,
            chk: self.chk,
        }
    }
}

impl KeynumSK {
    pub fn len(&self) -> usize {
        use std::mem;
        mem::size_of::<KeynumSK>()
    }
}

impl fmt::Debug for KeynumSK {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        for byte in self.sk.iter() {
            try!(write!(f, "{:x}", byte))
        }
        Ok(())
    }
}

impl cmp::PartialEq for KeynumSK {
    fn eq(&self, other: &KeynumSK) -> bool {
        use sodiumoxide::utils::memcmp;
        memcmp(&self.sk, &other.sk)
    }
}
impl cmp::Eq for KeynumSK {}

pub struct SeckeyStruct {
    pub sig_alg: [u8; TWOBYTES],
    pub kdf_alg: [u8; TWOBYTES],
    pub chk_alg: [u8; TWOBYTES],
    pub kdf_salt: [u8; SALTBYTES],
    pub kdf_opslimit_le: [u8; KEYNUMBYTES],
    pub kdf_memlimit_le: [u8; KEYNUMBYTES],
    pub keynum_sk: KeynumSK,
}

impl SeckeyStruct {
    pub fn from(bytes_buf: &[u8]) -> Result<SeckeyStruct> {
        let mut buf = Cursor::new(bytes_buf);
        let mut sig_alg = [0u8; TWOBYTES];
        let mut kdf_alg = [0u8; TWOBYTES];
        let mut chk_alg = [0u8; TWOBYTES];
        let mut kdf_salt = [0u8; SALTBYTES];
        let mut ops_limit = [0u8; KEYNUMBYTES];
        let mut mem_limit = [0u8; KEYNUMBYTES];
        let mut keynum = [0u8; KEYNUMBYTES];
        let mut sk = [0u8; SECRETKEYBYTES];
        let mut chk = [0u8; BYTES];
        buf.read(&mut sig_alg)?;
        buf.read(&mut kdf_alg)?;
        buf.read(&mut chk_alg)?;
        buf.read(&mut kdf_salt)?;
        buf.read(&mut ops_limit)?;
        buf.read(&mut mem_limit)?;
        buf.read(&mut keynum)?;
        buf.read(&mut sk)?;
        buf.read(&mut chk)?;

        Ok(SeckeyStruct {
               sig_alg: sig_alg,
               kdf_alg: kdf_alg,
               chk_alg: chk_alg,
               kdf_salt: kdf_salt,
               kdf_opslimit_le: ops_limit,
               kdf_memlimit_le: mem_limit,
               keynum_sk: KeynumSK {
                   keynum: keynum,
                   sk: sk,
                   chk: chk,
               },
           })
    }
    pub fn bytes(&self) -> Vec<u8> {
        let mut iters = Vec::new();
        iters.push(self.sig_alg.iter());
        iters.push(self.kdf_alg.iter());
        iters.push(self.chk_alg.iter());
        iters.push(self.kdf_salt.iter());
        iters.push(self.kdf_opslimit_le.iter());
        iters.push(self.kdf_memlimit_le.iter());
        iters.push(self.keynum_sk.keynum.iter());
        iters.push(self.keynum_sk.sk.iter());
        iters.push(self.keynum_sk.chk.iter());
        let v: Vec<u8> = iters
            .iter()
            .flat_map(|b| {
                          let b = b.clone();
                          b.into_iter().cloned()
                      })
            .collect();
        v
    }
    pub fn write_checksum(&mut self) -> Result<()> {
        let h = self.read_checksum()?;
        self.keynum_sk.chk.copy_from_slice(&h[..]);
        Ok(())
    }

    pub fn read_checksum(&self) -> Result<Vec<u8>> {
        let state_sz = unsafe { ffi::crypto_generichash_statebytes() };
        let mut state: Vec<u8> = vec![0;state_sz];
        let ptr_state = state.as_mut_ptr() as *mut ffi::crypto_generichash_state;
        generichash::init(ptr_state)?;
        generichash::update(ptr_state, &self.sig_alg)?;
        generichash::update(ptr_state, &self.keynum_sk.keynum)?;
        generichash::update(ptr_state, &self.keynum_sk.sk)?;
        let h = generichash::finalize(ptr_state)?;
        Ok(Vec::from(&h[..]))
    }

    pub fn xor_keynum(&mut self, stream: &[u8]) {

        let b8 = self.keynum_sk
            .keynum
            .iter_mut()
            .zip(stream.iter())
            .map(|(byte, stream)| *byte = *byte ^ *stream)
            .count();

        let b64 = self.keynum_sk
            .sk
            .iter_mut()
            .zip(stream[b8..].iter())
            .map(|(byte, stream)| *byte = *byte ^ *stream)
            .count();

        let _b32 = self.keynum_sk
            .chk
            .iter_mut()
            .zip(stream[b8 + b64..].iter())
            .map(|(byte, stream)| *byte = *byte ^ *stream)
            .count();
    }
}

impl fmt::Debug for SeckeyStruct {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        for byte in self.keynum_sk.sk.iter() {
            try!(write!(f, "{:x}", byte))
        }
        Ok(())
    }
}

impl cmp::PartialEq for SeckeyStruct {
    fn eq(&self, other: &SeckeyStruct) -> bool {
        use sodiumoxide::utils::memcmp;
        memcmp(&self.keynum_sk.sk, &other.keynum_sk.sk)
    }
}
impl cmp::Eq for SeckeyStruct {}

#[derive(Debug)]
pub struct PubkeyStruct {
    pub sig_alg: [u8; TWOBYTES],
    pub keynum_pk: KeynumPK,
}
#[derive(Debug, Clone)]
pub struct KeynumPK {
    pub keynum: [u8; KEYNUMBYTES],
    pub pk: [u8; PUBLICKEYBYTES],
}

impl cmp::PartialEq for PubkeyStruct {
    fn eq(&self, other: &PubkeyStruct) -> bool {
        use sodiumoxide::utils::memcmp;
        memcmp(&self.keynum_pk.pk, &other.keynum_pk.pk)
    }
}
impl cmp::Eq for PubkeyStruct {}

impl PubkeyStruct {
    pub fn len() -> usize {
        use std::mem;
        mem::size_of::<PubkeyStruct>()
    }

    pub fn from(buf: &[u8]) -> Result<PubkeyStruct> {
        let mut buf = Cursor::new(buf);
        let mut sig_alg = [0u8; TWOBYTES];
        let mut keynum = [0u8; KEYNUMBYTES];
        let mut pk = [0u8; PUBLICKEYBYTES];
        buf.read(&mut sig_alg)?;
        buf.read(&mut keynum)?;
        buf.read(&mut pk)?;
        Ok(PubkeyStruct {
               sig_alg: sig_alg,
               keynum_pk: KeynumPK {
                   keynum: keynum,
                   pk: pk,
               },
           })
    }

    pub fn bytes(&self) -> Vec<u8> {
        let mut iters = Vec::new();
        iters.push(self.sig_alg.iter());
        iters.push(self.keynum_pk.keynum.iter());
        iters.push(self.keynum_pk.pk.iter());
        let v: Vec<u8> = iters
            .iter()
            .flat_map(|b| {
                          let b = b.clone();
                          b.into_iter().cloned()
                      })
            .collect();
        v
    }
}

pub struct SigStruct {
    pub sig_alg: [u8; TWOBYTES],
    pub keynum: [u8; KEYNUMBYTES],
    pub sig: [u8; SIGNATUREBYTES],
}
impl SigStruct {
    pub fn len() -> usize {
        use std::mem;
        mem::size_of::<SigStruct>()
    }
    pub fn bytes(&self) -> Vec<u8> {
        let mut iters = Vec::new();
        iters.push(self.sig_alg.iter());
        iters.push(self.keynum.iter());
        iters.push(self.sig.iter());
        let v: Vec<u8> = iters
            .iter()
            .flat_map(|b| {
                          let b = b.clone();
                          b.into_iter().cloned()
                      })
            .collect();
        v
    }
    pub fn from(bytes_buf: &[u8]) -> Result<SigStruct> {
        let mut buf = Cursor::new(bytes_buf);
        let mut sig_alg = [0u8; 2];
        let mut keynum = [0u8; KEYNUMBYTES];
        let mut sig = [0u8; SIGNATUREBYTES];
        buf.read(&mut sig_alg)?;
        buf.read(&mut keynum)?;
        buf.read(&mut sig)?;
        Ok(SigStruct {
               sig_alg: sig_alg,
               keynum: keynum,
               sig: sig,
           })
    }
}

impl Default for SigStruct {
    fn default() -> Self {
        SigStruct {
            sig_alg: [0u8; TWOBYTES],
            keynum: [0u8; KEYNUMBYTES],
            sig: [0u8; SIGNATUREBYTES],
        }
    }
}