Commit 80675657 authored by Edward Barnard's avatar Edward Barnard
Browse files

Expose EVP_BytesToKey

This is based on work by pyrho.
Closes #88
parent a10604e1
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -128,6 +128,8 @@ pub const MBSTRING_UTF8: c_int = MBSTRING_FLAG;
pub const NID_ext_key_usage: c_int = 126;
pub const NID_key_usage:     c_int = 83;

pub const PKCS5_SALT_LEN: c_int = 8;

pub const SSL_CTRL_OPTIONS: c_int = 32;
pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77;

@@ -409,6 +411,10 @@ extern "C" {
    // fn EVP_aes_256_gcm() -> EVP_CIPHER;
    pub fn EVP_rc4() -> *const EVP_CIPHER;

    pub fn EVP_BytesToKey(typ: *const EVP_CIPHER, md: *const EVP_MD,
                          salt: *const u8, data: *const u8, datalen: c_int,
                          count: c_int, key: *mut u8, iv: *mut u8) -> c_int;

    pub fn EVP_CIPHER_CTX_new() -> *mut EVP_CIPHER_CTX;
    pub fn EVP_CIPHER_CTX_set_padding(ctx: *mut EVP_CIPHER_CTX, padding: c_int) -> c_int;
    pub fn EVP_CIPHER_CTX_free(ctx: *mut EVP_CIPHER_CTX);
+2 −0
Original line number Diff line number Diff line
@@ -22,3 +22,5 @@ pub mod pkey;
pub mod rand;
pub mod symm;
pub mod memcmp;

mod symm_internal;
 No newline at end of file
+109 −0
Original line number Diff line number Diff line
use libc::c_int;
use std::ptr::null;

use crypto::symm_internal::evpc;
use crypto::hash;
use crypto::symm;
use ffi;

#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct KeyIvPair
{
    pub key: Vec<u8>,
    pub iv: Vec<u8>
}

/// Derives a key and an IV from various parameters.
///
/// If specified `salt` must be 8 bytes in length.
///
/// If the total key and IV length is less than 16 bytes and MD5 is used then 
/// the algorithm is compatible with the key derivation algorithm from PKCS#5 
/// v1.5 or PBKDF1 from PKCS#5 v2.0.
///
/// New applications should not use this and instead use `pbkdf2_hmac_sha1` or 
/// another more modern key derivation algorithm.
pub fn evp_bytes_to_key_pbkdf1_compatible(typ: symm::Type, message_digest_type: hash::Type,
                      data: &[u8], salt: Option<&[u8]>,
                      count: u32) -> KeyIvPair {

    unsafe {

        let salt_ptr = match salt {
            Some(salt) => {
                assert_eq!(salt.len(), ffi::PKCS5_SALT_LEN as usize);
                salt.as_ptr()
            },
            None => null()
        };

        ffi::init();

        let (evp, keylen, _) = evpc(typ);

        let message_digest = message_digest_type.evp_md();

        let mut key = vec![0; keylen as usize];
        let mut iv = vec![0; keylen as usize];


        let ret: c_int = ffi::EVP_BytesToKey(evp,
                                             message_digest,
                                             salt_ptr,
                                             data.as_ptr(),
                                             data.len() as c_int,
                                             count as c_int,
                                             key.as_mut_ptr(),
                                             iv.as_mut_ptr());
        assert!(ret == keylen as c_int);
        
        KeyIvPair {
            key: key,
            iv: iv
        }
    }
}

/// Derives a key from a password and salt using the PBKDF2-HMAC-SHA1 algorithm.
pub fn pbkdf2_hmac_sha1(pass: &str, salt: &[u8], iter: usize, keylen: usize) -> Vec<u8> {
    unsafe {
@@ -27,6 +90,9 @@ pub fn pbkdf2_hmac_sha1(pass: &str, salt: &[u8], iter: usize, keylen: usize) ->

#[cfg(test)]
mod tests {
    use crypto::hash;
    use crypto::symm;

    // Test vectors from
    // http://tools.ietf.org/html/draft-josefsson-pbkdf2-test-vectors-06
    #[test]
@@ -116,4 +182,47 @@ mod tests {
            )
        );
    }

    #[test]
    fn test_evp_bytes_to_key_pbkdf1_compatible() {
        let salt = [
            16_u8, 34_u8, 19_u8, 23_u8, 141_u8, 4_u8, 207_u8, 221_u8
        ];

        let data = [
            143_u8, 210_u8, 75_u8, 63_u8, 214_u8, 179_u8, 155_u8,
            241_u8, 242_u8, 31_u8, 154_u8, 56_u8, 198_u8, 145_u8, 192_u8, 64_u8,
            2_u8, 245_u8, 167_u8, 220_u8, 55_u8, 119_u8, 233_u8, 136_u8, 139_u8,
            27_u8, 71_u8, 242_u8, 119_u8, 175_u8, 65_u8, 207_u8
        ];



        let expected_key = vec![
            249_u8, 115_u8, 114_u8, 97_u8, 32_u8, 213_u8, 165_u8, 146_u8, 58_u8,
            87_u8, 234_u8, 3_u8, 43_u8, 250_u8, 97_u8, 114_u8, 26_u8, 98_u8,
            245_u8, 246_u8, 238_u8, 177_u8, 229_u8, 161_u8, 183_u8, 224_u8,
            174_u8, 3_u8, 6_u8, 244_u8, 236_u8, 255_u8
        ];
        let expected_iv = vec![
            4_u8, 223_u8, 153_u8, 219_u8, 28_u8, 142_u8, 234_u8, 68_u8, 227_u8,
            69_u8, 98_u8, 107_u8, 208_u8, 14_u8, 236_u8, 60_u8, 0_u8, 0_u8,
            0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8,
            0_u8, 0_u8, 0_u8
        ];

        assert_eq!(
            super::evp_bytes_to_key_pbkdf1_compatible(
                symm::Type::AES_256_CBC,
                hash::Type::SHA1,
                &data,
                Some(&salt),
                1
            ),
            super::KeyIvPair {
                key: expected_key,
                iv: expected_iv
            }
        );
    }
}
+1 −23
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@ use std::iter::repeat;
use std::convert::AsRef;
use libc::{c_int};

use crypto::symm_internal::evpc;
use ffi;

#[derive(Copy, Clone)]
@@ -34,29 +35,6 @@ pub enum Type {
    RC4_128,
}

fn evpc(t: Type) -> (*const ffi::EVP_CIPHER, u32, u32) {
    unsafe {
        match t {
            Type::AES_128_ECB => (ffi::EVP_aes_128_ecb(), 16, 16),
            Type::AES_128_CBC => (ffi::EVP_aes_128_cbc(), 16, 16),
            #[cfg(feature = "aes_xts")]
            Type::AES_128_XTS => (ffi::EVP_aes_128_xts(), 32, 16),
            #[cfg(feature = "aes_ctr")]
            Type::AES_128_CTR => (ffi::EVP_aes_128_ctr(), 16, 0),
            //AES_128_GCM => (EVP_aes_128_gcm(), 16, 16),

            Type::AES_256_ECB => (ffi::EVP_aes_256_ecb(), 32, 16),
            Type::AES_256_CBC => (ffi::EVP_aes_256_cbc(), 32, 16),
            #[cfg(feature = "aes_xts")]
            Type::AES_256_XTS => (ffi::EVP_aes_256_xts(), 64, 16),
            #[cfg(feature = "aes_ctr")]
            Type::AES_256_CTR => (ffi::EVP_aes_256_ctr(), 32, 0),
            //AES_256_GCM => (EVP_aes_256_gcm(), 32, 16),

            Type::RC4_128 => (ffi::EVP_rc4(), 16, 0),
        }
    }
}

/// Represents a symmetric cipher context.
pub struct Crypter {
+26 −0
Original line number Diff line number Diff line
use crypto::symm;
use ffi;

pub fn evpc(t: symm::Type) -> (*const ffi::EVP_CIPHER, u32, u32) {
    unsafe {
        match t {
            symm::Type::AES_128_ECB => (ffi::EVP_aes_128_ecb(), 16, 16),
            symm::Type::AES_128_CBC => (ffi::EVP_aes_128_cbc(), 16, 16),
            #[cfg(feature = "aes_xts")]
            symm::Type::AES_128_XTS => (ffi::EVP_aes_128_xts(), 32, 16),
            #[cfg(feature = "aes_ctr")]
            symm::Type::AES_128_CTR => (ffi::EVP_aes_128_ctr(), 16, 0),
            //AES_128_GCM => (EVP_aes_128_gcm(), 16, 16),

            symm::Type::AES_256_ECB => (ffi::EVP_aes_256_ecb(), 32, 16),
            symm::Type::AES_256_CBC => (ffi::EVP_aes_256_cbc(), 32, 16),
            #[cfg(feature = "aes_xts")]
            symm::Type::AES_256_XTS => (ffi::EVP_aes_256_xts(), 64, 16),
            #[cfg(feature = "aes_ctr")]
            symm::Type::AES_256_CTR => (ffi::EVP_aes_256_ctr(), 32, 0),
            //AES_256_GCM => (EVP_aes_256_gcm(), 32, 16),

            symm::Type::RC4_128 => (ffi::EVP_rc4(), 16, 0),
        }
    }
}
 No newline at end of file