Merge remote-tracking branch 'remotes/kballard/master'
Conflicts: crypto.rs hash.rs pkcs5.rs pkey.rs rand.rs symm.rs
This commit is contained in:
commit
08374ec054
|
|
@ -1,4 +1,5 @@
|
||||||
*.sw[po]
|
*.sw[po]
|
||||||
libcrypto*.dylib
|
libcrypto*.dylib
|
||||||
|
libcrypto*.so
|
||||||
*.dSYM/
|
*.dSYM/
|
||||||
crypto
|
crypto
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
crypto: $(wildcard *.rs)
|
||||||
|
rustc crypto.rs
|
||||||
|
rustc --test crypto.rs
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f crypto libcrypto-*.so
|
||||||
|
rm -f libcrypto-*.dylib
|
||||||
|
rm -rf *.dSYM
|
||||||
26
README.md
26
README.md
|
|
@ -1,21 +1,13 @@
|
||||||
This package provides Rust bindings for the functionality exposed by OpenSSL's
|
This package provides Rust bindings for the functionality exposed by OpenSSL's
|
||||||
libcrypto. Currently provided:
|
libcrypto. OpenSSL 1.0.1 or higher is required. Currently provided:
|
||||||
|
|
||||||
* Hashes (hash.rs)
|
* Hash functions (hash.rs)
|
||||||
* MD5
|
* SHA-512, SHA-384, SHA-256, SHA-224
|
||||||
* SHA-1
|
* SHA-1
|
||||||
* SHA-2 (224, 256, 384, 512)
|
* MD5
|
||||||
* Symmetric crypto (symm.rs)
|
* Symmetric crypto (symm.rs)
|
||||||
* AES in ECB or CBC mode, all key lengths
|
* AES-128 and AES-256 (ECB, CBC, CTR or GCM mode)
|
||||||
* Keypair generation (pkey.rs)
|
* RC4-128
|
||||||
* RSA, all key lengths
|
* RSA (pkey.rs)
|
||||||
* Asymmetric encryption (pkey.rs)
|
* Encryption with PKCS #1 OAEP padding or PKCS #1 v1.5 padding
|
||||||
* RSA with PKCS#1 OAEP padding
|
* Signatures with PKCS #1 v1.5 padding and any supported hash
|
||||||
* Digital signatures (pkey.rs)
|
|
||||||
* RSA with whatever your system openssl does (PKCS#1 on my system) and sha256
|
|
||||||
|
|
||||||
Each module provides two interfaces: a low-level API which wraps the OpenSSL
|
|
||||||
interfaces as directly as possible and a high-level API which presents the
|
|
||||||
OpenSSL API as a Rust object and tries to make sensible default choices about
|
|
||||||
parameters most users won't care about. You probably want to use the high-level
|
|
||||||
API. For documentation on these, see the individual source files.
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2011 Google Inc.
|
* Copyright 2011 Google Inc.
|
||||||
|
* 2013 Jack Lloyd
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -15,12 +16,14 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#[link(name = "crypto",
|
#[link(name = "crypto",
|
||||||
vers = "0.2",
|
vers = "0.3",
|
||||||
uuid = "38297409-b4c2-4499-8131-a99a7e44dad3")];
|
uuid = "38297409-b4c2-4499-8131-a99a7e44dad3")];
|
||||||
#[crate_type = "lib"];
|
#[crate_type = "lib"];
|
||||||
|
|
||||||
pub mod hash;
|
pub mod hash;
|
||||||
pub mod pkey;
|
pub mod hex;
|
||||||
pub mod symm;
|
pub mod hmac;
|
||||||
pub mod pkcs5;
|
pub mod pkcs5;
|
||||||
|
pub mod pkey;
|
||||||
pub mod rand;
|
pub mod rand;
|
||||||
|
pub mod symm;
|
||||||
|
|
|
||||||
76
hash.rs
76
hash.rs
|
|
@ -40,7 +40,7 @@ mod libcrypto {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evpmd(t: HashType) -> (EVP_MD, uint) {
|
pub fn evpmd(t: HashType) -> (EVP_MD, uint) {
|
||||||
unsafe {
|
unsafe {
|
||||||
match t {
|
match t {
|
||||||
MD5 => (libcrypto::EVP_md5(), 16u),
|
MD5 => (libcrypto::EVP_md5(), 16u),
|
||||||
|
|
@ -115,35 +115,73 @@ pub fn hash(t: HashType, data: &[u8]) -> ~[u8] {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use hex::FromHex;
|
||||||
|
use hex::ToHex;
|
||||||
|
|
||||||
|
struct HashTest {
|
||||||
|
input: ~[u8],
|
||||||
|
expected_output: ~str
|
||||||
|
}
|
||||||
|
|
||||||
|
fn HashTest(input: ~str, output: ~str) -> HashTest {
|
||||||
|
HashTest { input: input.from_hex(),
|
||||||
|
expected_output: output }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hash_test(hashtype: HashType, hashtest: &HashTest) {
|
||||||
|
let calced_raw = hash(hashtype, hashtest.input);
|
||||||
|
|
||||||
|
let calced = calced_raw.to_hex();
|
||||||
|
|
||||||
|
if calced != hashtest.expected_output {
|
||||||
|
println(fmt!("Test failed - %s != %s", calced, hashtest.expected_output));
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(calced == hashtest.expected_output);
|
||||||
|
}
|
||||||
|
|
||||||
// Test vectors from http://www.nsrl.nist.gov/testdata/
|
// Test vectors from http://www.nsrl.nist.gov/testdata/
|
||||||
#[test]
|
#[test]
|
||||||
fn test_md5() {
|
fn test_md5() {
|
||||||
let s0 = ~[0x61u8, 0x62u8, 0x63u8];
|
let tests = [
|
||||||
let d0 =
|
HashTest(~"", ~"D41D8CD98F00B204E9800998ECF8427E"),
|
||||||
~[0x90u8, 0x01u8, 0x50u8, 0x98u8, 0x3cu8, 0xd2u8, 0x4fu8, 0xb0u8,
|
HashTest(~"7F", ~"83ACB6E67E50E31DB6ED341DD2DE1595"),
|
||||||
0xd6u8, 0x96u8, 0x3fu8, 0x7du8, 0x28u8, 0xe1u8, 0x7fu8, 0x72u8];
|
HashTest(~"EC9C", ~"0B07F0D4CA797D8AC58874F887CB0B68"),
|
||||||
assert!(hash(MD5, s0) == d0);
|
HashTest(~"FEE57A", ~"E0D583171EB06D56198FC0EF22173907"),
|
||||||
|
HashTest(~"42F497E0", ~"7C430F178AEFDF1487FEE7144E9641E2"),
|
||||||
|
HashTest(~"C53B777F1C", ~"75EF141D64CB37EC423DA2D9D440C925"),
|
||||||
|
HashTest(~"89D5B576327B", ~"EBBAF15EB0ED784C6FAA9DC32831BF33"),
|
||||||
|
HashTest(~"5D4CCE781EB190", ~"CE175C4B08172019F05E6B5279889F2C"),
|
||||||
|
HashTest(~"81901FE94932D7B9", ~"CD4D2F62B8CDB3A0CF968A735A239281"),
|
||||||
|
HashTest(~"C9FFDEE7788EFB4EC9", ~"E0841A231AB698DB30C6C0F3F246C014"),
|
||||||
|
HashTest(~"66AC4B7EBA95E53DC10B", ~"A3B3CEA71910D9AF56742AA0BB2FE329"),
|
||||||
|
HashTest(~"A510CD18F7A56852EB0319", ~"577E216843DD11573574D3FB209B97D8"),
|
||||||
|
HashTest(~"AAED18DBE8938C19ED734A8D", ~"6F80FB775F27E0A4CE5C2F42FC72C5F1")];
|
||||||
|
|
||||||
|
for test in tests.iter() {
|
||||||
|
hash_test(MD5, test);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sha1() {
|
fn test_sha1() {
|
||||||
let s0 = ~[0x61u8, 0x62u8, 0x63u8];
|
let tests = [
|
||||||
let d0 =
|
HashTest(~"616263", ~"A9993E364706816ABA3E25717850C26C9CD0D89D"),
|
||||||
~[0xa9u8, 0x99u8, 0x3eu8, 0x36u8, 0x47u8, 0x06u8, 0x81u8, 0x6au8,
|
];
|
||||||
0xbau8, 0x3eu8, 0x25u8, 0x71u8, 0x78u8, 0x50u8, 0xc2u8, 0x6cu8,
|
|
||||||
0x9cu8, 0xd0u8, 0xd8u8, 0x9du8];
|
for test in tests.iter() {
|
||||||
assert!(hash(SHA1, s0) == d0);
|
hash_test(SHA1, test);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sha256() {
|
fn test_sha256() {
|
||||||
let s0 = ~[0x61u8, 0x62u8, 0x63u8];
|
let tests = [
|
||||||
let d0 =
|
HashTest(~"616263", ~"BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD")
|
||||||
~[0xbau8, 0x78u8, 0x16u8, 0xbfu8, 0x8fu8, 0x01u8, 0xcfu8, 0xeau8,
|
];
|
||||||
0x41u8, 0x41u8, 0x40u8, 0xdeu8, 0x5du8, 0xaeu8, 0x22u8, 0x23u8,
|
|
||||||
0xb0u8, 0x03u8, 0x61u8, 0xa3u8, 0x96u8, 0x17u8, 0x7au8, 0x9cu8,
|
for test in tests.iter() {
|
||||||
0xb4u8, 0x10u8, 0xffu8, 0x61u8, 0xf2u8, 0x00u8, 0x15u8, 0xadu8];
|
hash_test(SHA256, test);
|
||||||
assert!(hash(SHA256, s0) == d0);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Jack Lloyd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use std::vec;
|
||||||
|
|
||||||
|
pub trait ToHex {
|
||||||
|
fn to_hex(&self) -> ~str;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'self> ToHex for &'self [u8] {
|
||||||
|
fn to_hex(&self) -> ~str {
|
||||||
|
|
||||||
|
let chars = "0123456789ABCDEF".iter().collect::<~[char]>();
|
||||||
|
|
||||||
|
let mut s = ~"";
|
||||||
|
|
||||||
|
for i in range(0u, self.len()) {
|
||||||
|
|
||||||
|
let x = self[i];
|
||||||
|
|
||||||
|
let xhi = (x >> 4) & 0x0F;
|
||||||
|
let xlo = (x ) & 0x0F;
|
||||||
|
|
||||||
|
s.push_char(chars[xhi]);
|
||||||
|
s.push_char(chars[xlo]);
|
||||||
|
}
|
||||||
|
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait FromHex {
|
||||||
|
fn from_hex(&self) -> ~[u8];
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'self> FromHex for &'self str {
|
||||||
|
fn from_hex(&self) -> ~[u8] {
|
||||||
|
let mut vec = vec::with_capacity(self.len() / 2);
|
||||||
|
|
||||||
|
for (i,c) in self.iter().enumerate() {
|
||||||
|
let nibble =
|
||||||
|
if c >= '0' && c <= '9' { (c as u8) - 0x30 }
|
||||||
|
else if c >= 'a' && c <= 'f' { (c as u8) - (0x61 - 10) }
|
||||||
|
else if c >= 'A' && c <= 'F' { (c as u8) - (0x41 - 10) }
|
||||||
|
else { fail!(~"bad hex character"); };
|
||||||
|
|
||||||
|
if i % 2 == 0 {
|
||||||
|
vec.push(nibble << 4);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vec[i/2] |= nibble;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vec
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test() {
|
||||||
|
|
||||||
|
assert!([05u8, 0xffu8, 0x00u8, 0x59u8].to_hex() == ~"05FF0059");
|
||||||
|
|
||||||
|
assert!("00FFA9D1F5".from_hex() == ~[0, 0xff, 0xa9, 0xd1, 0xf5]);
|
||||||
|
|
||||||
|
assert!("00FFA9D1F5".from_hex().to_hex() == ~"00FFA9D1F5");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Jack Lloyd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use hash::*;
|
||||||
|
use std::{libc,ptr,vec};
|
||||||
|
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub struct HMAC_CTX {
|
||||||
|
md: EVP_MD,
|
||||||
|
md_ctx: EVP_MD_CTX,
|
||||||
|
i_ctx: EVP_MD_CTX,
|
||||||
|
o_ctx: EVP_MD_CTX,
|
||||||
|
key_length: libc::c_uint,
|
||||||
|
key: [libc::c_uchar, ..128]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[link_args = "-lcrypto"]
|
||||||
|
#[abi = "cdecl"]
|
||||||
|
extern {
|
||||||
|
fn HMAC_CTX_init(ctx: *mut HMAC_CTX, key: *u8, keylen: libc::c_int, md: EVP_MD);
|
||||||
|
|
||||||
|
fn HMAC_Update(ctx: *mut HMAC_CTX, input: *u8, len: libc::c_uint);
|
||||||
|
|
||||||
|
fn HMAC_Final(ctx: *mut HMAC_CTX, output: *mut u8, len: *mut libc::c_uint);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HMAC {
|
||||||
|
priv ctx: HMAC_CTX,
|
||||||
|
priv len: uint,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn HMAC(ht: HashType, key: ~[u8]) -> HMAC {
|
||||||
|
unsafe {
|
||||||
|
|
||||||
|
let (evp, mdlen) = evpmd(ht);
|
||||||
|
|
||||||
|
let mut ctx : HMAC_CTX = HMAC_CTX {
|
||||||
|
md: ptr::null(),
|
||||||
|
md_ctx: ptr::null(),
|
||||||
|
i_ctx: ptr::null(),
|
||||||
|
o_ctx: ptr::null(),
|
||||||
|
key_length: 0,
|
||||||
|
key: [0u8, .. 128]
|
||||||
|
};
|
||||||
|
|
||||||
|
HMAC_CTX_init(&mut ctx,
|
||||||
|
vec::raw::to_ptr(key),
|
||||||
|
key.len() as libc::c_int,
|
||||||
|
evp);
|
||||||
|
|
||||||
|
HMAC { ctx: ctx, len: mdlen }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HMAC {
|
||||||
|
pub fn update(&mut self, data: &[u8]) {
|
||||||
|
unsafe {
|
||||||
|
do data.as_imm_buf |pdata, len| {
|
||||||
|
HMAC_Update(&mut self.ctx, pdata, len as libc::c_uint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn final(&mut self) -> ~[u8] {
|
||||||
|
unsafe {
|
||||||
|
let mut res = vec::from_elem(self.len, 0u8);
|
||||||
|
let mut outlen: libc::c_uint = 0;
|
||||||
|
do res.as_mut_buf |pres, _len| {
|
||||||
|
HMAC_Final(&mut self.ctx, pres, &mut outlen);
|
||||||
|
assert!(self.len == outlen as uint)
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut h = HMAC(SHA512, ~[00u8]);
|
||||||
|
|
||||||
|
h.update([00u8]);
|
||||||
|
|
||||||
|
println(fmt!("%?", h.final()))
|
||||||
|
}
|
||||||
220
pkey.rs
220
pkey.rs
|
|
@ -3,11 +3,11 @@ use std::libc::{c_int, c_uint};
|
||||||
use std::libc;
|
use std::libc;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::vec;
|
use std::vec;
|
||||||
|
use hash::{HashType, MD5, SHA1, SHA224, SHA256, SHA384, SHA512};
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub type EVP_PKEY = *libc::c_void;
|
pub type EVP_PKEY = *libc::c_void;
|
||||||
|
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub type RSA = *libc::c_void;
|
pub type RSA = *libc::c_void;
|
||||||
|
|
||||||
|
|
@ -16,7 +16,7 @@ mod libcrypto {
|
||||||
use std::libc::{c_char, c_int, c_uint};
|
use std::libc::{c_char, c_int, c_uint};
|
||||||
|
|
||||||
#[link_args = "-lcrypto"]
|
#[link_args = "-lcrypto"]
|
||||||
extern "C" {
|
extern {
|
||||||
fn EVP_PKEY_new() -> *EVP_PKEY;
|
fn EVP_PKEY_new() -> *EVP_PKEY;
|
||||||
fn EVP_PKEY_free(k: *EVP_PKEY);
|
fn EVP_PKEY_free(k: *EVP_PKEY);
|
||||||
fn EVP_PKEY_assign(pkey: *EVP_PKEY, typ: c_int, key: *c_char) -> c_int;
|
fn EVP_PKEY_assign(pkey: *EVP_PKEY, typ: c_int, key: *c_char) -> c_int;
|
||||||
|
|
@ -55,6 +55,30 @@ pub enum Role {
|
||||||
Verify
|
Verify
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc = "Type of encryption padding to use."]
|
||||||
|
pub enum EncryptionPadding {
|
||||||
|
OAEP,
|
||||||
|
PKCS1v15
|
||||||
|
}
|
||||||
|
|
||||||
|
fn openssl_padding_code(padding: EncryptionPadding) -> c_int {
|
||||||
|
match padding {
|
||||||
|
OAEP => 4,
|
||||||
|
PKCS1v15 => 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn openssl_hash_nid(hash: HashType) -> c_int {
|
||||||
|
match hash {
|
||||||
|
MD5 => 4, // NID_md5,
|
||||||
|
SHA1 => 64, // NID_sha1
|
||||||
|
SHA224 => 675, // NID_sha224
|
||||||
|
SHA256 => 672, // NID_sha256
|
||||||
|
SHA384 => 673, // NID_sha384
|
||||||
|
SHA512 => 674, // NID_sha512
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct PKey {
|
pub struct PKey {
|
||||||
priv evp: *EVP_PKEY,
|
priv evp: *EVP_PKEY,
|
||||||
priv parts: Parts,
|
priv parts: Parts,
|
||||||
|
|
@ -195,99 +219,105 @@ impl PKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn encrypt_with_padding(&self, s: &[u8], padding: EncryptionPadding) -> ~[u8] {
|
||||||
|
unsafe {
|
||||||
|
let rsa = libcrypto::EVP_PKEY_get1_RSA(self.evp);
|
||||||
|
let len = libcrypto::RSA_size(rsa);
|
||||||
|
|
||||||
|
assert!(s.len() < self.max_data());
|
||||||
|
|
||||||
|
let mut r = vec::from_elem(len as uint + 1u, 0u8);
|
||||||
|
|
||||||
|
let rv = do r.as_mut_buf |pr, _len| {
|
||||||
|
do s.as_imm_buf |ps, s_len| {
|
||||||
|
libcrypto::RSA_public_encrypt(
|
||||||
|
s_len as c_uint,
|
||||||
|
ps,
|
||||||
|
pr,
|
||||||
|
rsa,
|
||||||
|
openssl_padding_code(padding)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if rv < 0 as c_int {
|
||||||
|
~[]
|
||||||
|
} else {
|
||||||
|
r.truncate(rv as uint);
|
||||||
|
r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decrypt_with_padding(&self, s: &[u8], padding: EncryptionPadding) -> ~[u8] {
|
||||||
|
unsafe {
|
||||||
|
let rsa = libcrypto::EVP_PKEY_get1_RSA(self.evp);
|
||||||
|
let len = libcrypto::RSA_size(rsa);
|
||||||
|
|
||||||
|
assert_eq!(s.len() as c_uint, libcrypto::RSA_size(rsa));
|
||||||
|
|
||||||
|
let mut r = vec::from_elem(len as uint + 1u, 0u8);
|
||||||
|
|
||||||
|
let rv = do r.as_mut_buf |pr, _len| {
|
||||||
|
do s.as_imm_buf |ps, s_len| {
|
||||||
|
libcrypto::RSA_private_decrypt(
|
||||||
|
s_len as c_uint,
|
||||||
|
ps,
|
||||||
|
pr,
|
||||||
|
rsa,
|
||||||
|
openssl_padding_code(padding)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if rv < 0 as c_int {
|
||||||
|
~[]
|
||||||
|
} else {
|
||||||
|
r.truncate(rv as uint);
|
||||||
|
r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encrypts data using OAEP padding, returning the encrypted data. The
|
* Encrypts data using OAEP padding, returning the encrypted data. The
|
||||||
* supplied data must not be larger than max_data().
|
* supplied data must not be larger than max_data().
|
||||||
*/
|
*/
|
||||||
pub fn encrypt(&self, s: &[u8]) -> ~[u8] {
|
pub fn encrypt(&self, s: &[u8]) -> ~[u8] { self.encrypt_with_padding(s, OAEP) }
|
||||||
unsafe {
|
|
||||||
let rsa = libcrypto::EVP_PKEY_get1_RSA(self.evp);
|
|
||||||
let len = libcrypto::RSA_size(rsa);
|
|
||||||
|
|
||||||
// 41 comes from RSA_public_encrypt(3) for OAEP
|
|
||||||
assert!(s.len() < libcrypto::RSA_size(rsa) as uint - 41u);
|
|
||||||
|
|
||||||
let mut r = vec::from_elem(len as uint + 1u, 0u8);
|
|
||||||
|
|
||||||
let rv = do r.as_mut_buf |pr, _len| {
|
|
||||||
do s.as_imm_buf |ps, s_len| {
|
|
||||||
// XXX: 4 == RSA_PKCS1_OAEP_PADDING
|
|
||||||
libcrypto::RSA_public_encrypt(
|
|
||||||
s_len as c_uint,
|
|
||||||
ps,
|
|
||||||
pr,
|
|
||||||
rsa, 4 as c_int
|
|
||||||
)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if rv < 0 as c_int {
|
|
||||||
~[]
|
|
||||||
} else {
|
|
||||||
r.truncate(rv as uint);
|
|
||||||
r
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decrypts data, expecting OAEP padding, returning the decrypted data.
|
* Decrypts data, expecting OAEP padding, returning the decrypted data.
|
||||||
*/
|
*/
|
||||||
pub fn decrypt(&self, s: &[u8]) -> ~[u8] {
|
pub fn decrypt(&self, s: &[u8]) -> ~[u8] { self.decrypt_with_padding(s, OAEP) }
|
||||||
unsafe {
|
|
||||||
let rsa = libcrypto::EVP_PKEY_get1_RSA(self.evp);
|
|
||||||
let len = libcrypto::RSA_size(rsa);
|
|
||||||
|
|
||||||
assert!(s.len() as c_uint == libcrypto::RSA_size(rsa));
|
|
||||||
|
|
||||||
let mut r = vec::from_elem(len as uint + 1u, 0u8);
|
|
||||||
|
|
||||||
let rv = do r.as_mut_buf |pr, _len| {
|
|
||||||
do s.as_imm_buf |ps, s_len| {
|
|
||||||
// XXX: 4 == RSA_PKCS1_OAEP_PADDING
|
|
||||||
libcrypto::RSA_private_decrypt(
|
|
||||||
s_len as c_uint,
|
|
||||||
ps,
|
|
||||||
pr,
|
|
||||||
rsa,
|
|
||||||
4 as c_int
|
|
||||||
)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if rv < 0 as c_int {
|
|
||||||
~[]
|
|
||||||
} else {
|
|
||||||
r.truncate(rv as uint);
|
|
||||||
r
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signs data, using OpenSSL's default scheme and sha256. Unlike encrypt(),
|
* Signs data, using OpenSSL's default scheme and sha256. Unlike encrypt(),
|
||||||
* can process an arbitrary amount of data; returns the signature.
|
* can process an arbitrary amount of data; returns the signature.
|
||||||
*/
|
*/
|
||||||
pub fn sign(&self, s: &[u8]) -> ~[u8] {
|
pub fn sign(&self, s: &[u8]) -> ~[u8] { self.sign_with_hash(s, SHA256) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
pub fn verify(&self, m: &[u8], s: &[u8]) -> bool { self.verify_with_hash(m, s, SHA256) }
|
||||||
|
|
||||||
|
pub fn sign_with_hash(&self, s: &[u8], hash: HashType) -> ~[u8] {
|
||||||
unsafe {
|
unsafe {
|
||||||
let rsa = libcrypto::EVP_PKEY_get1_RSA(self.evp);
|
let rsa = libcrypto::EVP_PKEY_get1_RSA(self.evp);
|
||||||
let len = libcrypto::RSA_size(rsa);
|
let mut len = libcrypto::RSA_size(rsa);
|
||||||
let mut r = vec::from_elem(len as uint + 1u, 0u8);
|
let mut r = vec::from_elem(len as uint + 1u, 0u8);
|
||||||
|
|
||||||
let rv = do r.as_mut_buf |pr, _len| {
|
let rv = do r.as_mut_buf |pr, _len| {
|
||||||
do s.as_imm_buf |ps, s_len| {
|
do s.as_imm_buf |ps, s_len| {
|
||||||
let mut len = len;
|
libcrypto::RSA_sign(
|
||||||
|
openssl_hash_nid(hash),
|
||||||
// XXX: 672 == NID_sha256
|
ps,
|
||||||
libcrypto::RSA_sign(
|
s_len as c_uint,
|
||||||
672 as c_int,
|
pr,
|
||||||
ps,
|
&mut len,
|
||||||
s_len as c_uint,
|
rsa)
|
||||||
pr,
|
}
|
||||||
&mut len,
|
};
|
||||||
rsa)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if rv < 0 as c_int {
|
if rv < 0 as c_int {
|
||||||
~[]
|
~[]
|
||||||
|
|
@ -298,19 +328,14 @@ impl PKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
pub fn verify_with_hash(&self, m: &[u8], s: &[u8], hash: HashType) -> bool {
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
pub fn verify(&self, m: &[u8], s: &[u8]) -> bool {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let rsa = libcrypto::EVP_PKEY_get1_RSA(self.evp);
|
let rsa = libcrypto::EVP_PKEY_get1_RSA(self.evp);
|
||||||
|
|
||||||
do m.as_imm_buf |pm, m_len| {
|
do m.as_imm_buf |pm, m_len| {
|
||||||
do s.as_imm_buf |ps, s_len| {
|
do s.as_imm_buf |ps, s_len| {
|
||||||
// XXX: 672 == NID_sha256
|
|
||||||
let rv = libcrypto::RSA_verify(
|
let rv = libcrypto::RSA_verify(
|
||||||
672 as c_int,
|
openssl_hash_nid(hash),
|
||||||
pm,
|
pm,
|
||||||
m_len as c_uint,
|
m_len as c_uint,
|
||||||
ps,
|
ps,
|
||||||
|
|
@ -336,6 +361,7 @@ impl Drop for PKey {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use hash::{MD5, SHA1};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_gen_pub() {
|
fn test_gen_pub() {
|
||||||
|
|
@ -385,6 +411,18 @@ mod tests {
|
||||||
assert!(msg == dmsg);
|
assert!(msg == dmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_encrypt_pkcs() {
|
||||||
|
let mut k0 = PKey::new();
|
||||||
|
let mut k1 = PKey::new();
|
||||||
|
let msg = ~[0xdeu8, 0xadu8, 0xd0u8, 0x0du8];
|
||||||
|
k0.gen(512u);
|
||||||
|
k1.load_pub(k0.save_pub());
|
||||||
|
let emsg = k1.encrypt_with_padding(msg, PKCS1v15);
|
||||||
|
let dmsg = k0.decrypt_with_padding(emsg, PKCS1v15);
|
||||||
|
assert!(msg == dmsg);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sign() {
|
fn test_sign() {
|
||||||
let mut k0 = PKey::new();
|
let mut k0 = PKey::new();
|
||||||
|
|
@ -396,4 +434,18 @@ mod tests {
|
||||||
let rv = k1.verify(msg, sig);
|
let rv = k1.verify(msg, sig);
|
||||||
assert!(rv == true);
|
assert!(rv == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sign_hashes() {
|
||||||
|
let mut k0 = PKey::new();
|
||||||
|
let mut k1 = PKey::new();
|
||||||
|
let msg = ~[0xdeu8, 0xadu8, 0xd0u8, 0x0du8];
|
||||||
|
k0.gen(512u);
|
||||||
|
k1.load_pub(k0.save_pub());
|
||||||
|
|
||||||
|
let sig = k0.sign_with_hash(msg, MD5);
|
||||||
|
|
||||||
|
assert!(k1.verify_with_hash(msg, sig, MD5));
|
||||||
|
assert!(!k1.verify_with_hash(msg, sig, SHA1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
3
rand.rs
3
rand.rs
|
|
@ -29,6 +29,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rand_bytes() {
|
fn test_rand_bytes() {
|
||||||
let _bytes = rand_bytes(5u);
|
let bytes = rand_bytes(32u);
|
||||||
|
println(fmt!("%?", bytes));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
92
symm.rs
92
symm.rs
|
|
@ -8,7 +8,7 @@ pub type EVP_CIPHER_CTX = *libc::c_void;
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub type EVP_CIPHER = *libc::c_void;
|
pub type EVP_CIPHER = *libc::c_void;
|
||||||
|
|
||||||
pub mod libcrypto {
|
mod libcrypto {
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::libc::{c_int, c_uint};
|
use std::libc::{c_int, c_uint};
|
||||||
|
|
||||||
|
|
@ -20,10 +20,15 @@ pub mod libcrypto {
|
||||||
|
|
||||||
fn EVP_aes_128_ecb() -> EVP_CIPHER;
|
fn EVP_aes_128_ecb() -> EVP_CIPHER;
|
||||||
fn EVP_aes_128_cbc() -> EVP_CIPHER;
|
fn EVP_aes_128_cbc() -> EVP_CIPHER;
|
||||||
fn EVP_aes_192_ecb() -> EVP_CIPHER;
|
// fn EVP_aes_128_ctr() -> EVP_CIPHER;
|
||||||
fn EVP_aes_192_cbc() -> EVP_CIPHER;
|
// fn EVP_aes_128_gcm() -> EVP_CIPHER;
|
||||||
|
|
||||||
fn EVP_aes_256_ecb() -> EVP_CIPHER;
|
fn EVP_aes_256_ecb() -> EVP_CIPHER;
|
||||||
fn EVP_aes_256_cbc() -> EVP_CIPHER;
|
fn EVP_aes_256_cbc() -> EVP_CIPHER;
|
||||||
|
// fn EVP_aes_256_ctr() -> EVP_CIPHER;
|
||||||
|
// fn EVP_aes_256_gcm() -> EVP_CIPHER;
|
||||||
|
|
||||||
|
fn EVP_rc4() -> EVP_CIPHER;
|
||||||
|
|
||||||
fn EVP_CipherInit(ctx: EVP_CIPHER_CTX, evp: EVP_CIPHER,
|
fn EVP_CipherInit(ctx: EVP_CIPHER_CTX, evp: EVP_CIPHER,
|
||||||
key: *u8, iv: *u8, mode: c_int);
|
key: *u8, iv: *u8, mode: c_int);
|
||||||
|
|
@ -40,15 +45,33 @@ pub enum Mode {
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
|
AES_128_ECB,
|
||||||
|
AES_128_CBC,
|
||||||
|
// AES_128_CTR,
|
||||||
|
//AES_128_GCM,
|
||||||
|
|
||||||
AES_256_ECB,
|
AES_256_ECB,
|
||||||
AES_256_CBC,
|
AES_256_CBC,
|
||||||
|
// AES_256_CTR,
|
||||||
|
//AES_256_GCM,
|
||||||
|
|
||||||
|
RC4_128,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evpc(t: Type) -> (EVP_CIPHER, uint, uint) {
|
fn evpc(t: Type) -> (EVP_CIPHER, uint, uint) {
|
||||||
unsafe {
|
unsafe {
|
||||||
match t {
|
match t {
|
||||||
|
AES_128_ECB => (libcrypto::EVP_aes_128_ecb(), 16u, 16u),
|
||||||
|
AES_128_CBC => (libcrypto::EVP_aes_128_cbc(), 16u, 16u),
|
||||||
|
// AES_128_CTR => (libcrypto::EVP_aes_128_ctr(), 16u, 0u),
|
||||||
|
//AES_128_GCM => (libcrypto::EVP_aes_128_gcm(), 16u, 16u),
|
||||||
|
|
||||||
AES_256_ECB => (libcrypto::EVP_aes_256_ecb(), 32u, 16u),
|
AES_256_ECB => (libcrypto::EVP_aes_256_ecb(), 32u, 16u),
|
||||||
AES_256_CBC => (libcrypto::EVP_aes_256_cbc(), 32u, 16u),
|
AES_256_CBC => (libcrypto::EVP_aes_256_cbc(), 32u, 16u),
|
||||||
|
// AES_256_CTR => (libcrypto::EVP_aes_256_ctr(), 32u, 0u),
|
||||||
|
//AES_256_GCM => (libcrypto::EVP_aes_256_gcm(), 32u, 16u),
|
||||||
|
|
||||||
|
RC4_128 => (libcrypto::EVP_rc4(), 16u, 0u),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -73,8 +96,12 @@ impl Crypter {
|
||||||
* data encrypted must be a multiple of block size.
|
* data encrypted must be a multiple of block size.
|
||||||
*/
|
*/
|
||||||
pub fn pad(&self, padding: bool) {
|
pub fn pad(&self, padding: bool) {
|
||||||
let v = if padding { 1 } else { 0} as c_int;
|
if self.blocksize > 0 {
|
||||||
unsafe { libcrypto::EVP_CIPHER_CTX_set_padding(self.ctx, v) };
|
unsafe {
|
||||||
|
let v = if padding { 1 } else { 0 } as c_int;
|
||||||
|
libcrypto::EVP_CIPHER_CTX_set_padding(self.ctx, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -186,6 +213,8 @@ pub fn decrypt(t: Type, key: &[u8], iv: ~[u8], data: &[u8]) -> ~[u8] {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
use hex::FromHex;
|
||||||
|
|
||||||
// Test vectors from FIPS-197:
|
// Test vectors from FIPS-197:
|
||||||
// http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
|
// http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -211,4 +240,57 @@ mod tests {
|
||||||
let p1 = c.update(r0) + c.final();
|
let p1 = c.update(r0) + c.final();
|
||||||
assert!(p1 == p0);
|
assert!(p1 == p0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn cipher_test(ciphertype: Type, pt: ~str, ct: ~str, key: ~str, iv: ~str) {
|
||||||
|
use hex::ToHex;
|
||||||
|
|
||||||
|
let cipher = Crypter::new(ciphertype);
|
||||||
|
cipher.init(Encrypt, key.from_hex(), iv.from_hex());
|
||||||
|
|
||||||
|
let expected = ct.from_hex();
|
||||||
|
let computed = cipher.update(pt.from_hex()) + cipher.final();
|
||||||
|
|
||||||
|
if computed != expected {
|
||||||
|
println(fmt!("Computed: %s", computed.to_hex()));
|
||||||
|
println(fmt!("Expected: %s", expected.to_hex()));
|
||||||
|
if computed.len() != expected.len() {
|
||||||
|
println(fmt!("Lengths differ: %u in computed vs %u expected",
|
||||||
|
computed.len(), expected.len()));
|
||||||
|
}
|
||||||
|
fail!(~"test failure");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rc4() {
|
||||||
|
|
||||||
|
let pt = ~"0000000000000000000000000000000000000000000000000000000000000000000000000000";
|
||||||
|
let ct = ~"A68686B04D686AA107BD8D4CAB191A3EEC0A6294BC78B60F65C25CB47BD7BB3A48EFC4D26BE4";
|
||||||
|
let key = ~"97CD440324DA5FD1F7955C1C13B6B466";
|
||||||
|
let iv = ~"";
|
||||||
|
|
||||||
|
cipher_test(RC4_128, pt, ct, key, iv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*#[test]
|
||||||
|
fn test_aes128_ctr() {
|
||||||
|
|
||||||
|
let pt = ~"6BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710";
|
||||||
|
let ct = ~"874D6191B620E3261BEF6864990DB6CE9806F66B7970FDFF8617187BB9FFFDFF5AE4DF3EDBD5D35E5B4F09020DB03EAB1E031DDA2FBE03D1792170A0F3009CEE";
|
||||||
|
let key = ~"2B7E151628AED2A6ABF7158809CF4F3C";
|
||||||
|
let iv = ~"F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF";
|
||||||
|
|
||||||
|
cipher_test(AES_128_CTR, pt, ct, key, iv);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/*#[test]
|
||||||
|
fn test_aes128_gcm() {
|
||||||
|
// Test case 3 in GCM spec
|
||||||
|
let pt = ~"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255";
|
||||||
|
let ct = ~"42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f59854d5c2af327cd64a62cf35abd2ba6fab4";
|
||||||
|
let key = ~"feffe9928665731c6d6a8f9467308308";
|
||||||
|
let iv = ~"cafebabefacedbaddecaf888";
|
||||||
|
|
||||||
|
cipher_test(AES_128_GCM, pt, ct, key, iv);
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue