ctaes-sys 0.1.0

Native bindings to the ctaes library
Documentation
#[macro_use]
extern crate failure;
extern crate typenum;
extern crate generic_array;
extern crate libc;

use failure::Error;
use typenum::{U15, U32};
use generic_array::{GenericArray, ArrayLength};
use libc::c_uchar;

#[repr(C)]
#[derive(Debug, Copy, Clone, Default)]
pub struct AES_state {
    pub slice: [u16; 8],
}

#[repr(C)]
#[derive(Debug, Copy, Clone, Default)]
pub struct AES256_ctx {
    pub rk: [AES_state; 15],
}

#[link_name = "ctaes"]
extern "C" {
    pub fn AES256_init(ctx: *mut AES256_ctx, key32: *const c_uchar);

    pub fn AES256_encrypt(
        ctx: *const AES256_ctx,
        blocks: usize,
        cipher16: *mut c_uchar,
        plain16: *const c_uchar,
    );

    pub fn AES256_decrypt(
        ctx: *const AES256_ctx,
        blocks: usize,
        plain16: *mut c_uchar,
        cipher16: *const c_uchar,
    );
}

#[derive(Debug, Copy, Clone, Default)]
pub struct AESGCMState(pub [u16; 8]);

impl AESGCMState {
    fn as_c_repr(&self) -> AES_state {
        AES_state { slice: self.0 }
    }

    fn from_c_repr(repr: AES_state) -> AESGCMState {
        AESGCMState(repr.slice)
    }
}

#[derive(Debug, Copy, Clone, Default)]
pub struct AESGCM256(pub GenericArray<AESGCMState, U15>);

impl AESGCM256 {
    fn as_c_repr(&self) -> AES256_ctx {
        let mut arr = [AES_state::default(); 15];
        for i in 0..15 {
            arr[i] = self.0[i].as_c_repr();
        }
        AES256_ctx { rk: arr }
    }

    fn from_c_repr(repr: AES256_ctx) -> AESGCM256 {
        let mut arr = GenericArray::<AESGCMState, U15>::default();
        for i in 0..15 {
            arr[i] = AESGCMState::from_c_repr(repr.rk[i]);
        }
        AESGCM256(arr)
    }
}

pub trait AESGCMCipher {
    type Ctx;
    type KeySize: ArrayLength<u8>;
    fn new(key: GenericArray<u8, Self::KeySize>) -> Self;
    fn encrypt(&mut self, plain: &[u8]) -> Result<Vec<u8>, Error>;
    fn decrypt(&mut self, ciph: &[u8]) -> Result<Vec<u8>, Error>;
}

pub type AES256GCMKey = GenericArray<u8, U32>;

impl AESGCMCipher for AESGCM256 {
    type Ctx = AESGCM256;
    type KeySize = U32;

    fn new(key: AES256GCMKey) -> Self {
        let mut ctx = AES256_ctx::default();
        unsafe {
            AES256_init(&mut ctx, key.as_slice().as_ptr());
        }
        AESGCM256::from_c_repr(ctx)
    }

    fn encrypt(&mut self, plain: &[u8]) -> Result<Vec<u8>, Error> {
        let ctx = self.as_c_repr();
        let len = plain.len();
        if len % 16 != 0 {
            return Err(format_err!("invalid length"));
        }
        let blocks = len / 16;
        let mut ciph = Vec::new();
        for _ in 0..blocks {
            ciph.extend_from_slice(&[0u8; 16][..]);
        }
        unsafe {
            AES256_encrypt(&ctx, blocks, ciph.as_mut_ptr(), plain.as_ptr());
        }
        Ok(ciph)
    }

    fn decrypt(&mut self, ciph: &[u8]) -> Result<Vec<u8>, Error> {
        let ctx = self.as_c_repr();
        let len = ciph.len();
        if len % 16 != 0 {
            return Err(format_err!("invalid length"));
        }
        let blocks = len / 16;
        let mut plain = Vec::new();
        for _ in 0..blocks {
            plain.extend_from_slice(&[0u8; 16][..]);
        }
        unsafe {
            AES256_decrypt(&ctx, blocks, plain.as_mut_ptr(), ciph.as_ptr());
        }
        Ok(plain)
    }
}

#[cfg(test)]
mod tests {
    extern crate hex;

    use super::*;

    fn test_vectors() -> Vec<(String, String, String)> {
        vec![
            (
                "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f".to_string(),
                "00112233445566778899aabbccddeeff".to_string(),
                "8ea2b7ca516745bfeafc49904b496089".to_string()
            ),
            (
                "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4".to_string(),
                "6bc1bee22e409f96e93d7e117393172a".to_string(),
                "f3eed1bdb5d2a03c064b5a7e3db181f8".to_string()
            ),
            (
                "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4".to_string(),
                "ae2d8a571e03ac9c9eb76fac45af8e51".to_string(),
                "591ccb10d410ed26dc5ba74a31362870".to_string()
            ),
            (
                "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4".to_string(),
                "30c81c46a35ce411e5fbc1191a0a52ef".to_string(),
                "b6ed21b99ca6f4f9f153e7b1beafed1d".to_string()
            ),
            (
                "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4".to_string(),
                "f69f2445df4f9b17ad2b417be66c3710".to_string(),
                "23304b7a39f9f3ff067d8d8f9e24ecc7".to_string()
            ),
        ]
    }

    #[test]
    fn aes_gcm_encrypt_test_vectors() {
        for v in test_vectors() {
            let key = *AES256GCMKey::from_slice(hex::decode(v.0).unwrap().as_slice());
            let mut cipher = AESGCM256::new(key);
            let res = cipher.encrypt(hex::decode(v.1).unwrap().as_slice()).unwrap();
            let test = hex::decode(v.2).unwrap();
            assert_eq!(res, test.as_slice())
        }
    }

    #[test]
    fn aes_gcm_decrypt_test_vectors() {
        for v in test_vectors() {
            let key = *AES256GCMKey::from_slice(hex::decode(v.0).unwrap().as_slice());
            let mut cipher = AESGCM256::new(key);
            let res = cipher.decrypt(hex::decode(v.2).unwrap().as_slice()).unwrap();
            let test = hex::decode(v.1).unwrap();
            assert_eq!(res, test.as_slice())
        }
    }
}