aboutsummaryrefslogtreecommitdiff
path: root/openssl/src/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'openssl/src/crypto')
-rw-r--r--openssl/src/crypto/dsa.rs338
-rw-r--r--openssl/src/crypto/hash.rs150
-rw-r--r--openssl/src/crypto/hmac.rs162
-rw-r--r--openssl/src/crypto/mod.rs11
-rw-r--r--openssl/src/crypto/pkcs5.rs179
-rw-r--r--openssl/src/crypto/pkey.rs876
-rw-r--r--openssl/src/crypto/rand.rs20
-rw-r--r--openssl/src/crypto/rsa.rs303
-rw-r--r--openssl/src/crypto/symm.rs329
-rw-r--r--openssl/src/crypto/symm_internal.rs35
-rw-r--r--openssl/src/crypto/util.rs58
11 files changed, 1097 insertions, 1364 deletions
diff --git a/openssl/src/crypto/dsa.rs b/openssl/src/crypto/dsa.rs
new file mode 100644
index 00000000..97ba7a97
--- /dev/null
+++ b/openssl/src/crypto/dsa.rs
@@ -0,0 +1,338 @@
+use ffi;
+use std::fmt;
+use error::ErrorStack;
+use std::ptr;
+use libc::{c_uint, c_int, c_char, c_void};
+
+use bn::BigNumRef;
+use bio::{MemBio, MemBioSlice};
+use crypto::hash;
+use HashTypeInternals;
+use crypto::util::{CallbackState, invoke_passwd_cb};
+
+
+/// Builder for upfront DSA parameter generateration
+pub struct DSAParams(*mut ffi::DSA);
+
+impl DSAParams {
+ pub fn with_size(size: u32) -> Result<DSAParams, ErrorStack> {
+ unsafe {
+ // Wrap it so that if we panic we'll call the dtor
+ let dsa = DSAParams(try_ssl_null!(ffi::DSA_new()));
+ try_ssl!(ffi::DSA_generate_parameters_ex(dsa.0, size as c_int, ptr::null(), 0,
+ ptr::null_mut(), ptr::null_mut(), ptr::null()));
+ Ok(dsa)
+ }
+ }
+
+ /// Generate a key pair from the initialized parameters
+ pub fn generate(self) -> Result<DSA, ErrorStack> {
+ unsafe {
+ try_ssl!(ffi::DSA_generate_key(self.0));
+ let dsa = DSA(self.0);
+ ::std::mem::forget(self);
+ Ok(dsa)
+ }
+ }
+}
+
+impl Drop for DSAParams {
+ fn drop(&mut self) {
+ unsafe {
+ ffi::DSA_free(self.0);
+ }
+ }
+}
+
+pub struct DSA(*mut ffi::DSA);
+
+impl Drop for DSA {
+ fn drop(&mut self) {
+ unsafe {
+ ffi::DSA_free(self.0);
+ }
+ }
+}
+
+impl DSA {
+ pub unsafe fn from_ptr(dsa: *mut ffi::DSA) -> DSA {
+ DSA(dsa)
+ }
+
+ /// Generate a DSA key pair
+ /// For more complicated key generation scenarios see the `DSAParams` type
+ pub fn generate(size: u32) -> Result<DSA, ErrorStack> {
+ let params = try!(DSAParams::with_size(size));
+ params.generate()
+ }
+
+ /// Reads a DSA private key from PEM formatted data.
+ pub fn private_key_from_pem(buf: &[u8]) -> Result<DSA, ErrorStack> {
+ ffi::init();
+ let mem_bio = try!(MemBioSlice::new(buf));
+
+ unsafe {
+ let dsa = try_ssl_null!(ffi::PEM_read_bio_DSAPrivateKey(mem_bio.as_ptr(),
+ ptr::null_mut(),
+ None,
+ ptr::null_mut()));
+ let dsa = DSA(dsa);
+ assert!(dsa.has_private_key());
+ Ok(dsa)
+ }
+ }
+
+ /// Read a private key from PEM supplying a password callback to be invoked if the private key
+ /// is encrypted.
+ ///
+ /// The callback will be passed the password buffer and should return the number of characters
+ /// placed into the buffer.
+ pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<DSA, ErrorStack>
+ where F: FnOnce(&mut [c_char]) -> usize
+ {
+ ffi::init();
+ let mut cb = CallbackState::new(pass_cb);
+ let mem_bio = try!(MemBioSlice::new(buf));
+
+ unsafe {
+ let cb_ptr = &mut cb as *mut _ as *mut c_void;
+ let dsa = try_ssl_null!(ffi::PEM_read_bio_DSAPrivateKey(mem_bio.as_ptr(),
+ ptr::null_mut(),
+ Some(invoke_passwd_cb::<F>),
+ cb_ptr));
+ let dsa = DSA(dsa);
+ assert!(dsa.has_private_key());
+ Ok(dsa)
+ }
+ }
+
+ /// Writes an DSA private key as unencrypted PEM formatted data
+ pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack>
+ {
+ assert!(self.has_private_key());
+ let mem_bio = try!(MemBio::new());
+
+ unsafe {
+ try_ssl!(ffi::PEM_write_bio_DSAPrivateKey(mem_bio.as_ptr(), self.0,
+ ptr::null(), ptr::null_mut(), 0,
+ None, ptr::null_mut()))
+ };
+
+ Ok(mem_bio.get_buf().to_owned())
+ }
+
+ /// Reads an DSA public key from PEM formatted data.
+ pub fn public_key_from_pem(buf: &[u8]) -> Result<DSA, ErrorStack>
+ {
+ ffi::init();
+
+ let mem_bio = try!(MemBioSlice::new(buf));
+ unsafe {
+ let dsa = try_ssl_null!(ffi::PEM_read_bio_DSA_PUBKEY(mem_bio.as_ptr(),
+ ptr::null_mut(),
+ None,
+ ptr::null_mut()));
+ Ok(DSA(dsa))
+ }
+ }
+
+ /// Writes an DSA public key as PEM formatted data
+ pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
+ let mem_bio = try!(MemBio::new());
+ unsafe { try_ssl!(ffi::PEM_write_bio_DSA_PUBKEY(mem_bio.as_ptr(), self.0)) };
+ Ok(mem_bio.get_buf().to_owned())
+ }
+
+ pub fn size(&self) -> Option<u32> {
+ if self.q().is_some() {
+ unsafe { Some(ffi::DSA_size(self.0) as u32) }
+ } else {
+ None
+ }
+ }
+
+ pub fn sign(&self, hash: hash::Type, message: &[u8]) -> Result<Vec<u8>, ErrorStack> {
+ let k_len = self.size().expect("DSA missing a q") as c_uint;
+ let mut sig = vec![0; k_len as usize];
+ let mut sig_len = k_len;
+ assert!(self.has_private_key());
+
+ unsafe {
+ try_ssl!(ffi::DSA_sign(hash.as_nid() as c_int,
+ message.as_ptr(),
+ message.len() as c_int,
+ sig.as_mut_ptr(),
+ &mut sig_len,
+ self.0));
+ sig.set_len(sig_len as usize);
+ sig.shrink_to_fit();
+ Ok(sig)
+ }
+ }
+
+ pub fn verify(&self, hash: hash::Type, message: &[u8], sig: &[u8]) -> Result<bool, ErrorStack> {
+ unsafe {
+ let result = ffi::DSA_verify(hash.as_nid() as c_int,
+ message.as_ptr(),
+ message.len() as c_int,
+ sig.as_ptr(),
+ sig.len() as c_int,
+ self.0);
+
+ try_ssl_if!(result == -1);
+ Ok(result == 1)
+ }
+ }
+
+ pub fn as_ptr(&self) -> *mut ffi::DSA {
+ self.0
+ }
+
+ pub fn p<'a>(&'a self) -> Option<BigNumRef<'a>> {
+ unsafe {
+ let p = (*self.0).p;
+ if p.is_null() {
+ None
+ } else {
+ Some(BigNumRef::from_ptr((*self.0).p))
+ }
+ }
+ }
+
+ pub fn q<'a>(&'a self) -> Option<BigNumRef<'a>> {
+ unsafe {
+ let q = (*self.0).q;
+ if q.is_null() {
+ None
+ } else {
+ Some(BigNumRef::from_ptr((*self.0).q))
+ }
+ }
+ }
+
+ pub fn g<'a>(&'a self) -> Option<BigNumRef<'a>> {
+ unsafe {
+ let g = (*self.0).g;
+ if g.is_null() {
+ None
+ } else {
+ Some(BigNumRef::from_ptr((*self.0).g))
+ }
+ }
+ }
+
+ pub fn has_public_key(&self) -> bool {
+ unsafe { !(*self.0).pub_key.is_null() }
+ }
+
+ pub fn has_private_key(&self) -> bool {
+ unsafe { !(*self.0).priv_key.is_null() }
+ }
+}
+
+impl fmt::Debug for DSA {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "DSA")
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use std::io::Write;
+ use libc::c_char;
+
+ use super::*;
+ use crypto::hash::*;
+
+ #[test]
+ pub fn test_generate() {
+ let key = DSA::generate(1024).unwrap();
+
+ key.public_key_to_pem().unwrap();
+ key.private_key_to_pem().unwrap();
+
+ let input: Vec<u8> = (0..25).cycle().take(1024).collect();
+
+ let digest = {
+ let mut sha = Hasher::new(Type::SHA1).unwrap();
+ sha.write_all(&input).unwrap();
+ sha.finish().unwrap()
+ };
+
+ let sig = key.sign(Type::SHA1, &digest).unwrap();
+ let verified = key.verify(Type::SHA1, &digest, &sig).unwrap();
+ assert!(verified);
+ }
+
+ #[test]
+ pub fn test_sign_verify() {
+ let input: Vec<u8> = (0..25).cycle().take(1024).collect();
+
+ let private_key = {
+ let key = include_bytes!("../../test/dsa.pem");
+ DSA::private_key_from_pem(key).unwrap()
+ };
+
+ let public_key = {
+ let key = include_bytes!("../../test/dsa.pem.pub");
+ DSA::public_key_from_pem(key).unwrap()
+ };
+
+ let digest = {
+ let mut sha = Hasher::new(Type::SHA1).unwrap();
+ sha.write_all(&input).unwrap();
+ sha.finish().unwrap()
+ };
+
+ let sig = private_key.sign(Type::SHA1, &digest).unwrap();
+ let verified = public_key.verify(Type::SHA1, &digest, &sig).unwrap();
+ assert!(verified);
+ }
+
+ #[test]
+ pub fn test_sign_verify_fail() {
+ let input: Vec<u8> = (0..25).cycle().take(128).collect();
+ let private_key = {
+ let key = include_bytes!("../../test/dsa.pem");
+ DSA::private_key_from_pem(key).unwrap()
+ };
+
+ let public_key = {
+ let key = include_bytes!("../../test/dsa.pem.pub");
+ DSA::public_key_from_pem(key).unwrap()
+ };
+
+ let digest = {
+ let mut sha = Hasher::new(Type::SHA1).unwrap();
+ sha.write_all(&input).unwrap();
+ sha.finish().unwrap()
+ };
+
+ let mut sig = private_key.sign(Type::SHA1, &digest).unwrap();
+ // tamper with the sig this should cause a failure
+ let len = sig.len();
+ sig[len / 2] = 0;
+ sig[len - 1] = 0;
+ if let Ok(true) = public_key.verify(Type::SHA1, &digest, &sig) {
+ panic!("Tampered with signatures should not verify!");
+ }
+ }
+
+ #[test]
+ pub fn test_password() {
+ let mut password_queried = false;
+ let key = include_bytes!("../../test/dsa-encrypted.pem");
+ DSA::private_key_from_pem_cb(key, |password| {
+ password_queried = true;
+ password[0] = b'm' as c_char;
+ password[1] = b'y' as c_char;
+ password[2] = b'p' as c_char;
+ password[3] = b'a' as c_char;
+ password[4] = b's' as c_char;
+ password[5] = b's' as c_char;
+ 6
+ }).unwrap();
+
+ assert!(password_queried);
+ }
+}
diff --git a/openssl/src/crypto/hash.rs b/openssl/src/crypto/hash.rs
index 69d3a350..207a55f5 100644
--- a/openssl/src/crypto/hash.rs
+++ b/openssl/src/crypto/hash.rs
@@ -1,10 +1,12 @@
use libc::c_uint;
-use std::iter::repeat;
use std::io::prelude::*;
use std::io;
+use std::ptr;
+use std::cmp;
use ffi;
-use crypto::HashTypeInternals;
+use HashTypeInternals;
+use error::ErrorStack;
use nid::Nid;
/// Message digest (hash) type.
@@ -31,26 +33,8 @@ impl HashTypeInternals for Type {
Type::RIPEMD160 => Nid::RIPEMD160,
}
}
-}
-impl Type {
- /// Returns the length of the message digest.
- #[inline]
- pub fn md_len(&self) -> usize {
- match *self {
- Type::MD5 => 16,
- Type::SHA1 => 20,
- Type::SHA224 => 28,
- Type::SHA256 => 32,
- Type::SHA384 => 48,
- Type::SHA512 => 64,
- Type::RIPEMD160 => 20,
- }
- }
-
- /// Internal interface subject to removal.
- #[inline]
- pub fn evp_md(&self) -> *const ffi::EVP_MD {
+ fn evp_md(&self) -> *const ffi::EVP_MD {
unsafe {
match *self {
Type::MD5 => ffi::EVP_md5(),
@@ -84,21 +68,20 @@ use self::State::*;
/// use openssl::crypto::hash::{hash, Type};
/// let data = b"\x42\xF4\x97\xE0";
/// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
-/// let res = hash(Type::MD5, data);
+/// let res = hash(Type::MD5, data).unwrap();
/// assert_eq!(res, spec);
/// ```
///
/// Use the `Write` trait to supply the input in chunks.
///
/// ```
-/// use std::io::prelude::*;
/// use openssl::crypto::hash::{Hasher, Type};
/// let data = [b"\x42\xF4", b"\x97\xE0"];
/// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
-/// let mut h = Hasher::new(Type::MD5);
-/// h.write_all(data[0]);
-/// h.write_all(data[1]);
-/// let res = h.finish();
+/// let mut h = Hasher::new(Type::MD5).unwrap();
+/// h.update(data[0]).unwrap();
+/// h.update(data[1]).unwrap();
+/// let res = h.finish().unwrap();
/// assert_eq!(res, spec);
/// ```
///
@@ -116,14 +99,10 @@ pub struct Hasher {
impl Hasher {
/// Creates a new `Hasher` with the specified hash type.
- pub fn new(ty: Type) -> Hasher {
+ pub fn new(ty: Type) -> Result<Hasher, ErrorStack> {
ffi::init();
- let ctx = unsafe {
- let r = ffi::EVP_MD_CTX_create();
- assert!(!r.is_null());
- r
- };
+ let ctx = unsafe { try_ssl_null!(ffi::EVP_MD_CTX_create()) };
let md = ty.evp_md();
let mut h = Hasher {
@@ -132,67 +111,60 @@ impl Hasher {
type_: ty,
state: Finalized,
};
- h.init();
- h
+ try!(h.init());
+ Ok(h)
}
- #[inline]
- fn init(&mut self) {
+ fn init(&mut self) -> Result<(), ErrorStack> {
match self.state {
- Reset => return,
+ Reset => return Ok(()),
Updated => {
- self.finalize();
+ try!(self.finish());
}
Finalized => (),
}
- unsafe {
- let r = ffi::EVP_DigestInit_ex(self.ctx, self.md, 0 as *const _);
- assert_eq!(r, 1);
- }
+ unsafe { try_ssl!(ffi::EVP_DigestInit_ex(self.ctx, self.md, 0 as *const _)); }
self.state = Reset;
+ Ok(())
}
- #[inline]
- fn update(&mut self, data: &[u8]) {
+ /// Feeds data into the hasher.
+ pub fn update(&mut self, mut data: &[u8]) -> Result<(), ErrorStack> {
if self.state == Finalized {
- self.init();
+ try!(self.init());
}
- unsafe {
- let r = ffi::EVP_DigestUpdate(self.ctx, data.as_ptr(), data.len() as c_uint);
- assert_eq!(r, 1);
+ while !data.is_empty() {
+ let len = cmp::min(data.len(), c_uint::max_value() as usize);
+ unsafe {
+ try_ssl!(ffi::EVP_DigestUpdate(self.ctx, data.as_ptr(), len as c_uint));
+ }
+ data = &data[len..];
}
self.state = Updated;
+ Ok(())
}
- #[inline]
- fn finalize(&mut self) -> Vec<u8> {
+ /// Returns the hash of the data written since creation or
+ /// the last `finish` and resets the hasher.
+ pub fn finish(&mut self) -> Result<Vec<u8>, ErrorStack> {
if self.state == Finalized {
- self.init();
+ try!(self.init());
}
- let md_len = self.type_.md_len();
- let mut res: Vec<u8> = repeat(0).take(md_len).collect();
unsafe {
- let mut len = 0;
- let r = ffi::EVP_DigestFinal_ex(self.ctx, res.as_mut_ptr(), &mut len);
+ let mut len = ffi::EVP_MAX_MD_SIZE;
+ let mut res = vec![0; len as usize];
+ try_ssl!(ffi::EVP_DigestFinal_ex(self.ctx, res.as_mut_ptr(), &mut len));
+ res.truncate(len as usize);
self.state = Finalized;
- assert_eq!(len as usize, md_len);
- assert_eq!(r, 1);
+ Ok(res)
}
- res
- }
-
- /// Returns the hash of the data written since creation or
- /// the last `finish` and resets the hasher.
- #[inline]
- pub fn finish(&mut self) -> Vec<u8> {
- self.finalize()
}
}
impl Write for Hasher {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- self.update(buf);
+ try!(self.update(buf));
Ok(buf.len())
}
@@ -223,9 +195,7 @@ impl Drop for Hasher {
fn drop(&mut self) {
unsafe {
if self.state != Finalized {
- let mut buf: Vec<u8> = repeat(0).take(self.type_.md_len()).collect();
- let mut len = 0;
- ffi::EVP_DigestFinal_ex(self.ctx, buf.as_mut_ptr(), &mut len);
+ drop(self.finish());
}
ffi::EVP_MD_CTX_destroy(self.ctx);
}
@@ -233,9 +203,9 @@ impl Drop for Hasher {
}
/// Computes the hash of the `data` with the hash `t`.
-pub fn hash(t: Type, data: &[u8]) -> Vec<u8> {
- let mut h = Hasher::new(t);
- let _ = h.write_all(data);
+pub fn hash(t: Type, data: &[u8]) -> Result<Vec<u8>, ErrorStack> {
+ let mut h = try!(Hasher::new(t));
+ try!(h.update(data));
h.finish()
}
@@ -246,13 +216,13 @@ mod tests {
use std::io::prelude::*;
fn hash_test(hashtype: Type, hashtest: &(&str, &str)) {
- let res = hash(hashtype, &*hashtest.0.from_hex().unwrap());
+ let res = hash(hashtype, &*hashtest.0.from_hex().unwrap()).unwrap();
assert_eq!(res.to_hex(), hashtest.1);
}
fn hash_recycle_test(h: &mut Hasher, hashtest: &(&str, &str)) {
- let _ = h.write_all(&*hashtest.0.from_hex().unwrap());
- let res = h.finish();
+ let _ = h.write_all(&*hashtest.0.from_hex().unwrap()).unwrap();
+ let res = h.finish().unwrap();
assert_eq!(res.to_hex(), hashtest.1);
}
@@ -294,7 +264,7 @@ mod tests {
#[test]
fn test_md5_recycle() {
- let mut h = Hasher::new(Type::MD5);
+ let mut h = Hasher::new(Type::MD5).unwrap();
for test in md5_tests.iter() {
hash_recycle_test(&mut h, test);
}
@@ -302,11 +272,11 @@ mod tests {
#[test]
fn test_finish_twice() {
- let mut h = Hasher::new(Type::MD5);
- let _ = h.write_all(&*md5_tests[6].0.from_hex().unwrap());
- let _ = h.finish();
- let res = h.finish();
- let null = hash(Type::MD5, &[]);
+ let mut h = Hasher::new(Type::MD5).unwrap();
+ h.write_all(&*md5_tests[6].0.from_hex().unwrap()).unwrap();
+ h.finish().unwrap();
+ let res = h.finish().unwrap();
+ let null = hash(Type::MD5, &[]).unwrap();
assert_eq!(res, null);
}
@@ -316,26 +286,26 @@ mod tests {
let inp = md5_tests[i].0.from_hex().unwrap();
assert!(inp.len() > 2);
let p = inp.len() / 2;
- let h0 = Hasher::new(Type::MD5);
+ let h0 = Hasher::new(Type::MD5).unwrap();
println!("Clone a new hasher");
let mut h1 = h0.clone();
- let _ = h1.write_all(&inp[..p]);
+ h1.write_all(&inp[..p]).unwrap();
{
println!("Clone an updated hasher");
let mut h2 = h1.clone();
- let _ = h2.write_all(&inp[p..]);
- let res = h2.finish();
+ h2.write_all(&inp[p..]).unwrap();
+ let res = h2.finish().unwrap();
assert_eq!(res.to_hex(), md5_tests[i].1);
}
- let _ = h1.write_all(&inp[p..]);
- let res = h1.finish();
+ h1.write_all(&inp[p..]).unwrap();
+ let res = h1.finish().unwrap();
assert_eq!(res.to_hex(), md5_tests[i].1);
println!("Clone a finished hasher");
let mut h3 = h1.clone();
- let _ = h3.write_all(&*md5_tests[i + 1].0.from_hex().unwrap());
- let res = h3.finish();
+ h3.write_all(&*md5_tests[i + 1].0.from_hex().unwrap()).unwrap();
+ let res = h3.finish().unwrap();
assert_eq!(res.to_hex(), md5_tests[i + 1].1);
}
diff --git a/openssl/src/crypto/hmac.rs b/openssl/src/crypto/hmac.rs
index 143c7b75..857be339 100644
--- a/openssl/src/crypto/hmac.rs
+++ b/openssl/src/crypto/hmac.rs
@@ -14,13 +14,15 @@
//
use libc::{c_int, c_uint};
-use std::iter::repeat;
use std::io;
use std::io::prelude::*;
+use std::cmp;
+use ffi;
+use HashTypeInternals;
use crypto::hash::Type;
-use ffi;
-use ffi_extras;
+use error::ErrorStack;
+use c_helpers;
#[derive(PartialEq, Copy, Clone)]
enum State {
@@ -33,6 +35,8 @@ use self::State::*;
/// Provides HMAC computation.
///
+/// Requires the `hmac` feature.
+///
/// # Examples
///
/// Calculate a HMAC in one go.
@@ -43,34 +47,32 @@ use self::State::*;
/// let key = b"Jefe";
/// let data = b"what do ya want for nothing?";
/// let spec = b"\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7\x38";
-/// let res = hmac(Type::MD5, key, data);
+/// let res = hmac(Type::MD5, key, data).unwrap();
/// assert_eq!(res, spec);
/// ```
///
/// Use the `Write` trait to supply the input in chunks.
///
/// ```
-/// use std::io::prelude::*;
/// use openssl::crypto::hash::Type;
/// use openssl::crypto::hmac::HMAC;
/// let key = b"Jefe";
/// let data: &[&[u8]] = &[b"what do ya ", b"want for nothing?"];
/// let spec = b"\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7\x38";
-/// let mut h = HMAC::new(Type::MD5, &*key);
-/// h.write_all(data[0]);
-/// h.write_all(data[1]);
-/// let res = h.finish();
+/// let mut h = HMAC::new(Type::MD5, &*key).unwrap();
+/// h.update(data[0]).unwrap();
+/// h.update(data[1]).unwrap();
+/// let res = h.finish().unwrap();
/// assert_eq!(res, spec);
/// ```
pub struct HMAC {
ctx: ffi::HMAC_CTX,
- type_: Type,
state: State,
}
impl HMAC {
/// Creates a new `HMAC` with the specified hash type using the `key`.
- pub fn new(ty: Type, key: &[u8]) -> HMAC {
+ pub fn new(ty: Type, key: &[u8]) -> Result<HMAC, ErrorStack> {
ffi::init();
let ctx = unsafe {
@@ -82,89 +84,81 @@ impl HMAC {
let mut h = HMAC {
ctx: ctx,
- type_: ty,
state: Finalized,
};
- h.init_once(md, key);
- h
+ try!(h.init_once(md, key));
+ Ok(h)
}
- #[inline]
- fn init_once(&mut self, md: *const ffi::EVP_MD, key: &[u8]) {
+ fn init_once(&mut self, md: *const ffi::EVP_MD, key: &[u8]) -> Result<(), ErrorStack> {
unsafe {
- let r = ffi_extras::HMAC_Init_ex(&mut self.ctx,
- key.as_ptr(),
- key.len() as c_int,
- md,
- 0 as *const _);
- assert_eq!(r, 1);
+ try_ssl!(c_helpers::rust_HMAC_Init_ex(&mut self.ctx,
+ key.as_ptr() as *const _,
+ key.len() as c_int,
+ md,
+ 0 as *mut _));
}
self.state = Reset;
+ Ok(())
}
- #[inline]
- fn init(&mut self) {
+ fn init(&mut self) -> Result<(), ErrorStack> {
match self.state {
- Reset => return,
+ Reset => return Ok(()),
Updated => {
- self.finalize();
+ try!(self.finish());
}
Finalized => (),
}
// If the key and/or md is not supplied it's reused from the last time
// avoiding redundant initializations
unsafe {
- let r = ffi_extras::HMAC_Init_ex(&mut self.ctx,
- 0 as *const _,
- 0,
- 0 as *const _,
- 0 as *const _);
- assert_eq!(r, 1);
+ try_ssl!(c_helpers::rust_HMAC_Init_ex(&mut self.ctx,
+ 0 as *const _,
+ 0,
+ 0 as *const _,
+ 0 as *mut _));
}
self.state = Reset;
+ Ok(())
}
- #[inline]
- fn update(&mut self, data: &[u8]) {
+ pub fn update(&mut self, mut data: &[u8]) -> Result<(), ErrorStack> {
if self.state == Finalized {
- self.init();
+ try!(self.init());
}
- unsafe {
- let r = ffi_extras::HMAC_Update(&mut self.ctx, data.as_ptr(), data.len() as c_uint);
- assert_eq!(r, 1);
+ while !data.is_empty() {
+ let len = cmp::min(data.len(), c_uint::max_value() as usize);
+ unsafe {
+ try_ssl!(c_helpers::rust_HMAC_Update(&mut self.ctx, data.as_ptr(), len as c_uint));
+ }
+ data = &data[len..];
}
self.state = Updated;
+ Ok(())
}
- #[inline]
- fn finalize(&mut self) -> Vec<u8> {
+ /// Returns the hash of the data written since creation or
+ /// the last `finish` and resets the hasher.
+ pub fn finish(&mut self) -> Result<Vec<u8>, ErrorStack> {
if self.state == Finalized {
- self.init();
+ try!(self.init());
}
- let md_len = self.type_.md_len();
- let mut res: Vec<u8> = repeat(0).take(md_len).collect();
unsafe {
- let mut len = 0;
- let r = ffi_extras::HMAC_Final(&mut self.ctx, res.as_mut_ptr(), &mut len);
+ let mut len = ffi::EVP_MAX_MD_SIZE;
+ let mut res = vec![0; len as usize];
+ try_ssl!(c_helpers::rust_HMAC_Final(&mut self.ctx, res.as_mut_ptr(), &mut len));
+ res.truncate(len as usize);
self.state = Finalized;
- assert_eq!(len as usize, md_len);
- assert_eq!(r, 1);
+ Ok(res)
}
- res
- }
-
- /// Returns the hash of the data written since creation or
- /// the last `finish` and resets the hasher.
- #[inline]
- pub fn finish(&mut self) -> Vec<u8> {
- self.finalize()
}
}
impl Write for HMAC {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- self.update(buf);
+ try!(self.update(buf));
Ok(buf.len())
}
@@ -173,17 +167,18 @@ impl Write for HMAC {
}
}
+#[cfg(feature = "hmac_clone")]
impl Clone for HMAC {
+ /// Requires the `hmac_clone` feature.
fn clone(&self) -> HMAC {
let mut ctx: ffi::HMAC_CTX;
unsafe {
ctx = ::std::mem::uninitialized();
- let r = ffi_extras::HMAC_CTX_copy(&mut ctx, &self.ctx);
+ let r = ffi::HMAC_CTX_copy(&mut ctx, &self.ctx);
assert_eq!(r, 1);
}
HMAC {
ctx: ctx,
- type_: self.type_,
state: self.state,
}
}
@@ -193,9 +188,7 @@ impl Drop for HMAC {
fn drop(&mut self) {
unsafe {
if self.state != Finalized {
- let mut buf: Vec<u8> = repeat(0).take(self.type_.md_len()).collect();
- let mut len = 0;
- ffi_extras::HMAC_Final(&mut self.ctx, buf.as_mut_ptr(), &mut len);
+ drop(self.finish());
}
ffi::HMAC_CTX_cleanup(&mut self.ctx);
}
@@ -203,9 +196,9 @@ impl Drop for HMAC {
}
/// Computes the HMAC of the `data` with the hash `t` and `key`.
-pub fn hmac(t: Type, key: &[u8], data: &[u8]) -> Vec<u8> {
- let mut h = HMAC::new(t, key);
- let _ = h.write_all(data);
+pub fn hmac(t: Type, key: &[u8], data: &[u8]) -> Result<Vec<u8>, ErrorStack> {
+ let mut h = try!(HMAC::new(t, key));
+ try!(h.update(data));
h.finish()
}
@@ -220,14 +213,14 @@ mod tests {
fn test_hmac(ty: Type, tests: &[(Vec<u8>, Vec<u8>, Vec<u8>)]) {
for &(ref key, ref data, ref res) in tests.iter() {
- assert_eq!(hmac(ty, &**key, &**data), *res);
+ assert_eq!(hmac(ty, &**key, &**data).unwrap(), *res);
}
}
fn test_hmac_recycle(h: &mut HMAC, test: &(Vec<u8>, Vec<u8>, Vec<u8>)) {
let &(_, ref data, ref res) = test;
- let _ = h.write_all(&**data);
- assert_eq!(h.finish(), *res);
+ h.write_all(&**data).unwrap();
+ assert_eq!(h.finish().unwrap(), *res);
}
#[test]
@@ -273,7 +266,7 @@ mod tests {
.to_vec(),
"6f630fad67cda0ee1fb1f562db3aa53e".from_hex().unwrap())];
- let mut h = HMAC::new(MD5, &*tests[0].0);
+ let mut h = HMAC::new(MD5, &*tests[0].0).unwrap();
for i in 0..100usize {
let test = &tests[i % 2];
test_hmac_recycle(&mut h, test);
@@ -287,15 +280,16 @@ mod tests {
b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(),
"6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd".from_hex().unwrap());
- let mut h = HMAC::new(Type::MD5, &*test.0);
- let _ = h.write_all(&*test.1);
- let _ = h.finish();
- let res = h.finish();
- let null = hmac(Type::MD5, &*test.0, &[]);
+ let mut h = HMAC::new(Type::MD5, &*test.0).unwrap();
+ h.write_all(&*test.1).unwrap();
+ h.finish().unwrap();
+ let res = h.finish().unwrap();
+ let null = hmac(Type::MD5, &*test.0, &[]).unwrap();
assert_eq!(res, null);
}
#[test]
+ #[cfg(feature = "hmac_clone")]
fn test_clone() {
let tests: [(Vec<u8>, Vec<u8>, Vec<u8>); 2] =
[(repeat(0xaa_u8).take(80).collect(),
@@ -307,26 +301,26 @@ mod tests {
.to_vec(),
"6f630fad67cda0ee1fb1f562db3aa53e".from_hex().unwrap())];
let p = tests[0].0.len() / 2;
- let h0 = HMAC::new(Type::MD5, &*tests[0].0);
+ let h0 = HMAC::new(Type::MD5, &*tests[0].0).unwrap();
println!("Clone a new hmac");
let mut h1 = h0.clone();
- let _ = h1.write_all(&tests[0].1[..p]);
+ h1.write_all(&tests[0].1[..p]).unwrap();
{
println!("Clone an updated hmac");
let mut h2 = h1.clone();
- let _ = h2.write_all(&tests[0].1[p..]);
- let res = h2.finish();
+ h2.write_all(&tests[0].1[p..]).unwrap();
+ let res = h2.finish().unwrap();
assert_eq!(res, tests[0].2);
}
- let _ = h1.write_all(&tests[0].1[p..]);
- let res = h1.finish();
+ h1.write_all(&tests[0].1[p..]).unwrap();
+ let res = h1.finish().unwrap();
assert_eq!(res, tests[0].2);
println!("Clone a finished hmac");
let mut h3 = h1.clone();
- let _ = h3.write_all(&*tests[1].1);
- let res = h3.finish();
+ h3.write_all(&*tests[1].1).unwrap();
+ let res = h3.finish().unwrap();
assert_eq!(res, tests[1].2);
}
@@ -373,7 +367,7 @@ mod tests {
.to_vec(),
"e8e99d0f45237d786d6bbaa7965c7808bbff1a91".from_hex().unwrap())];
- let mut h = HMAC::new(SHA1, &*tests[0].0);
+ let mut h = HMAC::new(SHA1, &*tests[0].0).unwrap();
for i in 0..100usize {
let test = &tests[i % 2];
test_hmac_recycle(&mut h, test);
@@ -399,11 +393,11 @@ mod tests {
.to_vec())];
for (&(ref key, ref data), res) in tests.iter().zip(results.iter()) {
- assert_eq!(hmac(ty, &**key, &**data), *res);
+ assert_eq!(hmac(ty, &**key, &**data).unwrap(), *res);
}
// recycle test
- let mut h = HMAC::new(ty, &*tests[5].0);
+ let mut h = HMAC::new(ty, &*tests[5].0).unwrap();
for i in 0..100usize {
let test = &tests[4 + i % 2];
let tup = (test.0.clone(), test.1.clone(), results[4 + i % 2].clone());
diff --git a/openssl/src/crypto/mod.rs b/openssl/src/crypto/mod.rs
index 95b27022..93aba9eb 100644
--- a/openssl/src/crypto/mod.rs
+++ b/openssl/src/crypto/mod.rs
@@ -14,9 +14,8 @@
// limitations under the License.
//
-use nid::Nid;
-
pub mod hash;
+#[cfg(feature = "hmac")]
pub mod hmac;
pub mod pkcs5;
pub mod pkey;
@@ -24,9 +23,5 @@ pub mod rand;
pub mod symm;
pub mod memcmp;
pub mod rsa;
-
-mod symm_internal;
-
-trait HashTypeInternals {
- fn as_nid(&self) -> Nid;
-}
+pub mod dsa;
+mod util;
diff --git a/openssl/src/crypto/pkcs5.rs b/openssl/src/crypto/pkcs5.rs
index 0ba005cc..ef84fbe1 100644
--- a/openssl/src/crypto/pkcs5.rs
+++ b/openssl/src/crypto/pkcs5.rs
@@ -1,10 +1,11 @@
use libc::c_int;
-use std::ptr::null;
+use std::ptr;
+use ffi;
-use crypto::symm_internal::evpc;
+use HashTypeInternals;
use crypto::hash;
use crypto::symm;
-use ffi;
+use error::ErrorStack;
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct KeyIvPair {
@@ -16,125 +17,102 @@ pub struct KeyIvPair {
///
/// 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
+/// 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
+/// 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 {
-
+ -> Result<KeyIvPair, ErrorStack> {
unsafe {
-
let salt_ptr = match salt {
Some(salt) => {
assert_eq!(salt.len(), ffi::PKCS5_SALT_LEN as usize);
salt.as_ptr()
}
- None => null(),
+ None => ptr::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 typ = typ.as_ptr();
+ let message_digest_type = message_digest_type.evp_md();
+
+ let len = ffi::EVP_BytesToKey(typ,
+ message_digest_type,
+ salt_ptr,
+ data.as_ptr(),
+ data.len() as c_int,
+ count as c_int,
+ ptr::null_mut(),
+ ptr::null_mut());
+ if len == 0 {
+ return Err(ErrorStack::get());
+ }
+ let mut key = vec![0; len as usize];
+ let mut iv = vec![0; len 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);
+ try_ssl!(ffi::EVP_BytesToKey(typ,
+ message_digest_type,
+ salt_ptr,
+ data.as_ptr(),
+ data.len() as c_int,
+ count as c_int,
+ key.as_mut_ptr(),
+ iv.as_mut_ptr()));
- KeyIvPair { key: key, iv: iv }
+ Ok(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> {
+pub fn pbkdf2_hmac_sha1(pass: &[u8],
+ salt: &[u8],
+ iter: usize,
+ keylen: usize)
+ -> Result<Vec<u8>, ErrorStack> {
unsafe {
- assert!(iter >= 1);
- assert!(keylen >= 1);
-
- let mut out = Vec::with_capacity(keylen);
+ let mut out = vec![0; keylen];
ffi::init();
- let r = ffi::PKCS5_PBKDF2_HMAC_SHA1(pass.as_ptr(),
- pass.len() as c_int,
- salt.as_ptr(),
- salt.len() as c_int,
- iter as c_int,
- keylen as c_int,
- out.as_mut_ptr());
-
- if r != 1 {
- panic!();
- }
-
- out.set_len(keylen);
-
- out
+ try_ssl!(ffi::PKCS5_PBKDF2_HMAC_SHA1(pass.as_ptr(),
+ pass.len() as c_int,
+ salt.as_ptr(),
+ salt.len() as c_int,
+ iter as c_int,
+ keylen as c_int,
+ out.as_mut_ptr()));
+ Ok(out)
}
}
-/// Derives a key from a password and salt using the PBKDF2-HMAC-SHA256 algorithm.
-#[cfg(feature = "pkcs5_pbkdf2_hmac")]
-pub fn pbkdf2_hmac_sha256(pass: &str, salt: &[u8], iter: usize, keylen: usize) -> Vec<u8> {
- pbkdf2_hmac_sha(pass, salt, iter, unsafe { ffi::EVP_sha256() }, keylen)
-}
-
-/// Derives a key from a password and salt using the PBKDF2-HMAC-SHA512 algorithm.
-#[cfg(feature = "pkcs5_pbkdf2_hmac")]
-pub fn pbkdf2_hmac_sha512(pass: &str, salt: &[u8], iter: usize, keylen: usize) -> Vec<u8> {
- pbkdf2_hmac_sha(pass, salt, iter, unsafe { ffi::EVP_sha512() }, keylen)
-}
-
/// Derives a key from a password and salt using the PBKDF2-HMAC algorithm with a digest function.
#[cfg(feature = "pkcs5_pbkdf2_hmac")]
-fn pbkdf2_hmac_sha(pass: &str,
+pub fn pbkdf2_hmac(pass: &[u8],
salt: &[u8],
iter: usize,
- digest: *const ffi::EVP_MD,
+ hash: hash::Type,
keylen: usize)
- -> Vec<u8> {
+ -> Result<Vec<u8>, ErrorStack> {
unsafe {
- assert!(iter >= 1);
- assert!(keylen >= 1);
-
- let mut out = Vec::with_capacity(keylen);
-
+ let mut out = vec![0; keylen];
ffi::init();
-
- let r = ffi::PKCS5_PBKDF2_HMAC(pass.as_ptr(),
- pass.len() as c_int,
- salt.as_ptr(),
- salt.len() as c_int,
- iter as c_int,
- digest,
- keylen as c_int,
- out.as_mut_ptr());
-
- if r != 1 {
- panic!();
- }
-
- out.set_len(keylen);
-
- out
+ try_ssl!(ffi::PKCS5_PBKDF2_HMAC(pass.as_ptr(),
+ pass.len() as c_int,
+ salt.as_ptr(),
+ salt.len() as c_int,
+ iter as c_int,
+ hash.evp_md(),
+ keylen as c_int,
+ out.as_mut_ptr()));
+ Ok(out)
}
}
@@ -147,36 +125,36 @@ mod tests {
// http://tools.ietf.org/html/draft-josefsson-pbkdf2-test-vectors-06
#[test]
fn test_pbkdf2_hmac_sha1() {
- assert_eq!(super::pbkdf2_hmac_sha1("password", "salt".as_bytes(), 1, 20),
+ assert_eq!(super::pbkdf2_hmac_sha1(b"password", b"salt", 1, 20).unwrap(),
vec![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_eq!(super::pbkdf2_hmac_sha1("password", "salt".as_bytes(), 2, 20),
+ assert_eq!(super::pbkdf2_hmac_sha1(b"password", b"salt", 2, 20).unwrap(),
vec![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_eq!(super::pbkdf2_hmac_sha1("password", "salt".as_bytes(), 4096, 20),
+ assert_eq!(super::pbkdf2_hmac_sha1(b"password", b"salt", 4096, 20).unwrap(),
vec![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_eq!(super::pbkdf2_hmac_sha1("password", "salt".as_bytes(), 16777216, 20),
+ assert_eq!(super::pbkdf2_hmac_sha1(b"password", b"salt", 16777216, 20).unwrap(),
vec![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_eq!(super::pbkdf2_hmac_sha1("passwordPASSWORDpassword",
- "saltSALTsaltSALTsaltSALTsaltSALTsalt".as_bytes(),
+ assert_eq!(super::pbkdf2_hmac_sha1(b"passwordPASSWORDpassword",
+ b"saltSALTsaltSALTsaltSALTsaltSALTsalt",
4096,
- 25),
+ 25).unwrap(),
vec![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_eq!(super::pbkdf2_hmac_sha1("pass\x00word", "sa\x00lt".as_bytes(), 4096, 16),
+ assert_eq!(super::pbkdf2_hmac_sha1(b"pass\x00word", b"sa\x00lt", 4096, 16).unwrap(),
vec![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]);
}
@@ -186,11 +164,11 @@ mod tests {
#[test]
#[cfg(feature = "pkcs5_pbkdf2_hmac")]
fn test_pbkdf2_hmac_sha256() {
- assert_eq!(super::pbkdf2_hmac_sha256("passwd", "salt".as_bytes(), 1, 16),
+ assert_eq!(super::pbkdf2_hmac(b"passwd", b"salt", 1, hash::Type::SHA256, 16).unwrap(),
vec![0x55_u8, 0xac_u8, 0x04_u8, 0x6e_u8, 0x56_u8, 0xe3_u8, 0x08_u8, 0x9f_u8,
0xec_u8, 0x16_u8, 0x91_u8, 0xc2_u8, 0x25_u8, 0x44_u8, 0xb6_u8, 0x05_u8]);
- assert_eq!(super::pbkdf2_hmac_sha256("Password", "NaCl".as_bytes(), 80000, 16),
+ assert_eq!(super::pbkdf2_hmac(b"Password", b"NaCl", 80000, hash::Type::SHA256, 16).unwrap(),
vec![0x4d_u8, 0xdc_u8, 0xd8_u8, 0xf6_u8, 0x0b_u8, 0x98_u8, 0xbe_u8, 0x21_u8,
0x83_u8, 0x0c_u8, 0xee_u8, 0x5e_u8, 0xf2_u8, 0x27_u8, 0x01_u8, 0xf9_u8]);
}
@@ -200,7 +178,7 @@ mod tests {
#[test]
#[cfg(feature = "pkcs5_pbkdf2_hmac")]
fn test_pbkdf2_hmac_sha512() {
- assert_eq!(super::pbkdf2_hmac_sha512("password", "NaCL".as_bytes(), 1, 64),
+ assert_eq!(super::pbkdf2_hmac(b"password", b"NaCL", 1, hash::Type::SHA512, 64).unwrap(),
vec![0x73_u8, 0xde_u8, 0xcf_u8, 0xa5_u8, 0x8a_u8, 0xa2_u8, 0xe8_u8, 0x4f_u8,
0x94_u8, 0x77_u8, 0x1a_u8, 0x75_u8, 0x73_u8, 0x6b_u8, 0xb8_u8, 0x8b_u8,
0xd3_u8, 0xc7_u8, 0xb3_u8, 0x82_u8, 0x70_u8, 0xcf_u8, 0xb5_u8, 0x0c_u8,
@@ -210,7 +188,7 @@ mod tests {
0x60_u8, 0x60_u8, 0xa0_u8, 0x9f_u8, 0x76_u8, 0x41_u8, 0x5e_u8, 0x9f_u8,
0x71_u8, 0xea_u8, 0x47_u8, 0xf9_u8, 0xe9_u8, 0x06_u8, 0x43_u8, 0x06_u8]);
- assert_eq!(super::pbkdf2_hmac_sha512("pass\0word", "sa\0lt".as_bytes(), 1, 64),
+ assert_eq!(super::pbkdf2_hmac(b"pass\0word", b"sa\0lt", 1, hash::Type::SHA512, 64).unwrap(),
vec![0x71_u8, 0xa0_u8, 0xec_u8, 0x84_u8, 0x2a_u8, 0xbd_u8, 0x5c_u8, 0x67_u8,
0x8b_u8, 0xcf_u8, 0xd1_u8, 0x45_u8, 0xf0_u8, 0x9d_u8, 0x83_u8, 0x52_u8,
0x2f_u8, 0x93_u8, 0x36_u8, 0x15_u8, 0x60_u8, 0x56_u8, 0x3c_u8, 0x4d_u8,
@@ -220,10 +198,11 @@ mod tests {
0xb2_u8, 0x0f_u8, 0x06_u8, 0xbc_u8, 0x53_u8, 0x5e_u8, 0x5a_u8, 0xb5_u8,
0x44_u8, 0x0d_u8, 0xf7_u8, 0xe8_u8, 0x78_u8, 0x29_u8, 0x6f_u8, 0xa7_u8]);
- assert_eq!(super::pbkdf2_hmac_sha512("passwordPASSWORDpassword",
- "salt\0\0\0".as_bytes(),
- 50,
- 64),
+ assert_eq!(super::pbkdf2_hmac(b"passwordPASSWORDpassword",
+ b"salt\0\0\0",
+ 50,
+ hash::Type::SHA512,
+ 64).unwrap(),
vec![0x01_u8, 0x68_u8, 0x71_u8, 0xa4_u8, 0xc4_u8, 0xb7_u8, 0x5f_u8, 0x96_u8,
0x85_u8, 0x7f_u8, 0xd2_u8, 0xb9_u8, 0xf8_u8, 0xca_u8, 0x28_u8, 0x02_u8,
0x3b_u8, 0x30_u8, 0xee_u8, 0x2a_u8, 0x39_u8, 0xf5_u8, 0xad_u8, 0xca_u8,
@@ -257,7 +236,7 @@ mod tests {
hash::Type::SHA1,
&data,
Some(&salt),
- 1),
+ 1).unwrap(),
super::KeyIvPair {
key: expected_key,
iv: expected_iv,
diff --git a/openssl/src/crypto/pkey.rs b/openssl/src/crypto/pkey.rs
index c4111860..a2a6f9c1 100644
--- a/openssl/src/crypto/pkey.rs
+++ b/openssl/src/crypto/pkey.rs
@@ -1,260 +1,107 @@
-use libc::{c_int, c_uint, c_ulong};
-use std::io;
-use std::io::prelude::*;
-use std::iter::repeat;
-use std::mem;
+use libc::{c_void, c_char};
use std::ptr;
-use bio::MemBio;
-
-use crypto::HashTypeInternals;
-use crypto::hash;
-use crypto::hash::Type as HashType;
+use std::mem;
use ffi;
-use ssl::error::{SslError, StreamError};
-use crypto::rsa::RSA;
-
-#[derive(Copy, Clone)]
-pub enum Parts {
- Neither,
- Public,
- Both,
-}
-
-/// Represents a role an asymmetric key might be appropriate for.
-#[derive(Copy, Clone)]
-pub enum Role {
- Encrypt,
- Decrypt,
- Sign,
- Verify,
-}
-
-/// Type of encryption padding to use.
-#[derive(Copy, Clone)]
-pub enum EncryptionPadding {
- OAEP,
- PKCS1v15,
-}
-fn openssl_padding_code(padding: EncryptionPadding) -> c_int {
- match padding {
- EncryptionPadding::OAEP => 4,
- EncryptionPadding::PKCS1v15 => 1,
- }
-}
+use bio::{MemBio, MemBioSlice};
+use crypto::rsa::RSA;
+use error::ErrorStack;
+use crypto::util::{CallbackState, invoke_passwd_cb};
-pub struct PKey {
- evp: *mut ffi::EVP_PKEY,
- parts: Parts,
-}
+pub struct PKey(*mut ffi::EVP_PKEY);
unsafe impl Send for PKey {}
unsafe impl Sync for PKey {}
/// Represents a public key, optionally with a private key attached.
impl PKey {
- pub fn new() -> PKey {
+ /// Create a new `PKey` containing an RSA key.
+ pub fn from_rsa(rsa: RSA) -> Result<PKey, ErrorStack> {
unsafe {
- ffi::init();
-
- PKey {
- evp: ffi::EVP_PKEY_new(),
- parts: Parts::Neither,
- }
+ let evp = try_ssl_null!(ffi::EVP_PKEY_new());
+ let pkey = PKey(evp);
+ try_ssl!(ffi::EVP_PKEY_assign(pkey.0, ffi::EVP_PKEY_RSA, rsa.as_ptr() as *mut _));
+ mem::forget(rsa);
+ Ok(pkey)
}
}
- pub fn from_handle(handle: *mut ffi::EVP_PKEY, parts: Parts) -> PKey {
- ffi::init();
- assert!(!handle.is_null());
-
- PKey {
- evp: handle,
- parts: parts,
- }
+ pub unsafe fn from_ptr(handle: *mut ffi::EVP_PKEY) -> PKey {
+ PKey(handle)
}
/// Reads private key from PEM, takes ownership of handle
- pub fn private_key_from_pem<R>(reader: &mut R) -> Result<PKey, SslError>
- where R: Read
- {
- let mut mem_bio = try!(MemBio::new());
- try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
-
+ pub fn private_key_from_pem(buf: &[u8]) -> Result<PKey, ErrorStack> {
+ ffi::init();
+ let mem_bio = try!(MemBioSlice::new(buf));
unsafe {
- let evp = try_ssl_null!(ffi::PEM_read_bio_PrivateKey(mem_bio.get_handle(),
+ let evp = try_ssl_null!(ffi::PEM_read_bio_PrivateKey(mem_bio.as_ptr(),
ptr::null_mut(),
None,
ptr::null_mut()));
- Ok(PKey {
- evp: evp as *mut ffi::EVP_PKEY,
- parts: Parts::Both,
- })
- }
- }
-
- /// Reads public key from PEM, takes ownership of handle
- pub fn public_key_from_pem<R>(reader: &mut R) -> Result<PKey, SslError>
- where R: Read
- {
- let mut mem_bio = try!(MemBio::new());
- try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
-
- unsafe {
- let evp = try_ssl_null!(ffi::PEM_read_bio_PUBKEY(mem_bio.get_handle(),
- ptr::null_mut(),
- None,
- ptr::null_mut()));
- Ok(PKey {
- evp: evp as *mut ffi::EVP_PKEY,
- parts: Parts::Public,
- })
- }
- }
-
- /// Reads an RSA private key from PEM, takes ownership of handle
- pub fn private_rsa_key_from_pem<R>(reader: &mut R) -> Result<PKey, SslError>
- where R: Read
- {
- let rsa = try!(RSA::private_key_from_pem(reader));
- unsafe {
- let evp = try_ssl_null!(ffi::EVP_PKEY_new());
- try_ssl!(ffi::EVP_PKEY_set1_RSA(evp, rsa.as_ptr()));
-
- Ok(PKey {
- evp: evp,
- parts: Parts::Public,
- })
+ Ok(PKey::from_ptr(evp))
}
}
- /// Reads an RSA public key from PEM, takes ownership of handle
- pub fn public_rsa_key_from_pem<R>(reader: &mut R) -> Result<PKey, SslError>
- where R: Read
+ /// Read a private key from PEM, supplying a password callback to be invoked if the private key
+ /// is encrypted.
+ ///
+ /// The callback will be passed the password buffer and should return the number of characters
+ /// placed into the buffer.
+ pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<PKey, ErrorStack>
+ where F: FnOnce(&mut [c_char]) -> usize
{
- let rsa = try!(RSA::public_key_from_pem(reader));
- unsafe {
- let evp = try_ssl_null!(ffi::EVP_PKEY_new());
- try_ssl!(ffi::EVP_PKEY_set1_RSA(evp, rsa.as_ptr()));
-
- Ok(PKey {
- evp: evp,
- parts: Parts::Public,
- })
- }
- }
-
- fn _tostr(&self, f: unsafe extern "C" fn(*mut ffi::RSA, *const *mut u8) -> c_int) -> Vec<u8> {
- unsafe {
- let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
- let len = f(rsa, ptr::null());
- if len < 0 as c_int {
- return vec![];
- }
- let mut s = repeat(0u8).take(len as usize).collect::<Vec<_>>();
-
- let r = f(rsa, &s.as_mut_ptr());
- ffi::RSA_free(rsa);
-
- s.truncate(r as usize);
- s
- }
- }
-
- fn _fromstr(&mut self,
- s: &[u8],
- f: unsafe extern "C" fn(*const *mut ffi::RSA, *const *const u8, c_uint)
- -> *mut ffi::RSA)
- -> bool {
+ ffi::init();
+ let mut cb = CallbackState::new(pass_cb);
+ let mem_bio = try!(MemBioSlice::new(buf));
unsafe {
- let rsa = ptr::null_mut();
- f(&rsa, &s.as_ptr(), s.len() as c_uint);
- if !rsa.is_null() {
- ffi::EVP_PKEY_set1_RSA(self.evp, rsa) == 1
- } else {
- false
- }
+ let evp = try_ssl_null!(ffi::PEM_read_bio_PrivateKey(mem_bio.as_ptr(),
+ ptr::null_mut(),
+ Some(invoke_passwd_cb::<F>),
+ &mut cb as *mut _ as *mut c_void));
+ Ok(PKey::from_ptr(evp))
}
}
- pub fn gen(&mut self, keysz: usize) {
+ /// Reads public key from PEM, takes ownership of handle
+ pub fn public_key_from_pem(buf: &[u8]) -> Result<PKey, ErrorStack> {
+ ffi::init();
+ let mem_bio = try!(MemBioSlice::new(buf));
unsafe {
- let rsa = ffi::RSA_generate_key(keysz as c_int,
- 65537 as c_ulong,
- ptr::null(),
- ptr::null());
-
- // XXX: 6 == NID_rsaEncryption
- ffi::EVP_PKEY_assign(self.evp, 6 as c_int, mem::transmute(rsa));
-
- self.parts = Parts::Both;
+ let evp = try_ssl_null!(ffi::PEM_read_bio_PUBKEY(mem_bio.as_ptr(),
+ ptr::null_mut(),
+ None,
+ ptr::null_mut()));
+ Ok(PKey::from_ptr(evp))
}
}
/// assign RSA key to this pkey
- pub fn set_rsa(&mut self, rsa: &RSA) {
+ pub fn set_rsa(&mut self, rsa: &RSA) -> Result<(), ErrorStack> {
unsafe {
// this needs to be a reference as the set1_RSA ups the reference count
let rsa_ptr = rsa.as_ptr();
- if ffi::EVP_PKEY_set1_RSA(self.evp, rsa_ptr) == 1 {
- if rsa.has_e() && rsa.has_n() {
- self.parts = Parts::Public;
- }
- }
+ try_ssl!(ffi::EVP_PKEY_set1_RSA(self.0, rsa_ptr));
+ Ok(())
}
}
- /// get a reference to the interal RSA key for direct access to the key components
- pub fn get_rsa(&self) -> RSA {
+ /// Get a reference to the interal RSA key for direct access to the key components
+ pub fn get_rsa(&self) -> Result<RSA, ErrorStack> {
unsafe {
- let evp_pkey: *mut ffi::EVP_PKEY = self.evp;
+ let rsa = try_ssl_null!(ffi::EVP_PKEY_get1_RSA(self.0));
// this is safe as the ffi increments a reference counter to the internal key
- RSA::from_raw(ffi::EVP_PKEY_get1_RSA(evp_pkey))
- }
- }
-
- /**
- * Returns a DER serialized form of the public key, suitable for load_pub().
- */
- pub fn save_pub(&self) -> Vec<u8> {
- self._tostr(ffi::i2d_RSA_PUBKEY)
- }
-
- /**
- * Loads a DER serialized form of the public key, as produced by save_pub().
- */
- pub fn load_pub(&mut self, s: &[u8]) {
- if self._fromstr(s, ffi::d2i_RSA_PUBKEY) {
- self.parts = Parts::Public;
- }
- }
-
- /**
- * Returns a serialized form of the public and private keys, suitable for
- * load_priv().
- */
- pub fn save_priv(&self) -> Vec<u8> {
- self._tostr(ffi::i2d_RSAPrivateKey)
- }
- /**
- * Loads a serialized form of the public and private keys, as produced by
- * save_priv().
- */
- pub fn load_priv(&mut self, s: &[u8]) {
- if self._fromstr(s, ffi::d2i_RSAPrivateKey) {
- self.parts = Parts::Both;
+ Ok(RSA::from_ptr(rsa))
}
}
/// Stores private key as a PEM
// FIXME: also add password and encryption
- pub fn write_pem<W: Write>(&self,
- writer: &mut W /* , password: Option<String> */)
- -> Result<(), SslError> {
- let mut mem_bio = try!(MemBio::new());
+ pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
+ let mem_bio = try!(MemBio::new());
unsafe {
- try_ssl!(ffi::PEM_write_bio_PrivateKey(mem_bio.get_handle(),
- self.evp,
+ try_ssl!(ffi::PEM_write_bio_PrivateKey(mem_bio.as_ptr(),
+ self.0,
ptr::null(),
ptr::null_mut(),
-1,
@@ -262,635 +109,58 @@ impl PKey {
ptr::null_mut()));
}
- let mut buf = vec![];
- try!(mem_bio.read_to_end(&mut buf).map_err(StreamError));
- writer.write_all(&buf).map_err(StreamError)
+ Ok(mem_bio.get_buf().to_owned())
}
/// Stores public key as a PEM
- pub fn write_pub_pem<W: Write>(&self,
- writer: &mut W /* , password: Option<String> */)
- -> Result<(), SslError> {
- let mut mem_bio = try!(MemBio::new());
- unsafe { try_ssl!(ffi::PEM_write_bio_PUBKEY(mem_bio.get_handle(), self.evp)) }
- let mut buf = vec![];
- try!(mem_bio.read_to_end(&mut buf).map_err(StreamError));
- writer.write_all(&buf).map_err(StreamError)
- }
-
- /**
- * Returns the size of the public key modulus.
- */
- pub fn size(&self) -> usize {
- unsafe {
- let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
- if rsa.is_null() {
- 0
- } else {
- ffi::RSA_size(rsa) as usize
- }
- }
- }
-
- /**
- * Returns whether this pkey object can perform the specified role.
- */
- pub fn can(&self, r: Role) -> bool {
- match r {
- Role::Encrypt => {
- match self.parts {
- Parts::Neither => false,
- _ => true,
- }
- }
- Role::Verify => {
- match self.parts {
- Parts::Neither => false,
- _ => true,
- }
- }
- Role::Decrypt => {
- match self.parts {
- Parts::Both => true,
- _ => false,
- }
- }
- Role::Sign => {
- match self.parts {
- Parts::Both => true,
- _ => false,
- }
- }
- }
- }
-
- /**
- * Returns the maximum amount of data that can be encrypted by an encrypt()
- * call.
- */
- pub fn max_data(&self) -> usize {
- unsafe {
- let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
- if rsa.is_null() {
- return 0;
- }
- let len = ffi::RSA_size(rsa);
-
- // 41 comes from RSA_public_encrypt(3) for OAEP
- len as usize - 41
- }
- }
-
- pub fn private_encrypt_with_padding(&self, s: &[u8], padding: EncryptionPadding) -> Vec<u8> {
- unsafe {
- let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
- if rsa.is_null() {
- panic!("Could not get RSA key for encryption");
- }
- let len = ffi::RSA_size(rsa);
-
- assert!(s.len() < self.max_data());
-
- let mut r = repeat(0u8).take(len as usize + 1).collect::<Vec<_>>();
-
- let rv = ffi::RSA_private_encrypt(s.len() as c_int,
- s.as_ptr(),
- r.as_mut_ptr(),
- rsa,
- openssl_padding_code(padding));
-
- if rv < 0 as c_int {
- // println!("{:?}", SslError::get());
- vec![]
- } else {
- r.truncate(rv as usize);
- r
- }
- }
- }
-
- pub fn public_encrypt_with_padding(&self, s: &[u8], padding: EncryptionPadding) -> Vec<u8> {
- unsafe {
- let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
- if rsa.is_null() {
- panic!("Could not get RSA key for encryption");
- }
- let len = ffi::RSA_size(rsa);
-
- assert!(s.len() < self.max_data());
-
- let mut r = repeat(0u8).take(len as usize + 1).collect::<Vec<_>>();
-
- let rv = ffi::RSA_public_encrypt(s.len() as c_int,
- s.as_ptr(),
- r.as_mut_ptr(),
- rsa,
- openssl_padding_code(padding));
-
- if rv < 0 as c_int {
- vec![]
- } else {
- r.truncate(rv as usize);
- r
- }
- }
- }
-
- pub fn private_decrypt_with_padding(&self, s: &[u8], padding: EncryptionPadding) -> Vec<u8> {
- unsafe {
- let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
- if rsa.is_null() {
- panic!("Could not get RSA key for decryption");
- }
- let len = ffi::RSA_size(rsa);
-
- assert_eq!(s.len() as c_int, ffi::RSA_size(rsa));
-
- let mut r = repeat(0u8).take(len as usize + 1).collect::<Vec<_>>();
-
- let rv = ffi::RSA_private_decrypt(s.len() as c_int,
- s.as_ptr(),
- r.as_mut_ptr(),
- rsa,
- openssl_padding_code(padding));
-
- if rv < 0 as c_int {
- vec![]
- } else {
- r.truncate(rv as usize);
- r
- }
- }
- }
-
- pub fn public_decrypt_with_padding(&self, s: &[u8], padding: EncryptionPadding) -> Vec<u8> {
- unsafe {
- let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
- if rsa.is_null() {
- panic!("Could not get RSA key for decryption");
- }
- let len = ffi::RSA_size(rsa);
-
- assert_eq!(s.len() as c_int, ffi::RSA_size(rsa));
-
- let mut r = repeat(0u8).take(len as usize + 1).collect::<Vec<_>>();
-
- let rv = ffi::RSA_public_decrypt(s.len() as c_int,
- s.as_ptr(),
- r.as_mut_ptr(),
- rsa,
- openssl_padding_code(padding));
-
- if rv < 0 as c_int {
- vec![]
- } else {
- r.truncate(rv as usize);
- r
- }
- }
- }
-
- /**
- * Encrypts data with the public key, using OAEP padding, returning the encrypted data. The
- * supplied data must not be larger than max_data().
- */
- pub fn encrypt(&self, s: &[u8]) -> Vec<u8> {
- self.public_encrypt_with_padding(s, EncryptionPadding::OAEP)
- }
-
- /**
- * Encrypts data with the public key, using provided padding, returning the encrypted data. The
- * supplied data must not be larger than max_data().
- */
- pub fn encrypt_with_padding(&self, s: &[u8], padding: EncryptionPadding) -> Vec<u8> {
- self.public_encrypt_with_padding(s, padding)
- }
-
- /**
- * Encrypts data with the public key, using OAEP padding, returning the encrypted data. The
- * supplied data must not be larger than max_data().
- */
- pub fn public_encrypt(&self, s: &[u8]) -> Vec<u8> {
- self.public_encrypt_with_padding(s, EncryptionPadding::OAEP)
- }
-
- /**
- * Decrypts data with the public key, using PKCS1v15 padding, returning the decrypted data.
- */
- pub fn public_decrypt(&self, s: &[u8]) -> Vec<u8> {
- self.public_decrypt_with_padding(s, EncryptionPadding::PKCS1v15)
- }
-
- /**
- * Decrypts data with the private key, expecting OAEP padding, returning the decrypted data.
- */
- pub fn decrypt(&self, s: &[u8]) -> Vec<u8> {
- self.private_decrypt_with_padding(s, EncryptionPadding::OAEP)
- }
-
- /**
- * Decrypts data with the private key, using provided padding, returning the encrypted data. The
- * supplied data must not be larger than max_data().
- */
- pub fn decrypt_with_padding(&self, s: &[u8], padding: EncryptionPadding) -> Vec<u8> {
- self.private_decrypt_with_padding(s, padding)
- }
-
- /**
- * Decrypts data with the private key, expecting OAEP padding, returning the decrypted data.
- */
- pub fn private_decrypt(&self, s: &[u8]) -> Vec<u8> {
- self.private_decrypt_with_padding(s, EncryptionPadding::OAEP)
- }
-
- /**
- * Encrypts data with the private key, using PKCS1v15 padding, returning the encrypted data. The
- * supplied data must not be larger than max_data().
- */
- pub fn private_encrypt(&self, s: &[u8]) -> Vec<u8> {
- self.private_encrypt_with_padding(s, EncryptionPadding::PKCS1v15)
- }
-
- /**
- * Signs data, using OpenSSL's default scheme and adding sha256 ASN.1 information to the
- * signature.
- * The bytes to sign must be the result of a sha256 hashing;
- * returns the signature.
- */
- pub fn sign(&self, s: &[u8]) -> Vec<u8> {
- self.sign_with_hash(s, HashType::SHA256)
- }
-
- /**
- * Verifies a signature s (using OpenSSL's default scheme and sha256) on the SHA256 hash of a
- * message.
- * Returns true if the signature is valid, and false otherwise.
- */
- pub fn verify(&self, h: &[u8], s: &[u8]) -> bool {
- self.verify_with_hash(h, s, HashType::SHA256)
- }
-
- /**
- * Signs data, using OpenSSL's default scheme and add ASN.1 information for the given hash type to the
- * signature.
- * The bytes to sign must be the result of this type of hashing;
- * returns the signature.
- */
- pub fn sign_with_hash(&self, s: &[u8], hash: hash::Type) -> Vec<u8> {
- unsafe {
- let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
- if rsa.is_null() {
- panic!("Could not get RSA key for signing");
- }
- let len = ffi::RSA_size(rsa);
- let mut r = repeat(0u8).take(len as usize + 1).collect::<Vec<_>>();
-
- let mut len = 0;
- let rv = ffi::RSA_sign(hash.as_nid() as c_int,
- s.as_ptr(),
- s.len() as c_uint,
- r.as_mut_ptr(),
- &mut len,
- rsa);
-
- if rv < 0 as c_int {
- vec![]
- } else {
- r.truncate(len as usize);
- r
- }
- }
- }
-
- pub fn verify_with_hash(&self, h: &[u8], s: &[u8], hash: hash::Type) -> bool {
- unsafe {
- let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
- if rsa.is_null() {
- panic!("Could not get RSA key for verification");
- }
-
- let rv = ffi::RSA_verify(hash.as_nid() as c_int,
- h.as_ptr(),
- h.len() as c_uint,
- s.as_ptr(),
- s.len() as c_uint,
- rsa);
-
- rv == 1 as c_int
- }
+ pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
+ let mem_bio = try!(MemBio::new());
+ unsafe { try_ssl!(ffi::PEM_write_bio_PUBKEY(mem_bio.as_ptr(), self.0)) }
+ Ok(mem_bio.get_buf().to_owned())
}
- pub unsafe fn get_handle(&self) -> *mut ffi::EVP_PKEY {
- return self.evp;
+ pub fn as_ptr(&self) -> *mut ffi::EVP_PKEY {
+ return self.0;
}
pub fn public_eq(&self, other: &PKey) -> bool {
- unsafe { ffi::EVP_PKEY_cmp(self.evp, other.evp) == 1 }
+ unsafe { ffi::EVP_PKEY_cmp(self.0, other.0) == 1 }
}
}
impl Drop for PKey {
fn drop(&mut self) {
unsafe {
- ffi::EVP_PKEY_free(self.evp);
- }
- }
-}
-
-impl Clone for PKey {
- fn clone(&self) -> Self {
- let mut pkey = PKey::from_handle(unsafe { ffi::EVP_PKEY_new() }, self.parts);
- // copy by encoding to DER and back
- match self.parts {
- Parts::Public => {
- pkey.load_pub(&self.save_pub()[..]);
- }
- Parts::Both => {
- pkey.load_priv(&self.save_priv()[..]);
- }
- Parts::Neither => {}
+ ffi::EVP_PKEY_free(self.0);
}
- pkey
}
}
#[cfg(test)]
mod tests {
- use std::path::Path;
- use std::fs::File;
- use crypto::hash::Type::{MD5, SHA1};
- use crypto::rsa::RSA;
-
- #[test]
- fn test_gen_pub() {
- let mut k0 = super::PKey::new();
- let mut k1 = super::PKey::new();
- k0.gen(512);
- k1.load_pub(&k0.save_pub());
- assert_eq!(k0.save_pub(), k1.save_pub());
- assert!(k0.public_eq(&k1));
- assert_eq!(k0.size(), k1.size());
- assert!(k0.can(super::Role::Encrypt));
- assert!(k0.can(super::Role::Decrypt));
- assert!(k0.can(super::Role::Verify));
- assert!(k0.can(super::Role::Sign));
- assert!(k1.can(super::Role::Encrypt));
- assert!(!k1.can(super::Role::Decrypt));
- assert!(k1.can(super::Role::Verify));
- assert!(!k1.can(super::Role::Sign));
- }
-
- #[test]
- fn test_gen_priv() {
- let mut k0 = super::PKey::new();
- let mut k1 = super::PKey::new();
- k0.gen(512);
- k1.load_priv(&k0.save_priv());
- assert_eq!(k0.save_priv(), k1.save_priv());
- assert!(k0.public_eq(&k1));
- assert_eq!(k0.size(), k1.size());
- assert!(k0.can(super::Role::Encrypt));
- assert!(k0.can(super::Role::Decrypt));
- assert!(k0.can(super::Role::Verify));
- assert!(k0.can(super::Role::Sign));
- assert!(k1.can(super::Role::Encrypt));
- assert!(k1.can(super::Role::Decrypt));
- assert!(k1.can(super::Role::Verify));
- assert!(k1.can(super::Role::Sign));
- }
-
#[test]
fn test_private_key_from_pem() {
- let key_path = Path::new("test/key.pem");
- let mut file = File::open(&key_path)
- .ok()
- .expect("Failed to open `test/key.pem`");
-
- super::PKey::private_key_from_pem(&mut file).unwrap();
+ let key = include_bytes!("../../test/key.pem");
+ super::PKey::private_key_from_pem(key).unwrap();
}
#[test]
fn test_public_key_from_pem() {
- let key_path = Path::new("test/key.pem.pub");
- let mut file = File::open(&key_path)
- .ok()
- .expect("Failed to open `test/key.pem.pub`");
-
- super::PKey::public_key_from_pem(&mut file).unwrap();
- }
-
- #[test]
- fn test_private_rsa_key_from_pem() {
- let key_path = Path::new("test/key.pem");
- let mut file = File::open(&key_path)
- .ok()
- .expect("Failed to open `test/key.pem`");
-
- super::PKey::private_rsa_key_from_pem(&mut file).unwrap();
- }
-
- #[test]
- fn test_public_rsa_key_from_pem() {
- let key_path = Path::new("test/key.pem.pub");
- let mut file = File::open(&key_path)
- .ok()
- .expect("Failed to open `test/key.pem.pub`");
-
- super::PKey::public_rsa_key_from_pem(&mut file).unwrap();
- }
-
- #[test]
- fn test_private_encrypt() {
- let mut k0 = super::PKey::new();
- let mut k1 = super::PKey::new();
- let msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8];
- k0.gen(512);
- k1.load_pub(&k0.save_pub());
- let emsg = k0.private_encrypt(&msg);
- let dmsg = k1.public_decrypt(&emsg);
- assert!(msg == dmsg);
- }
-
- #[test]
- fn test_public_encrypt() {
- let mut k0 = super::PKey::new();
- let mut k1 = super::PKey::new();
- let msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8];
- k0.gen(512);
- k1.load_pub(&k0.save_pub());
- let emsg = k1.public_encrypt(&msg);
- let dmsg = k0.private_decrypt(&emsg);
- assert!(msg == dmsg);
- }
-
- #[test]
- fn test_public_encrypt_pkcs() {
- let mut k0 = super::PKey::new();
- let mut k1 = super::PKey::new();
- let msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8];
- k0.gen(512);
- k1.load_pub(&k0.save_pub());
- let emsg = k1.public_encrypt_with_padding(&msg, super::EncryptionPadding::PKCS1v15);
- let dmsg = k0.private_decrypt_with_padding(&emsg, super::EncryptionPadding::PKCS1v15);
- assert!(msg == dmsg);
- }
-
- #[test]
- fn test_sign() {
- let mut k0 = super::PKey::new();
- let mut k1 = super::PKey::new();
- let msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8];
- k0.gen(512);
- k1.load_pub(&k0.save_pub());
- let sig = k0.sign(&msg);
- let rv = k1.verify(&msg, &sig);
- assert!(rv == true);
- }
-
- #[test]
- fn test_sign_hashes() {
- let mut k0 = super::PKey::new();
- let mut k1 = super::PKey::new();
- let msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8];
- k0.gen(512);
- 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));
- }
-
- #[test]
- fn test_eq() {
- let mut k0 = super::PKey::new();
- let mut p0 = super::PKey::new();
- let mut k1 = super::PKey::new();
- let mut p1 = super::PKey::new();
- k0.gen(512);
- k1.gen(512);
- p0.load_pub(&k0.save_pub());
- p1.load_pub(&k1.save_pub());
-
- assert!(k0.public_eq(&k0));
- assert!(k1.public_eq(&k1));
- assert!(p0.public_eq(&p0));
- assert!(p1.public_eq(&p1));
- assert!(k0.public_eq(&p0));
- assert!(k1.public_eq(&p1));
-
- assert!(!k0.public_eq(&k1));
- assert!(!p0.public_eq(&p1));
- assert!(!k0.public_eq(&p1));
- assert!(!p0.public_eq(&k1));
+ let key = include_bytes!("../../test/key.pem.pub");
+ super::PKey::public_key_from_pem(key).unwrap();
}
#[test]
fn test_pem() {
- let key_path = Path::new("test/key.pem");
- let mut file = File::open(&key_path)
- .ok()
- .expect("Failed to open `test/key.pem`");
-
- let key = super::PKey::private_key_from_pem(&mut file).unwrap();
+ let key = include_bytes!("../../test/key.pem");
+ let key = super::PKey::private_key_from_pem(key).unwrap();
- let mut priv_key = Vec::new();
- let mut pub_key = Vec::new();
-
- key.write_pem(&mut priv_key).unwrap();
- key.write_pub_pem(&mut pub_key).unwrap();
+ let priv_key = key.private_key_to_pem().unwrap();
+ let pub_key = key.public_key_to_pem().unwrap();
// As a super-simple verification, just check that the buffers contain
// the `PRIVATE KEY` or `PUBLIC KEY` strings.
assert!(priv_key.windows(11).any(|s| s == b"PRIVATE KEY"));
assert!(pub_key.windows(10).any(|s| s == b"PUBLIC KEY"));
}
-
- #[test]
- fn test_public_key_from_raw() {
- let mut k0 = super::PKey::new();
- let mut k1 = super::PKey::new();
- let msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8];
-
- k0.gen(512);
- let sig = k0.sign(&msg);
-
- let r0 = k0.get_rsa();
- let r1 = RSA::from_public_components(r0.n().expect("n"), r0.e().expect("e")).expect("r1");
- k1.set_rsa(&r1);
-
- assert!(k1.can(super::Role::Encrypt));
- assert!(!k1.can(super::Role::Decrypt));
- assert!(k1.can(super::Role::Verify));
- assert!(!k1.can(super::Role::Sign));
-
- let rv = k1.verify(&msg, &sig);
- assert!(rv == true);
- }
-
- #[test]
- #[should_panic(expected = "Could not get RSA key for encryption")]
- fn test_nokey_encrypt() {
- let mut pkey = super::PKey::new();
- pkey.load_pub(&[]);
- pkey.encrypt(&[]);
- }
-
- #[test]
- #[should_panic(expected = "Could not get RSA key for decryption")]
- fn test_nokey_decrypt() {
- let mut pkey = super::PKey::new();
- pkey.load_priv(&[]);
- pkey.decrypt(&[]);
- }
-
- #[test]
- #[should_panic(expected = "Could not get RSA key for signing")]
- fn test_nokey_sign() {
- let mut pkey = super::PKey::new();
- pkey.load_priv(&[]);
- pkey.sign(&[]);
- }
-
- #[test]
- #[should_panic(expected = "Could not get RSA key for verification")]
- fn test_nokey_verify() {
- let mut pkey = super::PKey::new();
- pkey.load_pub(&[]);
- pkey.verify(&[], &[]);
- }
-
- #[test]
- fn test_pkey_clone_creates_copy() {
- let mut pkey = super::PKey::new();
- pkey.gen(512);
- let old_pkey_n = pkey.get_rsa().n().unwrap();
-
- let mut pkey2 = pkey.clone();
- pkey2.gen(512);
-
- assert!(old_pkey_n == pkey.get_rsa().n().unwrap());
- }
-
- #[test]
- fn test_pkey_clone_copies_private() {
- let mut pkey = super::PKey::new();
- pkey.gen(512);
-
- let pkey2 = pkey.clone();
-
- assert!(pkey.get_rsa().q().unwrap() == pkey2.get_rsa().q().unwrap());
- }
-
- #[test]
- fn test_pkey_clone_copies_public() {
- let mut pkey = super::PKey::new();
- pkey.gen(512);
- let mut pub_key = super::PKey::new();
- pub_key.load_pub(&pkey.save_pub()[..]);
-
- let pub_key2 = pub_key.clone();
-
- assert!(pub_key.get_rsa().n().unwrap() == pub_key2.get_rsa().n().unwrap());
- }
}
diff --git a/openssl/src/crypto/rand.rs b/openssl/src/crypto/rand.rs
index ba57a8a1..519449e9 100644
--- a/openssl/src/crypto/rand.rs
+++ b/openssl/src/crypto/rand.rs
@@ -1,19 +1,13 @@
use libc::c_int;
use ffi;
+use error::ErrorStack;
-pub fn rand_bytes(len: usize) -> Vec<u8> {
+pub fn rand_bytes(buf: &mut [u8]) -> Result<(), ErrorStack> {
unsafe {
- let mut out = Vec::with_capacity(len);
-
ffi::init();
- let r = ffi::RAND_bytes(out.as_mut_ptr(), len as c_int);
- if r != 1 as c_int {
- panic!()
- }
-
- out.set_len(len);
-
- out
+ assert!(buf.len() <= c_int::max_value() as usize);
+ try_ssl_if!(ffi::RAND_bytes(buf.as_mut_ptr(), buf.len() as c_int) != 1);
+ Ok(())
}
}
@@ -23,7 +17,7 @@ mod tests {
#[test]
fn test_rand_bytes() {
- let bytes = rand_bytes(32);
- println!("{:?}", bytes);
+ let mut buf = [0; 32];
+ rand_bytes(&mut buf).unwrap();
}
}
diff --git a/openssl/src/crypto/rsa.rs b/openssl/src/crypto/rsa.rs
index 52b8590e..feb66a6f 100644
--- a/openssl/src/crypto/rsa.rs
+++ b/openssl/src/crypto/rsa.rs
@@ -1,14 +1,15 @@
use ffi;
use std::fmt;
-use ssl::error::{SslError, StreamError};
use std::ptr;
-use std::io::{self, Read, Write};
-use libc::c_int;
+use std::mem;
+use libc::{c_int, c_void, c_char, c_ulong};
-use bn::BigNum;
-use bio::MemBio;
-use crypto::HashTypeInternals;
+use bn::{BigNum, BigNumRef};
+use bio::{MemBio, MemBioSlice};
+use error::ErrorStack;
+use HashTypeInternals;
use crypto::hash;
+use crypto::util::{CallbackState, invoke_passwd_cb};
pub struct RSA(*mut ffi::RSA);
@@ -23,11 +24,13 @@ impl Drop for RSA {
impl RSA {
/// only useful for associating the key material directly with the key, it's safer to use
/// the supplied load and save methods for DER formatted keys.
- pub fn from_public_components(n: BigNum, e: BigNum) -> Result<RSA, SslError> {
+ pub fn from_public_components(n: BigNum, e: BigNum) -> Result<RSA, ErrorStack> {
unsafe {
let rsa = try_ssl_null!(ffi::RSA_new());
- (*rsa).n = n.into_raw();
- (*rsa).e = e.into_raw();
+ (*rsa).n = n.as_ptr();
+ (*rsa).e = e.as_ptr();
+ mem::forget(n);
+ mem::forget(e);
Ok(RSA(rsa))
}
}
@@ -40,35 +43,53 @@ impl RSA {
dp: BigNum,
dq: BigNum,
qi: BigNum)
- -> Result<RSA, SslError> {
+ -> Result<RSA, ErrorStack> {
unsafe {
let rsa = try_ssl_null!(ffi::RSA_new());
- (*rsa).n = n.into_raw();
- (*rsa).e = e.into_raw();
- (*rsa).d = d.into_raw();
- (*rsa).p = p.into_raw();
- (*rsa).q = q.into_raw();
- (*rsa).dmp1 = dp.into_raw();
- (*rsa).dmq1 = dq.into_raw();
- (*rsa).iqmp = qi.into_raw();
+ (*rsa).n = n.as_ptr();
+ (*rsa).e = e.as_ptr();
+ (*rsa).d = d.as_ptr();
+ (*rsa).p = p.as_ptr();
+ (*rsa).q = q.as_ptr();
+ (*rsa).dmp1 = dp.as_ptr();
+ (*rsa).dmq1 = dq.as_ptr();
+ (*rsa).iqmp = qi.as_ptr();
+ mem::forget(n);
+ mem::forget(e);
+ mem::forget(d);
+ mem::forget(p);
+ mem::forget(q);
+ mem::forget(dp);
+ mem::forget(dq);
+ mem::forget(qi);
Ok(RSA(rsa))
}
}
- /// the caller should assert that the rsa pointer is valid.
- pub unsafe fn from_raw(rsa: *mut ffi::RSA) -> RSA {
+ pub unsafe fn from_ptr(rsa: *mut ffi::RSA) -> RSA {
RSA(rsa)
}
- /// Reads an RSA private key from PEM formatted data.
- pub fn private_key_from_pem<R>(reader: &mut R) -> Result<RSA, SslError>
- where R: Read
- {
- let mut mem_bio = try!(MemBio::new());
- try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
+ /// Generates a public/private key pair with the specified size.
+ ///
+ /// The public exponent will be 65537.
+ pub fn generate(bits: u32) -> Result<RSA, ErrorStack> {
+ unsafe {
+ let rsa = try_ssl_null!(ffi::RSA_new());
+ let rsa = RSA(rsa);
+ let e = try!(BigNum::new_from(ffi::RSA_F4 as c_ulong));
+
+ try_ssl!(ffi::RSA_generate_key_ex(rsa.0, bits as c_int, e.as_ptr(), ptr::null_mut()));
+ Ok(rsa)
+ }
+ }
+
+ /// Reads an RSA private key from PEM formatted data.
+ pub fn private_key_from_pem(buf: &[u8]) -> Result<RSA, ErrorStack> {
+ let mem_bio = try!(MemBioSlice::new(buf));
unsafe {
- let rsa = try_ssl_null!(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.get_handle(),
+ let rsa = try_ssl_null!(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.as_ptr(),
ptr::null_mut(),
None,
ptr::null_mut()));
@@ -76,40 +97,29 @@ impl RSA {
}
}
- /// Writes an RSA private key as unencrypted PEM formatted data
- pub fn private_key_to_pem<W>(&self, writer: &mut W) -> Result<(), SslError>
- where W: Write
+ /// Reads an RSA private key from PEM formatted data and supplies a password callback.
+ pub fn private_key_from_pem_cb<F>(buf: &[u8], pass_cb: F) -> Result<RSA, ErrorStack>
+ where F: FnOnce(&mut [c_char]) -> usize
{
- let mut mem_bio = try!(MemBio::new());
+ let mut cb = CallbackState::new(pass_cb);
+ let mem_bio = try!(MemBioSlice::new(buf));
- let result = unsafe {
- ffi::PEM_write_bio_RSAPrivateKey(mem_bio.get_handle(),
- self.0,
- ptr::null(),
- ptr::null_mut(),
- 0,
- None,
- ptr::null_mut())
- };
-
- if result == 1 {
- try!(io::copy(&mut mem_bio, writer).map_err(StreamError));
+ unsafe {
+ let cb_ptr = &mut cb as *mut _ as *mut c_void;
+ let rsa = try_ssl_null!(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.as_ptr(),
+ ptr::null_mut(),
+ Some(invoke_passwd_cb::<F>),
+ cb_ptr));
- Ok(())
- } else {
- Err(SslError::OpenSslErrors(vec![]))
+ Ok(RSA(rsa))
}
}
/// Reads an RSA public key from PEM formatted data.
- pub fn public_key_from_pem<R>(reader: &mut R) -> Result<RSA, SslError>
- where R: Read
- {
- let mut mem_bio = try!(MemBio::new());
- try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
-
+ pub fn public_key_from_pem(buf: &[u8]) -> Result<RSA, ErrorStack> {
+ let mem_bio = try!(MemBioSlice::new(buf));
unsafe {
- let rsa = try_ssl_null!(ffi::PEM_read_bio_RSA_PUBKEY(mem_bio.get_handle(),
+ let rsa = try_ssl_null!(ffi::PEM_read_bio_RSA_PUBKEY(mem_bio.as_ptr(),
ptr::null_mut(),
None,
ptr::null_mut()));
@@ -117,97 +127,127 @@ impl RSA {
}
}
- /// Writes an RSA public key as PEM formatted data
- pub fn public_key_to_pem<W>(&self, writer: &mut W) -> Result<(), SslError>
- where W: Write
- {
- let mut mem_bio = try!(MemBio::new());
+ /// Writes an RSA private key as unencrypted PEM formatted data
+ pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
+ let mem_bio = try!(MemBio::new());
+
+ unsafe {
+ try_ssl!(ffi::PEM_write_bio_RSAPrivateKey(mem_bio.as_ptr(),
+ self.0,
+ ptr::null(),
+ ptr::null_mut(),
+ 0,
+ None,
+ ptr::null_mut()));
+ }
+ Ok(mem_bio.get_buf().to_owned())
+ }
- let result = unsafe { ffi::PEM_write_bio_RSA_PUBKEY(mem_bio.get_handle(), self.0) };
+ /// Writes an RSA public key as PEM formatted data
+ pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
+ let mem_bio = try!(MemBio::new());
- if result == 1 {
- try!(io::copy(&mut mem_bio, writer).map_err(StreamError));
+ unsafe {
+ try_ssl!(ffi::PEM_write_bio_RSA_PUBKEY(mem_bio.as_ptr(), self.0))
+ };
- Ok(())
- } else {
- Err(SslError::OpenSslErrors(vec![]))
- }
+ Ok(mem_bio.get_buf().to_owned())
}
- pub fn size(&self) -> Result<u32, SslError> {
- if self.has_n() {
- unsafe { Ok(ffi::RSA_size(self.0) as u32) }
+ pub fn size(&self) -> Option<u32> {
+ if self.n().is_some() {
+ unsafe { Some(ffi::RSA_size(self.0) as u32) }
} else {
- Err(SslError::OpenSslErrors(vec![]))
+ None
}
}
- pub fn sign(&self, hash: hash::Type, message: &[u8]) -> Result<Vec<u8>, SslError> {
- let k_len = try!(self.size());
- let mut sig = vec![0;k_len as usize];
+ pub fn sign(&self, hash: hash::Type, message: &[u8]) -> Result<Vec<u8>, ErrorStack> {
+ let k_len = self.size().expect("RSA missing an n");
+ let mut sig = vec![0; k_len as usize];
let mut sig_len = k_len;
unsafe {
- let result = ffi::RSA_sign(hash.as_nid() as c_int,
- message.as_ptr(),
- message.len() as u32,
- sig.as_mut_ptr(),
- &mut sig_len,
- self.0);
+ try_ssl!(ffi::RSA_sign(hash.as_nid() as c_int,
+ message.as_ptr(),
+ message.len() as u32,
+ sig.as_mut_ptr(),
+ &mut sig_len,
+ self.0));
assert!(sig_len == k_len);
-
- if result == 1 {
- Ok(sig)
- } else {
- Err(SslError::OpenSslErrors(vec![]))
- }
+ Ok(sig)
}
}
- pub fn verify(&self, hash: hash::Type, message: &[u8], sig: &[u8]) -> Result<bool, SslError> {
+ pub fn verify(&self, hash: hash::Type, message: &[u8], sig: &[u8]) -> Result<(), ErrorStack> {
unsafe {
- let result = ffi::RSA_verify(hash.as_nid() as c_int,
- message.as_ptr(),
- message.len() as u32,
- sig.as_ptr(),
- sig.len() as u32,
- self.0);
-
- Ok(result == 1)
+ try_ssl!(ffi::RSA_verify(hash.as_nid() as c_int,
+ message.as_ptr(),
+ message.len() as u32,
+ sig.as_ptr(),
+ sig.len() as u32,
+ self.0));
}
+ Ok(())
}
pub fn as_ptr(&self) -> *mut ffi::RSA {
self.0
}
- // The following getters are unsafe, since BigNum::new_from_ffi fails upon null pointers
- pub fn n(&self) -> Result<BigNum, SslError> {
- unsafe { BigNum::new_from_ffi((*self.0).n) }
- }
-
- pub fn has_n(&self) -> bool {
- unsafe { !(*self.0).n.is_null() }
- }
-
- pub fn d(&self) -> Result<BigNum, SslError> {
- unsafe { BigNum::new_from_ffi((*self.0).d) }
+ pub fn n<'a>(&'a self) -> Option<BigNumRef<'a>> {
+ unsafe {
+ let n = (*self.0).n;
+ if n.is_null() {
+ None
+ } else {
+ Some(BigNumRef::from_ptr(n))
+ }
+ }
}
- pub fn e(&self) -> Result<BigNum, SslError> {
- unsafe { BigNum::new_from_ffi((*self.0).e) }
+ pub fn d<'a>(&self) -> Option<BigNumRef<'a>> {
+ unsafe {
+ let d = (*self.0).d;
+ if d.is_null() {
+ None
+ } else {
+ Some(BigNumRef::from_ptr(d))
+ }
+ }
}
- pub fn has_e(&self) -> bool {
- unsafe { !(*self.0).e.is_null() }
+ pub fn e<'a>(&'a self) -> Option<BigNumRef<'a>> {
+ unsafe {
+ let e = (*self.0).e;
+ if e.is_null() {
+ None
+ } else {
+ Some(BigNumRef::from_ptr(e))
+ }
+ }
}
- pub fn p(&self) -> Result<BigNum, SslError> {
- unsafe { BigNum::new_from_ffi((*self.0).p) }
+ pub fn p<'a>(&'a self) -> Option<BigNumRef<'a>> {
+ unsafe {
+ let p = (*self.0).p;
+ if p.is_null() {
+ None
+ } else {
+ Some(BigNumRef::from_ptr(p))
+ }
+ }
}
- pub fn q(&self) -> Result<BigNum, SslError> {
- unsafe { BigNum::new_from_ffi((*self.0).q) }
+ pub fn q<'a>(&'a self) -> Option<BigNumRef<'a>> {
+ unsafe {
+ let q = (*self.0).q;
+ if q.is_null() {
+ None
+ } else {
+ Some(BigNumRef::from_ptr(q))
+ }
+ }
}
}
@@ -219,8 +259,9 @@ impl fmt::Debug for RSA {
#[cfg(test)]
mod test {
- use std::fs::File;
use std::io::Write;
+ use libc::c_char;
+
use super::*;
use crypto::hash::*;
@@ -252,12 +293,12 @@ mod test {
#[test]
pub fn test_sign() {
- let mut buffer = File::open("test/rsa.pem").unwrap();
- let private_key = RSA::private_key_from_pem(&mut buffer).unwrap();
+ let key = include_bytes!("../../test/rsa.pem");
+ let private_key = RSA::private_key_from_pem(key).unwrap();
- let mut sha = Hasher::new(Type::SHA256);
+ let mut sha = Hasher::new(Type::SHA256).unwrap();
sha.write_all(&signing_input_rs256()).unwrap();
- let digest = sha.finish();
+ let digest = sha.finish().unwrap();
let result = private_key.sign(Type::SHA256, &digest).unwrap();
@@ -266,15 +307,31 @@ mod test {
#[test]
pub fn test_verify() {
- let mut buffer = File::open("test/rsa.pem.pub").unwrap();
- let public_key = RSA::public_key_from_pem(&mut buffer).unwrap();
+ let key = include_bytes!("../../test/rsa.pem.pub");
+ let public_key = RSA::public_key_from_pem(key).unwrap();
- let mut sha = Hasher::new(Type::SHA256);
+ let mut sha = Hasher::new(Type::SHA256).unwrap();
sha.write_all(&signing_input_rs256()).unwrap();
- let digest = sha.finish();
+ let digest = sha.finish().unwrap();
- let result = public_key.verify(Type::SHA256, &digest, &signature_rs256()).unwrap();
+ assert!(public_key.verify(Type::SHA256, &digest, &signature_rs256()).is_ok());
+ }
- assert!(result);
+ #[test]
+ pub fn test_password() {
+ let mut password_queried = false;
+ let key = include_bytes!("../../test/rsa-encrypted.pem");
+ RSA::private_key_from_pem_cb(key, |password| {
+ password_queried = true;
+ password[0] = b'm' as c_char;
+ password[1] = b'y' as c_char;
+ password[2] = b'p' as c_char;
+ password[3] = b'a' as c_char;
+ password[4] = b's' as c_char;
+ password[5] = b's' as c_char;
+ 6
+ }).unwrap();
+
+ assert!(password_queried);
}
}
diff --git a/openssl/src/crypto/symm.rs b/openssl/src/crypto/symm.rs
index 935980f3..93764e4d 100644
--- a/openssl/src/crypto/symm.rs
+++ b/openssl/src/crypto/symm.rs
@@ -1,9 +1,10 @@
-use std::iter::repeat;
+use std::cmp;
+use std::ptr;
use libc::c_int;
-
-use crypto::symm_internal::evpc;
use ffi;
+use error::ErrorStack;
+
#[derive(Copy, Clone)]
pub enum Mode {
Encrypt,
@@ -43,94 +44,184 @@ pub enum Type {
RC4_128,
}
+impl Type {
+ pub fn as_ptr(&self) -> *const ffi::EVP_CIPHER {
+ unsafe {
+ match *self {
+ Type::AES_128_ECB => ffi::EVP_aes_128_ecb(),
+ Type::AES_128_CBC => ffi::EVP_aes_128_cbc(),
+ #[cfg(feature = "aes_xts")]
+ Type::AES_128_XTS => ffi::EVP_aes_128_xts(),
+ #[cfg(feature = "aes_ctr")]
+ Type::AES_128_CTR => ffi::EVP_aes_128_ctr(),
+ // AES_128_GCM => (EVP_aes_128_gcm(), 16, 16),
+ Type::AES_128_CFB1 => ffi::EVP_aes_128_cfb1(),
+ Type::AES_128_CFB128 => ffi::EVP_aes_128_cfb128(),
+ Type::AES_128_CFB8 => ffi::EVP_aes_128_cfb8(),
+
+ Type::AES_256_ECB => ffi::EVP_aes_256_ecb(),
+ Type::AES_256_CBC => ffi::EVP_aes_256_cbc(),
+ #[cfg(feature = "aes_xts")]
+ Type::AES_256_XTS => ffi::EVP_aes_256_xts(),
+ #[cfg(feature = "aes_ctr")]
+ Type::AES_256_CTR => ffi::EVP_aes_256_ctr(),
+ // AES_256_GCM => (EVP_aes_256_gcm(), 32, 16),
+ Type::AES_256_CFB1 => ffi::EVP_aes_256_cfb1(),
+ Type::AES_256_CFB128 => ffi::EVP_aes_256_cfb128(),
+ Type::AES_256_CFB8 => ffi::EVP_aes_256_cfb8(),
+
+ Type::DES_CBC => ffi::EVP_des_cbc(),
+ Type::DES_ECB => ffi::EVP_des_ecb(),
+
+ Type::RC4_128 => ffi::EVP_rc4(),
+ }
+ }
+ }
+
+ /// Returns the length of keys used with this cipher.
+ pub fn key_len(&self) -> usize {
+ unsafe {
+ ffi::EVP_CIPHER_key_length(self.as_ptr()) as usize
+ }
+ }
+
+ /// Returns the length of the IV used with this cipher, or `None` if the
+ /// cipher does not use an IV.
+ pub fn iv_len(&self) -> Option<usize> {
+ unsafe {
+ let len = ffi::EVP_CIPHER_iv_length(self.as_ptr()) as usize;
+ if len == 0 {
+ None
+ } else {
+ Some(len)
+ }
+ }
+ }
+
+ /// Returns the block size of the cipher.
+ ///
+ /// # Note
+ ///
+ /// Stream ciphers such as RC4 have a block size of 1.
+ pub fn block_size(&self) -> usize {
+ unsafe {
+ ffi::EVP_CIPHER_block_size(self.as_ptr()) as usize
+ }
+ }
+}
/// Represents a symmetric cipher context.
pub struct Crypter {
- evp: *const ffi::EVP_CIPHER,
ctx: *mut ffi::EVP_CIPHER_CTX,
- keylen: u32,
- blocksize: u32,
+ block_size: usize,
}
impl Crypter {
- pub fn new(t: Type) -> Crypter {
+ /// Creates a new `Crypter`.
+ ///
+ /// # Panics
+ ///
+ /// Panics if an IV is required by the cipher but not provided, or if the
+ /// IV's length does not match the expected length (see `Type::iv_len`).
+ pub fn new(t: Type, mode: Mode, key: &[u8], iv: Option<&[u8]>) -> Result<Crypter, ErrorStack> {
ffi::init();
- let ctx = unsafe { ffi::EVP_CIPHER_CTX_new() };
- let (evp, keylen, blocksz) = evpc(t);
- Crypter {
- evp: evp,
- ctx: ctx,
- keylen: keylen,
- blocksize: blocksz,
- }
- }
-
- /**
- * Enables or disables padding. If padding is disabled, total amount of
- * data encrypted must be a multiple of block size.
- */
- pub fn pad(&self, padding: bool) {
- if self.blocksize > 0 {
- unsafe {
- let v = if padding {
- 1 as c_int
- } else {
- 0
- };
- ffi::EVP_CIPHER_CTX_set_padding(self.ctx, v);
- }
- }
- }
-
- /**
- * Initializes this crypter.
- */
- pub fn init(&self, mode: Mode, key: &[u8], iv: &[u8]) {
unsafe {
+ let ctx = try_ssl_null!(ffi::EVP_CIPHER_CTX_new());
+ let crypter = Crypter {
+ ctx: ctx,
+ block_size: t.block_size(),
+ };
+
let mode = match mode {
- Mode::Encrypt => 1 as c_int,
- Mode::Decrypt => 0 as c_int,
+ Mode::Encrypt => 1,
+ Mode::Decrypt => 0,
};
- assert_eq!(key.len(), self.keylen as usize);
- ffi::EVP_CipherInit(self.ctx, self.evp, key.as_ptr(), iv.as_ptr(), mode);
+ try_ssl!(ffi::EVP_CipherInit_ex(crypter.ctx,
+ t.as_ptr(),
+ ptr::null_mut(),
+ ptr::null_mut(),
+ ptr::null_mut(),
+ mode));
+
+ assert!(key.len() <= c_int::max_value() as usize);
+ try_ssl!(ffi::EVP_CIPHER_CTX_set_key_length(crypter.ctx, key.len() as c_int));
+
+ let key = key.as_ptr() as *mut _;
+ let iv = match (iv, t.iv_len()) {
+ (Some(iv), Some(len)) => {
+ assert!(iv.len() == len);
+ iv.as_ptr() as *mut _
+ }
+ (Some(_), None) | (None, None) => ptr::null_mut(),
+ (None, Some(_)) => panic!("an IV is required for this cipher"),
+ };
+ try_ssl!(ffi::EVP_CipherInit_ex(crypter.ctx,
+ ptr::null(),
+ ptr::null_mut(),
+ key,
+ iv,
+ mode));
+
+ Ok(crypter)
}
}
- /**
- * Update this crypter with more data to encrypt or decrypt. Returns
- * encrypted or decrypted bytes.
- */
- pub fn update(&self, data: &[u8]) -> Vec<u8> {
+ /// Enables or disables padding.
+ ///
+ /// If padding is disabled, total amount of data encrypted/decrypted must
+ /// be a multiple of the cipher's block size.
+ pub fn pad(&mut self, padding: bool) {
+ unsafe { ffi::EVP_CIPHER_CTX_set_padding(self.ctx, padding as c_int); }
+ }
+
+ /// Feeds data from `input` through the cipher, writing encrypted/decrypted
+ /// bytes into `output`.
+ ///
+ /// The number of bytes written to `output` is returned. Note that this may
+ /// not be equal to the length of `input`.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `output.len() < input.len() + block_size` where
+ /// `block_size` is the block size of the cipher (see `Type::block_size`),
+ /// or if `output.len() > c_int::max_value()`.
+ pub fn update(&mut self, input: &[u8], output: &mut [u8]) -> Result<usize, ErrorStack> {
unsafe {
- let sum = data.len() + (self.blocksize as usize);
- let mut res = repeat(0u8).take(sum).collect::<Vec<_>>();
- let mut reslen = sum as c_int;
-
- ffi::EVP_CipherUpdate(self.ctx,
- res.as_mut_ptr(),
- &mut reslen,
- data.as_ptr(),
- data.len() as c_int);
-
- res.truncate(reslen as usize);
- res
+ assert!(output.len() >= input.len() + self.block_size);
+ assert!(output.len() <= c_int::max_value() as usize);
+ let mut outl = output.len() as c_int;
+ let inl = input.len() as c_int;
+
+ try_ssl!(ffi::EVP_CipherUpdate(self.ctx,
+ output.as_mut_ptr(),
+ &mut outl,
+ input.as_ptr(),
+ inl));
+
+ Ok(outl as usize)
}
}
- /**
- * Finish crypting. Returns the remaining partial block of output, if any.
- */
- pub fn finalize(&self) -> Vec<u8> {
+ /// Finishes the encryption/decryption process, writing any remaining data
+ /// to `output`.
+ ///
+ /// The number of bytes written to `output` is returned.
+ ///
+ /// `update` should not be called after this method.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `output` is less than the cipher's block size.
+ pub fn finalize(&mut self, output: &mut [u8]) -> Result<usize, ErrorStack> {
unsafe {
- let mut res = repeat(0u8).take(self.blocksize as usize).collect::<Vec<_>>();
- let mut reslen = self.blocksize as c_int;
+ assert!(output.len() >= self.block_size);
+ let mut outl = cmp::min(output.len(), c_int::max_value() as usize) as c_int;
- ffi::EVP_CipherFinal(self.ctx, res.as_mut_ptr(), &mut reslen);
+ try_ssl!(ffi::EVP_CipherFinal(self.ctx, output.as_mut_ptr(), &mut outl));
- res.truncate(reslen as usize);
- res
+ Ok(outl as usize)
}
}
}
@@ -147,31 +238,43 @@ impl Drop for Crypter {
* Encrypts data, using the specified crypter type in encrypt mode with the
* specified key and iv; returns the resulting (encrypted) data.
*/
-pub fn encrypt(t: Type, key: &[u8], iv: &[u8], data: &[u8]) -> Vec<u8> {
- let c = Crypter::new(t);
- c.init(Mode::Encrypt, key, iv);
- let mut r = c.update(data);
- let rest = c.finalize();
- r.extend(rest.into_iter());
- r
+pub fn encrypt(t: Type,
+ key: &[u8],
+ iv: Option<&[u8]>,
+ data: &[u8])
+ -> Result<Vec<u8>, ErrorStack> {
+ cipher(t, Mode::Encrypt, key, iv, data)
}
/**
* Decrypts data, using the specified crypter type in decrypt mode with the
* specified key and iv; returns the resulting (decrypted) data.
*/
-pub fn decrypt(t: Type, key: &[u8], iv: &[u8], data: &[u8]) -> Vec<u8> {
- let c = Crypter::new(t);
- c.init(Mode::Decrypt, key, iv);
- let mut r = c.update(data);
- let rest = c.finalize();
- r.extend(rest.into_iter());
- r
+pub fn decrypt(t: Type,
+ key: &[u8],
+ iv: Option<&[u8]>,
+ data: &[u8])
+ -> Result<Vec<u8>, ErrorStack> {
+ cipher(t, Mode::Decrypt, key, iv, data)
+}
+
+fn cipher(t: Type,
+ mode: Mode,
+ key: &[u8],
+ iv: Option<&[u8]>,
+ data: &[u8])
+ -> Result<Vec<u8>, ErrorStack> {
+ let mut c = try!(Crypter::new(t, mode, key, iv));
+ let mut out = vec![0; data.len() + t.block_size()];
+ let count = try!(c.update(data, &mut out));
+ let rest = try!(c.finalize(&mut out[count..]));
+ out.truncate(count + rest);
+ Ok(out)
}
#[cfg(test)]
mod tests {
- use serialize::hex::FromHex;
+ use serialize::hex::{FromHex, ToHex};
// Test vectors from FIPS-197:
// http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
@@ -185,25 +288,33 @@ mod tests {
0xaau8, 0xbbu8, 0xccu8, 0xddu8, 0xeeu8, 0xffu8];
let c0 = [0x8eu8, 0xa2u8, 0xb7u8, 0xcau8, 0x51u8, 0x67u8, 0x45u8, 0xbfu8, 0xeau8, 0xfcu8,
0x49u8, 0x90u8, 0x4bu8, 0x49u8, 0x60u8, 0x89u8];
- let c = super::Crypter::new(super::Type::AES_256_ECB);
- c.init(super::Mode::Encrypt, &k0, &[]);
+ let mut c = super::Crypter::new(super::Type::AES_256_ECB,
+ super::Mode::Encrypt,
+ &k0,
+ None).unwrap();
c.pad(false);
- let mut r0 = c.update(&p0);
- r0.extend(c.finalize().into_iter());
- assert!(r0 == c0);
- c.init(super::Mode::Decrypt, &k0, &[]);
+ let mut r0 = vec![0; c0.len() + super::Type::AES_256_ECB.block_size()];
+ let count = c.update(&p0, &mut r0).unwrap();
+ let rest = c.finalize(&mut r0[count..]).unwrap();
+ r0.truncate(count + rest);
+ assert_eq!(r0.to_hex(), c0.to_hex());
+
+ let mut c = super::Crypter::new(super::Type::AES_256_ECB,
+ super::Mode::Decrypt,
+ &k0,
+ None).unwrap();
c.pad(false);
- let mut p1 = c.update(&r0);
- p1.extend(c.finalize().into_iter());
- assert!(p1 == p0);
+ let mut p1 = vec![0; r0.len() + super::Type::AES_256_ECB.block_size()];
+ let count = c.update(&r0, &mut p1).unwrap();
+ let rest = c.finalize(&mut p1[count..]).unwrap();
+ p1.truncate(count + rest);
+ assert_eq!(p1.to_hex(), p0.to_hex());
}
#[test]
fn test_aes_256_cbc_decrypt() {
- let cr = super::Crypter::new(super::Type::AES_256_CBC);
let iv = [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];
+ 98_u8, 107_u8, 208_u8, 14_u8, 236_u8, 60_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,
@@ -211,29 +322,31 @@ mod tests {
let ciphered_data = [0x4a_u8, 0x2e_u8, 0xe5_u8, 0x6_u8, 0xbf_u8, 0xcf_u8, 0xf2_u8,
0xd7_u8, 0xea_u8, 0x2d_u8, 0xb1_u8, 0x85_u8, 0x6c_u8, 0x93_u8,
0x65_u8, 0x6f_u8];
- cr.init(super::Mode::Decrypt, &data, &iv);
+ let mut cr = super::Crypter::new(super::Type::AES_256_CBC,
+ super::Mode::Decrypt,
+ &data,
+ Some(&iv)).unwrap();
cr.pad(false);
- let unciphered_data_1 = cr.update(&ciphered_data);
- let unciphered_data_2 = cr.finalize();
+ let mut unciphered_data = vec![0; data.len() + super::Type::AES_256_CBC.block_size()];
+ let count = cr.update(&ciphered_data, &mut unciphered_data).unwrap();
+ let rest = cr.finalize(&mut unciphered_data[count..]).unwrap();
+ unciphered_data.truncate(count + rest);
let expected_unciphered_data = b"I love turtles.\x01";
- assert!(unciphered_data_2.len() == 0);
-
- assert_eq!(&unciphered_data_1, expected_unciphered_data);
+ assert_eq!(&unciphered_data, expected_unciphered_data);
}
fn cipher_test(ciphertype: super::Type, pt: &str, ct: &str, key: &str, iv: &str) {
use serialize::hex::ToHex;
- let cipher = super::Crypter::new(ciphertype);
- cipher.init(super::Mode::Encrypt,
- &key.from_hex().unwrap(),
- &iv.from_hex().unwrap());
+ let pt = pt.from_hex().unwrap();
+ let ct = ct.from_hex().unwrap();
+ let key = key.from_hex().unwrap();
+ let iv = iv.from_hex().unwrap();
- let expected = ct.from_hex().unwrap();
- let mut computed = cipher.update(&pt.from_hex().unwrap());
- computed.extend(cipher.finalize().into_iter());
+ let computed = super::decrypt(ciphertype, &key, Some(&iv), &ct).unwrap();
+ let expected = pt;
if computed != expected {
println!("Computed: {}", computed.to_hex());
diff --git a/openssl/src/crypto/symm_internal.rs b/openssl/src/crypto/symm_internal.rs
deleted file mode 100644
index ba01e1c1..00000000
--- a/openssl/src/crypto/symm_internal.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-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_128_CFB1 => (ffi::EVP_aes_128_cfb1(), 16, 16),
- symm::Type::AES_128_CFB128 => (ffi::EVP_aes_128_cfb128(), 16, 16),
- symm::Type::AES_128_CFB8 => (ffi::EVP_aes_128_cfb8(), 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::AES_256_CFB1 => (ffi::EVP_aes_256_cfb1(), 32, 16),
- symm::Type::AES_256_CFB128 => (ffi::EVP_aes_256_cfb128(), 32, 16),
- symm::Type::AES_256_CFB8 => (ffi::EVP_aes_256_cfb8(), 32, 16),
-
- symm::Type::DES_CBC => (ffi::EVP_des_cbc(), 8, 8),
- symm::Type::DES_ECB => (ffi::EVP_des_ecb(), 8, 8),
-
- symm::Type::RC4_128 => (ffi::EVP_rc4(), 16, 0),
- }
- }
-}
diff --git a/openssl/src/crypto/util.rs b/openssl/src/crypto/util.rs
new file mode 100644
index 00000000..be72aa59
--- /dev/null
+++ b/openssl/src/crypto/util.rs
@@ -0,0 +1,58 @@
+use libc::{c_int, c_char, c_void};
+
+use std::any::Any;
+use std::panic;
+use std::slice;
+
+/// Wraps a user-supplied callback and a slot for panics thrown inside the callback (while FFI
+/// frames are on the stack).
+///
+/// When dropped, checks if the callback has panicked, and resumes unwinding if so.
+pub struct CallbackState<F> {
+ /// The user callback. Taken out of the `Option` when called.
+ cb: Option<F>,
+ /// If the callback panics, we place the panic object here, to be re-thrown once OpenSSL
+ /// returns.
+ panic: Option<Box<Any + Send + 'static>>,
+}
+
+impl<F> CallbackState<F> {
+ pub fn new(callback: F) -> Self {
+ CallbackState {
+ cb: Some(callback),
+ panic: None,
+ }
+ }
+}
+
+impl<F> Drop for CallbackState<F> {
+ fn drop(&mut self) {
+ if let Some(panic) = self.panic.take() {
+ panic::resume_unwind(panic);
+ }
+ }
+}
+
+/// Password callback function, passed to private key loading functions.
+///
+/// `cb_state` is expected to be a pointer to a `CallbackState`.
+pub extern "C" fn invoke_passwd_cb<F>(buf: *mut c_char,
+ size: c_int,
+ _rwflag: c_int,
+ cb_state: *mut c_void)
+ -> c_int
+ where F: FnOnce(&mut [i8]) -> usize {
+ let result = panic::catch_unwind(|| {
+ // build a `i8` slice to pass to the user callback
+ let pass_slice = unsafe { slice::from_raw_parts_mut(buf, size as usize) };
+ let callback = unsafe { &mut *(cb_state as *mut CallbackState<F>) };
+
+ callback.cb.take().unwrap()(pass_slice)
+ });
+
+ if let Ok(len) = result {
+ return len as c_int;
+ } else {
+ return 0;
+ }
+}