aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErick Tryzelaar <[email protected]>2013-08-15 08:20:47 -0700
committerErick Tryzelaar <[email protected]>2013-08-15 08:20:47 -0700
commit08374ec0546d42eb86a867adcd497cf5e874d0b8 (patch)
tree6d73d8ff2eb672e93453b1967a1e2e60cdaecd50
parentRemove pkey::ANYKEY (diff)
parentUpdate to latest rust master (0.8-pre 927aff1) (diff)
downloadrust-openssl-08374ec0546d42eb86a867adcd497cf5e874d0b8.tar.xz
rust-openssl-08374ec0546d42eb86a867adcd497cf5e874d0b8.zip
Merge remote-tracking branch 'remotes/kballard/master'
Conflicts: crypto.rs hash.rs pkcs5.rs pkey.rs rand.rs symm.rs
-rw-r--r--.gitignore1
-rw-r--r--Makefile9
-rw-r--r--README.md26
-rw-r--r--crypto.rs9
-rw-r--r--hash.rs76
-rw-r--r--hex.rs87
-rw-r--r--hmac.rs96
-rw-r--r--pkey.rs168
-rw-r--r--rand.rs3
-rw-r--r--symm.rs92
10 files changed, 464 insertions, 103 deletions
diff --git a/.gitignore b/.gitignore
index cd49243d..ecfc5572 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
*.sw[po]
libcrypto*.dylib
+libcrypto*.so
*.dSYM/
crypto
diff --git a/Makefile b/Makefile
new file mode 100644
index 00000000..9719e55c
--- /dev/null
+++ b/Makefile
@@ -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
diff --git a/README.md b/README.md
index 774949f7..16740d5b 100644
--- a/README.md
+++ b/README.md
@@ -1,21 +1,13 @@
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)
- * MD5
+* Hash functions (hash.rs)
+ * SHA-512, SHA-384, SHA-256, SHA-224
* SHA-1
- * SHA-2 (224, 256, 384, 512)
+ * MD5
* Symmetric crypto (symm.rs)
- * AES in ECB or CBC mode, all key lengths
-* Keypair generation (pkey.rs)
- * RSA, all key lengths
-* Asymmetric encryption (pkey.rs)
- * RSA with PKCS#1 OAEP padding
-* 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.
+ * AES-128 and AES-256 (ECB, CBC, CTR or GCM mode)
+ * RC4-128
+* RSA (pkey.rs)
+ * Encryption with PKCS #1 OAEP padding or PKCS #1 v1.5 padding
+ * Signatures with PKCS #1 v1.5 padding and any supported hash
diff --git a/crypto.rs b/crypto.rs
index e562bdca..1686a715 100644
--- a/crypto.rs
+++ b/crypto.rs
@@ -1,5 +1,6 @@
/*
* Copyright 2011 Google Inc.
+ * 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.
@@ -15,12 +16,14 @@
*/
#[link(name = "crypto",
- vers = "0.2",
+ vers = "0.3",
uuid = "38297409-b4c2-4499-8131-a99a7e44dad3")];
#[crate_type = "lib"];
pub mod hash;
-pub mod pkey;
-pub mod symm;
+pub mod hex;
+pub mod hmac;
pub mod pkcs5;
+pub mod pkey;
pub mod rand;
+pub mod symm;
diff --git a/hash.rs b/hash.rs
index 8cae213d..2a43cbd2 100644
--- a/hash.rs
+++ b/hash.rs
@@ -40,7 +40,7 @@ mod libcrypto {
}
}
-fn evpmd(t: HashType) -> (EVP_MD, uint) {
+pub fn evpmd(t: HashType) -> (EVP_MD, uint) {
unsafe {
match t {
MD5 => (libcrypto::EVP_md5(), 16u),
@@ -115,35 +115,73 @@ pub fn hash(t: HashType, data: &[u8]) -> ~[u8] {
#[cfg(test)]
mod tests {
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]
fn test_md5() {
- let s0 = ~[0x61u8, 0x62u8, 0x63u8];
- let d0 =
- ~[0x90u8, 0x01u8, 0x50u8, 0x98u8, 0x3cu8, 0xd2u8, 0x4fu8, 0xb0u8,
- 0xd6u8, 0x96u8, 0x3fu8, 0x7du8, 0x28u8, 0xe1u8, 0x7fu8, 0x72u8];
- assert!(hash(MD5, s0) == d0);
+ let tests = [
+ HashTest(~"", ~"D41D8CD98F00B204E9800998ECF8427E"),
+ HashTest(~"7F", ~"83ACB6E67E50E31DB6ED341DD2DE1595"),
+ HashTest(~"EC9C", ~"0B07F0D4CA797D8AC58874F887CB0B68"),
+ 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]
fn test_sha1() {
- let s0 = ~[0x61u8, 0x62u8, 0x63u8];
- let d0 =
- ~[0xa9u8, 0x99u8, 0x3eu8, 0x36u8, 0x47u8, 0x06u8, 0x81u8, 0x6au8,
- 0xbau8, 0x3eu8, 0x25u8, 0x71u8, 0x78u8, 0x50u8, 0xc2u8, 0x6cu8,
- 0x9cu8, 0xd0u8, 0xd8u8, 0x9du8];
- assert!(hash(SHA1, s0) == d0);
+ let tests = [
+ HashTest(~"616263", ~"A9993E364706816ABA3E25717850C26C9CD0D89D"),
+ ];
+
+ for test in tests.iter() {
+ hash_test(SHA1, test);
+ }
}
#[test]
fn test_sha256() {
- let s0 = ~[0x61u8, 0x62u8, 0x63u8];
- let d0 =
- ~[0xbau8, 0x78u8, 0x16u8, 0xbfu8, 0x8fu8, 0x01u8, 0xcfu8, 0xeau8,
- 0x41u8, 0x41u8, 0x40u8, 0xdeu8, 0x5du8, 0xaeu8, 0x22u8, 0x23u8,
- 0xb0u8, 0x03u8, 0x61u8, 0xa3u8, 0x96u8, 0x17u8, 0x7au8, 0x9cu8,
- 0xb4u8, 0x10u8, 0xffu8, 0x61u8, 0xf2u8, 0x00u8, 0x15u8, 0xadu8];
- assert!(hash(SHA256, s0) == d0);
+ let tests = [
+ HashTest(~"616263", ~"BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD")
+ ];
+
+ for test in tests.iter() {
+ hash_test(SHA256, test);
+ }
}
}
diff --git a/hex.rs b/hex.rs
new file mode 100644
index 00000000..b479ea18
--- /dev/null
+++ b/hex.rs
@@ -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");
+ }
+
+
+}
diff --git a/hmac.rs b/hmac.rs
new file mode 100644
index 00000000..1e71ed1b
--- /dev/null
+++ b/hmac.rs
@@ -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()))
+}
diff --git a/pkey.rs b/pkey.rs
index 75f5008e..9b97721b 100644
--- a/pkey.rs
+++ b/pkey.rs
@@ -3,11 +3,11 @@ use std::libc::{c_int, c_uint};
use std::libc;
use std::ptr;
use std::vec;
+use hash::{HashType, MD5, SHA1, SHA224, SHA256, SHA384, SHA512};
#[allow(non_camel_case_types)]
pub type EVP_PKEY = *libc::c_void;
-
#[allow(non_camel_case_types)]
pub type RSA = *libc::c_void;
@@ -16,7 +16,7 @@ mod libcrypto {
use std::libc::{c_char, c_int, c_uint};
#[link_args = "-lcrypto"]
- extern "C" {
+ extern {
fn EVP_PKEY_new() -> *EVP_PKEY;
fn EVP_PKEY_free(k: *EVP_PKEY);
fn EVP_PKEY_assign(pkey: *EVP_PKEY, typ: c_int, key: *c_char) -> c_int;
@@ -55,6 +55,30 @@ pub enum Role {
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 {
priv evp: *EVP_PKEY,
priv parts: Parts,
@@ -195,32 +219,26 @@ impl PKey {
}
}
- /**
- * Encrypts data using OAEP padding, returning the encrypted data. The
- * supplied data must not be larger than max_data().
- */
- pub fn encrypt(&self, s: &[u8]) -> ~[u8] {
+ 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);
- // 41 comes from RSA_public_encrypt(3) for OAEP
- assert!(s.len() < libcrypto::RSA_size(rsa) as uint - 41u);
+ 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| {
- // XXX: 4 == RSA_PKCS1_OAEP_PADDING
- libcrypto::RSA_public_encrypt(
- s_len as c_uint,
- ps,
- pr,
- rsa, 4 as c_int
- )
- }
- };
-
+ 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 {
@@ -230,30 +248,26 @@ impl PKey {
}
}
- /**
- * Decrypts data, expecting OAEP padding, returning the decrypted data.
- */
- pub fn decrypt(&self, s: &[u8]) -> ~[u8] {
+ 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!(s.len() as c_uint == 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| {
- // XXX: 4 == RSA_PKCS1_OAEP_PADDING
- libcrypto::RSA_private_decrypt(
- s_len as c_uint,
- ps,
- pr,
- rsa,
- 4 as c_int
- )
- }
- };
+ 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 {
~[]
@@ -265,29 +279,45 @@ impl PKey {
}
/**
+ * Encrypts data using OAEP padding, returning the encrypted data. The
+ * supplied data must not be larger than max_data().
+ */
+ pub fn encrypt(&self, s: &[u8]) -> ~[u8] { self.encrypt_with_padding(s, OAEP) }
+
+ /**
+ * Decrypts data, expecting OAEP padding, returning the decrypted data.
+ */
+ pub fn decrypt(&self, s: &[u8]) -> ~[u8] { self.decrypt_with_padding(s, OAEP) }
+
+ /**
* Signs data, using OpenSSL's default scheme and sha256. Unlike encrypt(),
* 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 {
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 rv = do r.as_mut_buf |pr, _len| {
- do s.as_imm_buf |ps, s_len| {
- let mut len = len;
-
- // XXX: 672 == NID_sha256
- libcrypto::RSA_sign(
- 672 as c_int,
- ps,
- s_len as c_uint,
- pr,
- &mut len,
- rsa)
- }
- };
+ do s.as_imm_buf |ps, s_len| {
+ libcrypto::RSA_sign(
+ openssl_hash_nid(hash),
+ ps,
+ s_len as c_uint,
+ pr,
+ &mut len,
+ rsa)
+ }
+ };
if rv < 0 as c_int {
~[]
@@ -298,19 +328,14 @@ impl PKey {
}
}
- /**
- * 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 {
+ pub fn verify_with_hash(&self, m: &[u8], s: &[u8], hash: HashType) -> bool {
unsafe {
let rsa = libcrypto::EVP_PKEY_get1_RSA(self.evp);
do m.as_imm_buf |pm, m_len| {
do s.as_imm_buf |ps, s_len| {
- // XXX: 672 == NID_sha256
let rv = libcrypto::RSA_verify(
- 672 as c_int,
+ openssl_hash_nid(hash),
pm,
m_len as c_uint,
ps,
@@ -336,6 +361,7 @@ impl Drop for PKey {
#[cfg(test)]
mod tests {
use super::*;
+ use hash::{MD5, SHA1};
#[test]
fn test_gen_pub() {
@@ -386,6 +412,18 @@ mod tests {
}
#[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]
fn test_sign() {
let mut k0 = PKey::new();
let mut k1 = PKey::new();
@@ -396,4 +434,18 @@ mod tests {
let rv = k1.verify(msg, sig);
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));
+ }
}
diff --git a/rand.rs b/rand.rs
index b05706a0..eedac4ab 100644
--- a/rand.rs
+++ b/rand.rs
@@ -29,6 +29,7 @@ mod tests {
#[test]
fn test_rand_bytes() {
- let _bytes = rand_bytes(5u);
+ let bytes = rand_bytes(32u);
+ println(fmt!("%?", bytes));
}
}
diff --git a/symm.rs b/symm.rs
index c4ed97e9..bc28624a 100644
--- a/symm.rs
+++ b/symm.rs
@@ -8,7 +8,7 @@ pub type EVP_CIPHER_CTX = *libc::c_void;
#[allow(non_camel_case_types)]
pub type EVP_CIPHER = *libc::c_void;
-pub mod libcrypto {
+mod libcrypto {
use super::*;
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_cbc() -> EVP_CIPHER;
- fn EVP_aes_192_ecb() -> EVP_CIPHER;
- fn EVP_aes_192_cbc() -> EVP_CIPHER;
+ // fn EVP_aes_128_ctr() -> EVP_CIPHER;
+ // fn EVP_aes_128_gcm() -> EVP_CIPHER;
+
fn EVP_aes_256_ecb() -> 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,
key: *u8, iv: *u8, mode: c_int);
@@ -40,15 +45,33 @@ pub enum Mode {
#[allow(non_camel_case_types)]
pub enum Type {
+ AES_128_ECB,
+ AES_128_CBC,
+ // AES_128_CTR,
+ //AES_128_GCM,
+
AES_256_ECB,
AES_256_CBC,
+ // AES_256_CTR,
+ //AES_256_GCM,
+
+ RC4_128,
}
fn evpc(t: Type) -> (EVP_CIPHER, uint, uint) {
unsafe {
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_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.
*/
pub fn pad(&self, padding: bool) {
- let v = if padding { 1 } else { 0} as c_int;
- unsafe { libcrypto::EVP_CIPHER_CTX_set_padding(self.ctx, v) };
+ if self.blocksize > 0 {
+ 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 {
use super::*;
+ use hex::FromHex;
+
// Test vectors from FIPS-197:
// http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
#[test]
@@ -211,4 +240,57 @@ mod tests {
let p1 = c.update(r0) + c.final();
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);
+ }*/
}