Merge pull request #5 from erickt/master

modernizing rustcrypto and exposing PKCS5_PBKDF2_HMAC_SHA1
This commit is contained in:
Elly Fong-Jones 2012-06-02 13:35:09 -07:00
commit c0bbc889d1
6 changed files with 177 additions and 143 deletions

View File

@ -24,3 +24,5 @@ use std; // FIXME https://github.com/mozilla/rust/issues/1127
mod hash; mod hash;
mod pkey; mod pkey;
mod symm; mod symm;
mod pkcs5;
mod rand;

35
hash.rs
View File

@ -1,40 +1,23 @@
use std;
import core::ptr;
import core::str;
import core::vec;
import libc::c_uint; import libc::c_uint;
export hasher; export hasher;
export hashtype; export hashtype;
export mk_hasher;
export hash; export hash;
export _native; export _native;
export md5, sha1, sha224, sha256, sha384, sha512; export md5, sha1, sha224, sha256, sha384, sha512;
iface hasher { iface hasher {
/* #[doc = "Initializes this hasher"]
Method: init
Initializes this hasher
*/
fn init(); fn init();
/* #[doc = "Update this hasher with more input bytes"]
Method: update
Update this hasher with more input bytes
*/
fn update([u8]); fn update([u8]);
/* #[doc = "
Method: final
Return the digest of all bytes added to this hasher since its last Return the digest of all bytes added to this hasher since its last
initialization initialization
*/ "]
fn final() -> [u8]; fn final() -> [u8];
} }
@ -78,7 +61,7 @@ fn evpmd(t: hashtype) -> (EVP_MD, uint) {
} }
} }
fn mk_hasher(ht: hashtype) -> hasher { fn hasher(ht: hashtype) -> hasher {
type hasherstate = { type hasherstate = {
evp: EVP_MD, evp: EVP_MD,
ctx: EVP_MD_CTX, ctx: EVP_MD_CTX,
@ -111,13 +94,11 @@ fn mk_hasher(ht: hashtype) -> hasher {
ret h; ret h;
} }
/* #[doc = "
Function: hash
Hashes the supplied input data using hash t, returning the resulting hash value Hashes the supplied input data using hash t, returning the resulting hash value
*/ "]
fn hash(t: hashtype, data: [u8]) -> [u8] unsafe { fn hash(t: hashtype, data: [u8]) -> [u8] unsafe {
let h = mk_hasher(t); let h = hasher(t);
h.init(); h.init();
h.update(data); h.update(data);
ret h.final(); ret h.final();

89
pkcs5.rs Normal file
View File

@ -0,0 +1,89 @@
import libc::{c_char, c_uchar, c_int};
#[link_name = "crypto"]
#[abi = "cdecl"]
native mod _native {
fn PKCS5_PBKDF2_HMAC_SHA1(pass: *c_char, passlen: c_int,
salt: *c_uchar, saltlen: c_int,
iter: c_int, keylen: c_int,
out: *c_uchar) -> c_int;
}
#[doc = "
Derives a key from a password and salt using the PBKDF2-HMAC-SHA1 algorithm.
"]
fn pbkdf2_hmac_sha1(pass: str, salt: [u8], iter: uint, keylen: uint) -> [u8] {
assert iter >= 1u;
assert keylen >= 1u;
str::as_c_str(pass) { |pass_buf|
vec::as_buf(salt) { |salt_buf|
let mut out = [];
vec::reserve(out, keylen);
vec::as_buf(out) { |out_buf|
let r = _native::PKCS5_PBKDF2_HMAC_SHA1(
pass_buf, str::len(pass) as c_int,
salt_buf, vec::len(salt) as c_int,
iter as c_int, keylen as c_int,
out_buf);
if r != 1 as c_int { fail; }
unsafe { vec::unsafe::set_len(out, keylen); }
out
}
}
}
}
#[cfg(test)]
mod tests {
// Test vectors from
// http://tools.ietf.org/html/draft-josefsson-pbkdf2-test-vectors-06
#[test]
fn test_pbkdf2_hmac_sha1() {
assert pbkdf2_hmac_sha1("password", str::bytes("salt"), 1u, 20u) == [
0x0c_u8, 0x60_u8, 0xc8_u8, 0x0f_u8, 0x96_u8, 0x1f_u8, 0x0e_u8,
0x71_u8, 0xf3_u8, 0xa9_u8, 0xb5_u8, 0x24_u8, 0xaf_u8, 0x60_u8,
0x12_u8, 0x06_u8, 0x2f_u8, 0xe0_u8, 0x37_u8, 0xa6_u8
];
assert pbkdf2_hmac_sha1("password", str::bytes("salt"), 2u, 20u) == [
0xea_u8, 0x6c_u8, 0x01_u8, 0x4d_u8, 0xc7_u8, 0x2d_u8, 0x6f_u8,
0x8c_u8, 0xcd_u8, 0x1e_u8, 0xd9_u8, 0x2a_u8, 0xce_u8, 0x1d_u8,
0x41_u8, 0xf0_u8, 0xd8_u8, 0xde_u8, 0x89_u8, 0x57_u8
];
assert pbkdf2_hmac_sha1("password", str::bytes("salt"), 4096u,
20u) == [
0x4b_u8, 0x00_u8, 0x79_u8, 0x01_u8, 0xb7_u8, 0x65_u8, 0x48_u8,
0x9a_u8, 0xbe_u8, 0xad_u8, 0x49_u8, 0xd9_u8, 0x26_u8, 0xf7_u8,
0x21_u8, 0xd0_u8, 0x65_u8, 0xa4_u8, 0x29_u8, 0xc1_u8
];
assert pbkdf2_hmac_sha1("password", str::bytes("salt"), 16777216u,
20u) == [
0xee_u8, 0xfe_u8, 0x3d_u8, 0x61_u8, 0xcd_u8, 0x4d_u8, 0xa4_u8,
0xe4_u8, 0xe9_u8, 0x94_u8, 0x5b_u8, 0x3d_u8, 0x6b_u8, 0xa2_u8,
0x15_u8, 0x8c_u8, 0x26_u8, 0x34_u8, 0xe9_u8, 0x84_u8
];
assert pbkdf2_hmac_sha1(
"passwordPASSWORDpassword",
str::bytes("saltSALTsaltSALTsaltSALTsaltSALTsalt"),
4096u, 25u) == [
0x3d_u8, 0x2e_u8, 0xec_u8, 0x4f_u8, 0xe4_u8, 0x1c_u8, 0x84_u8,
0x9b_u8, 0x80_u8, 0xc8_u8, 0xd8_u8, 0x36_u8, 0x62_u8, 0xc0_u8,
0xe4_u8, 0x4a_u8, 0x8b_u8, 0x29_u8, 0x1a_u8, 0x96_u8, 0x4c_u8,
0xf2_u8, 0xf0_u8, 0x70_u8, 0x38_u8
];
assert pbkdf2_hmac_sha1("pass\x00word", str::bytes("sa\x00lt"), 4096u,
16u) == [
0x56_u8, 0xfa_u8, 0x6a_u8, 0xa7_u8, 0x55_u8, 0x48_u8, 0x09_u8,
0x9d_u8, 0xcc_u8, 0x37_u8, 0xd7_u8, 0xf0_u8, 0x34_u8, 0x25_u8,
0xe0_u8, 0xc3_u8
];
}
}

109
pkey.rs
View File

@ -1,12 +1,7 @@
import core::ptr;
import core::str;
import core::unsafe;
import core::vec;
import libc::{c_int, c_uint}; import libc::{c_int, c_uint};
export pkeyrole, encrypt, decrypt, sign, verify; export pkeyrole, encrypt, decrypt, sign, verify;
export pkey, mk_pkey; export pkey;
export _native; export _native;
type EVP_PKEY = *libc::c_void; type EVP_PKEY = *libc::c_void;
@ -45,11 +40,7 @@ enum pkeyparts {
both both
} }
/* #[doc = "Represents a role an asymmetric key might be appropriate for."]
Tag: pkeyrole
Represents a role an asymmetric key might be appropriate for.
*/
enum pkeyrole { enum pkeyrole {
encrypt, encrypt,
decrypt, decrypt,
@ -57,100 +48,68 @@ enum pkeyrole {
verify verify
} }
/* #[doc = "Represents a public key, optionally with a private key attached."]
Object: pkey
Represents a public key, optionally with a private key attached.
*/
iface pkey { iface pkey {
/* #[doc = "
Method: save_pub
Returns a serialized form of the public key, suitable for load_pub(). Returns a serialized form of the public key, suitable for load_pub().
*/ "]
fn save_pub() -> [u8]; fn save_pub() -> [u8];
/* #[doc = "
Method: load_pub
Loads a serialized form of the public key, as produced by save_pub(). Loads a serialized form of the public key, as produced by save_pub().
*/ "]
fn load_pub(s: [u8]); fn load_pub(s: [u8]);
/* #[doc = "
Method: save_priv
Returns a serialized form of the public and private keys, suitable for Returns a serialized form of the public and private keys, suitable for
load_priv(). load_priv().
*/ "]
fn save_priv() -> [u8]; fn save_priv() -> [u8];
/* #[doc = "
Method: load_priv
Loads a serialized form of the public and private keys, as produced by Loads a serialized form of the public and private keys, as produced by
save_priv(). save_priv().
*/ "]
fn load_priv(s: [u8]); fn load_priv(s: [u8]);
/* #[doc = "Returns the size of the public key modulus."]
Method: size()
Returns the size of the public key modulus.
*/
fn size() -> uint; fn size() -> uint;
/* #[doc = "Generates a public/private keypair of the specified size."]
Method: gen()
Generates a public/private keypair of the specified size.
*/
fn gen(keysz: uint); fn gen(keysz: uint);
/* #[doc = "
Method: can()
Returns whether this pkey object can perform the specified role. Returns whether this pkey object can perform the specified role.
*/ "]
fn can(role: pkeyrole) -> bool; fn can(role: pkeyrole) -> bool;
/* #[doc = "
Method: max_data()
Returns the maximum amount of data that can be encrypted by an encrypt() Returns the maximum amount of data that can be encrypted by an encrypt()
call. call.
*/ "]
fn max_data() -> uint; fn max_data() -> uint;
/* #[doc = "
Method: encrypt()
Encrypts data using OAEP padding, returning the encrypted data. The supplied Encrypts data using OAEP padding, returning the encrypted data. The supplied
data must not be larger than max_data(). data must not be larger than max_data().
*/ "]
fn encrypt(s: [u8]) -> [u8]; fn encrypt(s: [u8]) -> [u8];
/* #[doc = "
Method: decrypt()
Decrypts data, expecting OAEP padding, returning the decrypted data. Decrypts data, expecting OAEP padding, returning the decrypted data.
*/ "]
fn decrypt(s: [u8]) -> [u8]; fn decrypt(s: [u8]) -> [u8];
/* #[doc = "
Method: sign()
Signs data, using OpenSSL's default scheme and sha256. Unlike encrypt(), can Signs data, using OpenSSL's default scheme and sha256. Unlike encrypt(), can
process an arbitrary amount of data; returns the signature. process an arbitrary amount of data; returns the signature.
*/ "]
fn sign(s: [u8]) -> [u8]; fn sign(s: [u8]) -> [u8];
/* #[doc = "
Method: verify()
Verifies a signature s (using OpenSSL's default scheme and sha256) on a Verifies a signature s (using OpenSSL's default scheme and sha256) on a
message m. Returns true if the signature is valid, and false otherwise. message m. Returns true if the signature is valid, and false otherwise.
*/ "]
fn verify(m: [u8], s: [u8]) -> bool; fn verify(m: [u8], s: [u8]) -> bool;
} }
@ -162,7 +121,7 @@ fn any_to_rsa(anykey: *ANYKEY) -> *RSA unsafe {
unsafe::reinterpret_cast::<*ANYKEY, *RSA>(anykey) unsafe::reinterpret_cast::<*ANYKEY, *RSA>(anykey)
} }
fn mk_pkey() -> pkey { fn pkey() -> pkey {
type pkeystate = { type pkeystate = {
mut evp: *EVP_PKEY, mut evp: *EVP_PKEY,
mut parts: pkeyparts mut parts: pkeyparts
@ -302,8 +261,8 @@ fn mk_pkey() -> pkey {
mod tests { mod tests {
#[test] #[test]
fn test_gen_pub() { fn test_gen_pub() {
let k0 = mk_pkey(); let k0 = pkey();
let k1 = mk_pkey(); let k1 = pkey();
k0.gen(512u); k0.gen(512u);
k1.load_pub(k0.save_pub()); k1.load_pub(k0.save_pub());
assert(k0.save_pub() == k1.save_pub()); assert(k0.save_pub() == k1.save_pub());
@ -320,8 +279,8 @@ mod tests {
#[test] #[test]
fn test_gen_priv() { fn test_gen_priv() {
let k0 = mk_pkey(); let k0 = pkey();
let k1 = mk_pkey(); let k1 = pkey();
k0.gen(512u); k0.gen(512u);
k1.load_priv(k0.save_priv()); k1.load_priv(k0.save_priv());
assert(k0.save_priv() == k1.save_priv()); assert(k0.save_priv() == k1.save_priv());
@ -338,8 +297,8 @@ mod tests {
#[test] #[test]
fn test_encrypt() { fn test_encrypt() {
let k0 = mk_pkey(); let k0 = pkey();
let k1 = mk_pkey(); let k1 = pkey();
let msg: [u8] = [0xdeu8, 0xadu8, 0xd0u8, 0x0du8]; let msg: [u8] = [0xdeu8, 0xadu8, 0xd0u8, 0x0du8];
k0.gen(512u); k0.gen(512u);
k1.load_pub(k0.save_pub()); k1.load_pub(k0.save_pub());
@ -350,8 +309,8 @@ mod tests {
#[test] #[test]
fn test_sign() { fn test_sign() {
let k0 = mk_pkey(); let k0 = pkey();
let k1 = mk_pkey(); let k1 = pkey();
let msg: [u8] = [0xdeu8, 0xadu8, 0xd0u8, 0x0du8]; let msg: [u8] = [0xdeu8, 0xadu8, 0xd0u8, 0x0du8];
k0.gen(512u); k0.gen(512u);
k1.load_pub(k0.save_pub()); k1.load_pub(k0.save_pub());

28
rand.rs Normal file
View File

@ -0,0 +1,28 @@
import libc::{c_uchar, c_int};
#[link_name = "crypto"]
#[abi = "cdecl"]
native mod _native {
fn RAND_bytes(buf: *c_uchar, num: c_int) -> c_int;
}
fn rand_bytes(len: uint) -> [u8] {
let mut out = [];
vec::reserve(out, len);
vec::as_buf(out) { |out_buf|
let r = _native::RAND_bytes(out_buf, len as c_int);
if r != 1 as c_int { fail }
unsafe { vec::unsafe::set_len(out, len); }
out
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_rand_bytes() {
let _bytes = rand_bytes(5u);
}
}

57
symm.rs
View File

@ -1,9 +1,3 @@
use std;
import core::ptr;
import core::str;
import core::vec;
import libc::c_int; import libc::c_int;
export crypter; export crypter;
@ -11,7 +5,6 @@ export cryptermode;
export encryptmode, decryptmode; export encryptmode, decryptmode;
export cryptertype; export cryptertype;
export aes_256_ecb, aes_256_cbc; export aes_256_ecb, aes_256_cbc;
export mk_crypter;
export encrypt, decrypt; export encrypt, decrypt;
export _native; export _native;
@ -38,40 +31,26 @@ native mod _native {
fn EVP_CipherFinal(ctx: EVP_CIPHER_CTX, res: *u8, len: *u32); fn EVP_CipherFinal(ctx: EVP_CIPHER_CTX, res: *u8, len: *u32);
} }
/* #[doc = "Represents a symmetric cipher context."]
Object: crypter
Represents a symmetric cipher context.
*/
iface crypter { iface crypter {
/* #[doc = "
Method: pad
Enables or disables padding. If padding is disabled, total amount of data Enables or disables padding. If padding is disabled, total amount of data
encrypted must be a multiple of block size. encrypted must be a multiple of block size.
*/ "]
fn pad(padding: bool); fn pad(padding: bool);
/* #[doc = "Initializes this crypter."]
Method: init
Initializes this crypter.
*/
fn init(mode: cryptermode, key: [u8], iv: [u8]); fn init(mode: cryptermode, key: [u8], iv: [u8]);
/* #[doc = "
Method: update
Update this crypter with more data to encrypt or decrypt. Returns encrypted Update this crypter with more data to encrypt or decrypt. Returns encrypted
or decrypted bytes. or decrypted bytes.
*/ "]
fn update(data: [u8]) -> [u8]; fn update(data: [u8]) -> [u8];
/* #[doc = "
Method: final
Finish crypting. Returns the remaining partial block of output, if any. Finish crypting. Returns the remaining partial block of output, if any.
*/ "]
fn final() -> [u8]; fn final() -> [u8];
} }
@ -92,7 +71,7 @@ fn evpc(t: cryptertype) -> (EVP_CIPHER, uint, uint) {
} }
} }
fn mk_crypter(t: cryptertype) -> crypter { fn crypter(t: cryptertype) -> crypter {
type crypterstate = { type crypterstate = {
evp: EVP_CIPHER, evp: EVP_CIPHER,
ctx: EVP_CIPHER_CTX, ctx: EVP_CIPHER_CTX,
@ -142,28 +121,24 @@ fn mk_crypter(t: cryptertype) -> crypter {
ret h; ret h;
} }
/* #[doc = "
Function: encrypt
Encrypts data, using the specified crypter type in encrypt mode with the Encrypts data, using the specified crypter type in encrypt mode with the
specified key and iv; returns the resulting (encrypted) data. specified key and iv; returns the resulting (encrypted) data.
*/ "]
fn encrypt(t: cryptertype, key: [u8], iv: [u8], data: [u8]) -> [u8] { fn encrypt(t: cryptertype, key: [u8], iv: [u8], data: [u8]) -> [u8] {
let c = mk_crypter(t); let c = crypter(t);
c.init(encryptmode, key, iv); c.init(encryptmode, key, iv);
let r = c.update(data); let r = c.update(data);
let rest = c.final(); let rest = c.final();
ret r + rest; ret r + rest;
} }
/* #[doc = "
Function: decrypt
Decrypts data, using the specified crypter type in decrypt mode with the Decrypts data, using the specified crypter type in decrypt mode with the
specified key and iv; returns the resulting (decrypted) data. specified key and iv; returns the resulting (decrypted) data.
*/ "]
fn decrypt(t: cryptertype, key: [u8], iv: [u8], data: [u8]) -> [u8] { fn decrypt(t: cryptertype, key: [u8], iv: [u8], data: [u8]) -> [u8] {
let c = mk_crypter(t); let c = crypter(t);
c.init(decryptmode, key, iv); c.init(decryptmode, key, iv);
let r = c.update(data); let r = c.update(data);
let rest = c.final(); let rest = c.final();
@ -187,7 +162,7 @@ mod tests {
let c0 = let c0 =
[ 0x8eu8, 0xa2u8, 0xb7u8, 0xcau8, 0x51u8, 0x67u8, 0x45u8, 0xbfu8, [ 0x8eu8, 0xa2u8, 0xb7u8, 0xcau8, 0x51u8, 0x67u8, 0x45u8, 0xbfu8,
0xeau8, 0xfcu8, 0x49u8, 0x90u8, 0x4bu8, 0x49u8, 0x60u8, 0x89u8 ]; 0xeau8, 0xfcu8, 0x49u8, 0x90u8, 0x4bu8, 0x49u8, 0x60u8, 0x89u8 ];
let c = mk_crypter(aes_256_ecb); let c = crypter(aes_256_ecb);
c.init(encryptmode, k0, []); c.init(encryptmode, k0, []);
c.pad(false); c.pad(false);
let r0 = c.update(p0) + c.final(); let r0 = c.update(p0) + c.final();