Refactor |ring::digest| to have a more usable API.

The previous interface suffered from multiple problems that made it
annoying to use in contexts that needed to digest data with a digest
function that wasn't known statically at build time. The old interface
was also hard to avoid uses of the heap when digest algorithm agility
is required. It was also annoying that one had to import the |Digest|
trait even in code that only wanted to use a statically-chosen digest
function, because calling a method declared in a trait requires that.

The updates to examples/checkdigest.rs demonstrate the improved
usability.

This change also moves to a new style where it is assumed that users of
*ring* will |use ring::*| and then access submodules using
partially-qualified syntax. For example, instead of naming the digest
context type |DigestContext|, it is named just |Context| with the
expectation that code will refer to it as |digest::Context|. Future
sub-modules will follow this convention so that, for example, the HMAC
context type will be |ring::hmac::Context|.

The new interface also helps establish the convention that algorithms
exposed as |pub static| values of some type, usually a struct type.
This convention help enable the linker to discard the code for unused
algorithms.

The fact that |SignatureDigestAlgorithm| is no longer needed in this
new design is a good indication that we're on a better track.
This commit is contained in:
Brian Smith 2015-09-11 20:26:29 -07:00
parent 1dd99fe88b
commit 32480fc591
5 changed files with 256 additions and 288 deletions

View File

@ -15,7 +15,7 @@
extern crate ring;
extern crate rustc_serialize;
use ring::{Digest, SHA256, SHA384, SHA512};
use ring::*;
use rustc_serialize::hex::FromHex;
use std::error::Error;
use std::io::{Read, Write};
@ -40,18 +40,14 @@ fn print_usage(program_name: &str) {
fn run(digest_name: &str, expected_digest_hex: &str,
file_path: &std::path::Path) -> Result<(), &'static str> {
enum D {
SHA256(SHA256),
SHA384(SHA384),
SHA512(SHA512),
}
let digest_alg = match digest_name {
"sha256" => &digest::SHA256,
"sha384" => &digest::SHA384,
"sha512" => &digest::SHA512,
_ => { return Err("unsupported digest algorithm"); }
};
let mut digest = try!(match digest_name {
"sha256" => Ok(D::SHA256(SHA256::new())),
"sha384" => Ok(D::SHA384(SHA384::new())),
"sha512" => Ok(D::SHA512(SHA512::new())),
_ => Err("unsupported digest algorithm")
});
let mut ctx = digest::Context::new(digest_alg);
{
let mut file = match std::fs::File::open(file_path) {
@ -65,11 +61,7 @@ fn run(digest_name: &str, expected_digest_hex: &str,
loop {
match file.read(&mut chunk[..]) {
Ok(0) => break,
Ok(bytes_read) => match digest {
D::SHA256(ref mut ctx) => ctx.update(&chunk[0..bytes_read]),
D::SHA384(ref mut ctx) => ctx.update(&chunk[0..bytes_read]),
D::SHA512(ref mut ctx) => ctx.update(&chunk[0..bytes_read]),
},
Ok(bytes_read) => ctx.update(&chunk[0..bytes_read]),
// TODO: don't use panic here
Err(why) => panic!("couldn't open {}: {}", file_path.display(),
why.description())
@ -77,12 +69,10 @@ fn run(digest_name: &str, expected_digest_hex: &str,
}
}
let actual_digest = ctx.finish();
let matched = match expected_digest_hex.from_hex() {
Ok(expected) => match digest {
D::SHA256(ref mut ctx) => &expected[..] == &ctx.finish()[..],
D::SHA384(ref mut ctx) => &expected[..] == &ctx.finish()[..],
D::SHA512(ref mut ctx) => &expected[..] == &ctx.finish()[..],
},
Ok(expected) => actual_digest.as_ref() == &expected[..],
Err(_) => panic!("syntactically invalid digest")
};

View File

@ -12,60 +12,100 @@
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//! SHA-2 and legacy SHA-1 and MD5 digest algorithms.
//!
//! If all the data is available in a single contiguous slice then the `digest`
//! function should be used. Otherwise, the digest can be calculated in
//! multiple steps using `Context`.
// Note on why are we doing things the hard way: It would be easy to implement
// this using the C `EVP_MD`/`EVP_MD_CTX` interface. However, if we were to do
// things that way, we'd have a hard dependency on `malloc` and other overhead.
// The goal for this implementation is to drive the overhead as close to zero
// as possible.
// XXX: Double-check conversions between |usize| and |libc::size_t|, and try to
// find some way to statically assert that they have the same range.
use libc;
use std::mem;
/// A context for digest calculations. If all the data is available in a single
/// contiguous slice, then the `digest` function should be used. Otherwise, the
/// digest can be calculated in parts.
/// A context for multi-step (Init-Update-Finish) digest calculations.
///
/// C analog: `EVP_MD_CTX`.
///
/// # Examples
///
/// ```
/// use ring::{digest, Digest, SHA384};
/// use ring::*;
///
/// let one_shot = digest::<SHA384>("hello, world".as_bytes());
/// let one_shot = digest::digest(&digest::SHA384, "hello, world".as_bytes());
///
/// let mut ctx = SHA384::new();
/// let mut ctx = digest::Context::new(&digest::SHA384);
/// ctx.update("hello".as_bytes());
/// ctx.update(", ".as_bytes());
/// ctx.update("world".as_bytes());
/// let multi_part = ctx.finish();
///
/// assert_eq!(&one_shot[..], &multi_part[..]);
/// assert_eq!(&one_shot.as_ref(), &multi_part.as_ref());
/// ```
pub trait Digest {
/// The sized array type for the digest's size. For example, for SHA-256
/// this is `[u8; 32]` (256 / 8 == 32).
type Value;
#[derive(Clone)]
pub struct Context {
pub algorithm: &'static Algorithm,
// We use u64 to try to ensure 64-bit alignment/padding.
// XXX: Test this, and also test that DIGEST_CONTEXT_U64_COUNT is enough
// by having the build system verify with the C part of the build system.
state: [u64; DIGEST_CONTEXT_STATE_U64_COUNT],
}
impl Context {
/// Constructs a new context.
///
/// C analog: `EVP_DigestInit`
fn new() -> Self;
pub fn new(algorithm: &'static Algorithm) -> Context {
let mut ctx = Context {
algorithm: algorithm,
state: [0u64; DIGEST_CONTEXT_STATE_U64_COUNT],
};
let _ = unsafe { (algorithm.init)(ctx.state.as_mut_ptr()) };
ctx
}
/// Updates the digest with all the data in `data`. `update` may be called
/// zero or more times until `finish` is called. It must not be called
/// after `finish` has been called.
///
/// C analog: `EVP_DigestUpdate`
fn update(&mut self, data: &[u8]);
pub fn update(&mut self, data: &[u8]) {
let _ = unsafe {
(self.algorithm.update)(self.state.as_mut_ptr(), data.as_ptr(),
data.len() as libc::size_t)
};
}
/// Finalizes the digest calculation and returns the digest value. `finish`
/// must not be called more than once.
/// consumes the context so it cannot be (mis-)used after `finish` has been
/// called.
///
/// C analog: `EVP_DigestFinal`
fn finish(&mut self) -> <Self as Digest>::Value;
pub fn finish(mut self) -> Digest {
let mut digest = Digest {
algorithm: self.algorithm,
value: unsafe { mem::uninitialized() },
};
let _ = unsafe {
(self.algorithm.final_)(digest.value.as_mut_ptr(),
self.state.as_mut_ptr())
};
digest
}
/// The algorithm that this context is using.
#[inline(always)]
pub fn algorithm(&self) -> &'static Algorithm { self.algorithm }
}
/// Returns the digest of `data` using the given digest function.
/// Returns the digest of `data` using the given digest algorithm.
///
/// C analog: `EVP_Digest`
///
/// # Examples:
///
@ -74,222 +114,198 @@ pub trait Digest {
/// extern crate rustc_serialize;
///
/// # fn main() {
/// use ring::{digest, Digest, SHA256};
/// use ring::*;
/// use rustc_serialize::hex::FromHex;
///
/// let expected_hex = "09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b";
/// let expected: Vec<u8> = expected_hex.from_hex().unwrap();
/// let actual = digest::<SHA256>("hello, world".as_bytes());
/// let actual = digest::digest(&digest::SHA256, "hello, world".as_bytes());
///
/// assert_eq!(&expected[..], &actual[..]);
/// assert_eq!(&expected, &actual.as_ref());
/// # }
/// ```
///
/// C analog: `EVP_Digest`
pub fn digest<D: Digest>(data: &[u8]) -> <D as Digest>::Value {
let mut ctx = D::new();
pub fn digest(algorithm: &'static Algorithm, data: &[u8]) -> Digest {
let mut ctx = Context::new(algorithm);
ctx.update(data);
ctx.finish()
}
/// A calculated digest value.
///
/// Use `as_ref` to get the value as a `&[u8]`.
pub struct Digest {
algorithm: &'static Algorithm,
value: [u8; MAX_DIGEST_LEN],
}
impl Digest {
/// The algorithm that was used to calculate the digest value.
#[inline(always)]
pub fn algorithm(&self) -> &'static Algorithm { self.algorithm }
}
impl AsRef<[u8]> for Digest {
fn as_ref(&self) -> &[u8] { &self.value[0..self.algorithm.digest_len] }
}
/// A digest algorithm.
///
/// C analog: `EVP_MD`
#[repr(C)]
pub struct Algorithm {
/// C analog: `EVP_MD_size`
pub digest_len: usize,
/// C analog: `EVP_MD_block_size`
pub block_len: usize,
init: unsafe extern fn(ctx_state: *mut u64) -> libc::c_int,
update: unsafe extern fn(ctx_state: *mut u64, data: *const u8,
len: libc::size_t) -> libc::c_int,
final_: unsafe extern fn(out: *mut u8, ctx_state: *mut u64) -> libc::c_int,
// XXX: This is required because the signature verification functions
// require a NID. But, really they don't need a NID, but just the OID of
// the digest function, perhaps with an `EVP_MD` if it wants to validate
// the properties of the digest like the length. XXX: This has to be public
// because it is accessed from the signature modules.
pub nid: libc::c_int,
}
#[cfg(test)]
mod test {
use super::*;
fn test_digest_alg(algorithm: &'static Algorithm,
test_cases: &[(&'static str, u32, &'static str)]) {
use rustc_serialize::hex::FromHex;
for &(data_chunk, repeat, expected_hex) in test_cases {
let expected = expected_hex.from_hex().unwrap();
let mut ctx = Context::new(algorithm);
let mut data = Vec::new();
for _ in 0..repeat {
ctx.update(data_chunk.as_bytes());
data.extend(data_chunk.as_bytes());
}
let actual_from_chunks = ctx.finish();
assert_eq!(&expected, &actual_from_chunks.as_ref());
let actual_from_one_shot = digest(algorithm, &data);
assert_eq!(&expected, &actual_from_one_shot.as_ref());
}
}
#[test]
fn test_md5() {
test_digest_alg(&MD5, &[
// From RFC 1321.
("", 1, "d41d8cd98f00b204e9800998ecf8427e"),
("a", 1, "0cc175b9c0f1b6a831c399e269772661"),
("abc", 1, "900150983cd24fb0d6963f7d28e17f72"),
("message digest", 1, "f96b697d7cb7938d525a2f31aaf161d0"),
("abcdefghijklmnopqrstuvwxyz", 1, "c3fcd3d76192e4007dfb496cca67e13b"),
("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 1,
"d174ab98d277d9f5a5611c2c9f419d9f"),
("1234567890", 8, "57edf4a22be3c955ac49da2e2107b67a"),
]);
}
#[test]
fn test_sha1() {
test_digest_alg(&SHA1, &[
// From RFC 3174.
("abc", 1, "a9993e364706816aba3e25717850c26c9cd0d89d"),
("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 1,
"84983e441c3bd26ebaae4aa1f95129e5e54670f1"),
("a", 1000000, "34aa973cd4c4daa4f61eeb2bdbad27316534016f"),
("0123456701234567012345670123456701234567012345670123456701234567", 10,
"dea356a2cddd90c7a7ecedc5ebb563934f460452"),
]);
}
#[test]
fn test_sha256() {
test_digest_alg(&SHA256, &[
// From NIST.
("abc", 1,
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"),
("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 1,
"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"),
]);
}
#[test]
fn test_sha384() {
test_digest_alg(&SHA384, &[
// From NIST.
("abc", 1,
"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed\
8086072ba1e7cc2358baeca134c825a7"),
("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn\
hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 1,
"09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712\
fcc7c71a557e2db966c3e9fa91746039"),
]);
}
#[test]
fn test_sha512() {
test_digest_alg(&SHA512, &[
// From NIST.
("abc", 1,
"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a\
2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"),
("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn\
hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 1,
"8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018\
501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909"),
]);
}
}
macro_rules! impl_Digest {
($A_name:expr, $a_name:expr, $XXX:ident, $length_in_bits:expr,
$xxx_state_st:ident, $xxx_Init:ident, $xxx_Update:ident, $xxx_Final:ident,
$xxx_DIGEST_LEN:ident, $xxx_tests:ident, $test_xxx:ident,
$xxx_num_test_cases:expr, $xxx_test_cases:expr) => {
($XXX:ident, $digest_len_in_bits:expr, $block_len_in_bits:expr,
$xxx_Init:ident, $xxx_Update:ident, $xxx_Final:ident, $NID_xxx:expr) => {
#[doc="The length, in bytes, of "]
#[doc=$a_name]
#[doc=" digest."]
pub const $xxx_DIGEST_LEN: usize = $length_in_bits / 8;
pub static $XXX: Algorithm = Algorithm {
digest_len: $digest_len_in_bits / 8,
block_len: $block_len_in_bits / 8,
#[doc=$A_name]
#[doc=" digest context that implements the `Digest` trait."]
pub struct $XXX { state: $xxx_state_st }
init: $xxx_Init,
update: $xxx_Update,
final_: $xxx_Final,
impl Digest for $XXX {
type Value = [u8; $xxx_DIGEST_LEN];
/// Constructs a new, initialized `$XXX`.
fn new() -> $XXX {
let mut ctx;
unsafe {
ctx = $XXX { state: mem::uninitialized() };
let _ = $xxx_Init(&mut ctx.state);
}
ctx
}
fn update(&mut self, data: &[u8]) {
unsafe {
let _ = $xxx_Update(&mut self.state, data.as_ptr(),
data.len() as libc::size_t);
}
}
fn finish(&mut self) -> <$XXX as Digest>::Value {
let mut result: <$XXX as Digest>::Value;
unsafe {
result = mem::uninitialized();
let _ = $xxx_Final(result.as_mut_ptr(), &mut self.state);
}
result
}
}
#[cfg(test)]
mod $xxx_tests {
use super::{Digest, digest, $XXX};
#[test]
fn $test_xxx() {
use rustc_serialize::hex::FromHex;
// From NIST:
const TEST_CASES: [(&'static str, u32, &'static str);
$xxx_num_test_cases] =
$xxx_test_cases;
for &(data_chunk, repeat, expected_hex) in TEST_CASES.iter() {
let expected = expected_hex.from_hex().unwrap();
let mut ctx = $XXX::new();
let mut data = Vec::new();
for _ in 0..repeat {
ctx.update(data_chunk.as_bytes());
data.extend(data_chunk.as_bytes());
}
let actual_from_chunks = ctx.finish();
assert_eq!(&expected[..], &actual_from_chunks[..]);
let actual_from_one_shot = digest::<$XXX>(&data);
assert_eq!(&expected[..], &actual_from_one_shot[..]);
}
}
}
nid: $NID_xxx,
};
// Although the called functions all specify a return value, in
// BoringSSL they are always guaranteed to return 1 according to the
// documentation in the header files, so we can safely ignore their
// return values.
extern {
// Although these functions all return a return value, in BoringSSL
// they are always guaranteed to return 1 according to the
// documentation in the header files, so we can safely ignore their
// return values.
fn $xxx_Init(md5: *mut $xxx_state_st) -> libc::c_int;
fn $xxx_Update(md5: *mut $xxx_state_st, data: *const u8,
fn $xxx_Init(ctx_state: *mut u64) -> libc::c_int;
fn $xxx_Update(ctx_state: *mut u64, data: *const u8,
len: libc::size_t) -> libc::c_int;
fn $xxx_Final(md: *mut u8, md5: *mut $xxx_state_st) -> libc::c_int;
fn $xxx_Final(out: *mut u8, ctx_state: *mut u64) -> libc::c_int;
}
}
}
impl_Digest!("An MD5", "an MD5", MD5, 128, md5_state_st, MD5_Init, MD5_Update,
MD5_Final, MD5_DIGEST_LEN, md5_tests, test_md5, 7, [
// From RFC 1321.
("", 1, "d41d8cd98f00b204e9800998ecf8427e"),
("a", 1, "0cc175b9c0f1b6a831c399e269772661"),
("abc", 1, "900150983cd24fb0d6963f7d28e17f72"),
("message digest", 1, "f96b697d7cb7938d525a2f31aaf161d0"),
("abcdefghijklmnopqrstuvwxyz", 1, "c3fcd3d76192e4007dfb496cca67e13b"),
("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 1,
"d174ab98d277d9f5a5611c2c9f419d9f"),
("1234567890", 8, "57edf4a22be3c955ac49da2e2107b67a"),
]);
impl_Digest!(MD5, 128, 512, MD5_Init, MD5_Update, MD5_Final, 4 /*NID_md5*/);
impl_Digest!(SHA1, 160, 512, SHA1_Init, SHA1_Update, SHA1_Final,
64 /*NID_sha1*/);
impl_Digest!(SHA256, 256, 512, SHA256_Init, SHA256_Update, SHA256_Final,
672 /*NID_sha256*/);
impl_Digest!(SHA384, 384, 1024, SHA384_Init, SHA384_Update, SHA384_Final,
673 /*NID_sha384*/);
impl_Digest!(SHA512, 512, 1024, SHA512_Init, SHA512_Update, SHA512_Final,
674 /*NID_sha512*/);
impl_Digest!("A SHA-1", "a SHA-1", SHA1, 160, sha_state_st, SHA1_Init,
SHA1_Update, SHA1_Final, SHA1_DIGEST_LEN, sha1_tests, test_sha1,
4, [
// From RFC 3174.
("abc", 1, "a9993e364706816aba3e25717850c26c9cd0d89d"),
("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 1,
"84983e441c3bd26ebaae4aa1f95129e5e54670f1"),
("a", 1000000, "34aa973cd4c4daa4f61eeb2bdbad27316534016f"),
("0123456701234567012345670123456701234567012345670123456701234567", 10,
"dea356a2cddd90c7a7ecedc5ebb563934f460452"),
]);
const MAX_DIGEST_LEN: usize = 512 / 8;
impl_Digest!("A SHA-256", "a SHA-256", SHA256, 256, sha256_state_st,
SHA256_Init, SHA256_Update, SHA256_Final, SHA256_DIGEST_LEN,
sha256_tests, test_sha256, 2, [
// From NIST.
("abc", 1,
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"),
("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 1,
"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"),
]);
impl_Digest!("A SHA-384", "a SHA-384", SHA384, 384, sha512_state_st,
SHA384_Init, SHA384_Update, SHA384_Final, SHA384_DIGEST_LEN,
sha384_tests, test_sha384, 2, [
// From NIST.
("abc", 1,
"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed\
8086072ba1e7cc2358baeca134c825a7"),
("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn\
hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 1,
"09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712\
fcc7c71a557e2db966c3e9fa91746039"),
]);
impl_Digest!("A SHA-512", "a SHA-512", SHA512, 512, sha512_state_st,
SHA512_Init, SHA512_Update, SHA512_Final, SHA512_DIGEST_LEN,
sha512_tests, test_sha512, 2, [
// From NIST.
("abc", 1,
"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a\
2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"),
("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn\
hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 1,
"8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018\
501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909"),
]);
// TODO: find a better way to keep the C and Rust struct definitions in sync.
#[allow(non_snake_case)]
#[repr(C)]
struct md5_state_st {
A: libc::uint32_t,
B: libc::uint32_t,
C: libc::uint32_t,
D: libc::uint32_t,
Nl: libc::uint32_t,
Nh: libc::uint32_t,
data: [libc::uint32_t; 16],
num: libc::c_uint
}
#[allow(non_snake_case)]
#[repr(C)]
struct sha_state_st {
h0: libc::uint32_t,
h1: libc::uint32_t,
h2: libc::uint32_t,
h3: libc::uint32_t,
h4: libc::uint32_t,
Nl: libc::uint32_t,
Nh: libc::uint32_t,
data: [libc::uint32_t; 16],
num: libc::c_uint
}
#[repr(C)]
#[allow(non_snake_case)]
struct sha256_state_st {
h: [libc::uint32_t; 8],
Nl: libc::uint32_t,
Nh: libc::uint32_t,
data: [libc::uint32_t; 16],
num: libc::c_uint,
md_len: libc::c_uint,
}
#[repr(C)]
#[allow(non_snake_case)]
struct sha512_state_st {
h: [libc::uint64_t; 8],
Nl: libc::uint64_t,
Nh: libc::uint64_t,
u_d: [libc::uint64_t; 16], // union { uint64_t d[16]; uint8_t p[128]; } u;
num: libc::c_uint,
md_len: libc::c_uint,
}
// The number of u64-sized words needed to store the largest digest context
// state.
const DIGEST_CONTEXT_STATE_U64_COUNT: usize = 28;

View File

@ -15,7 +15,7 @@
//! Elliptic curve cryptography.
use libc;
use super::ffi;
use super::{digest, ffi};
/// An elliptic curve. See `CURVE_P256`, `CURVE_P256`, and `CURVE_521`.
///
@ -46,11 +46,11 @@ pub static CURVE_P521: EllipticCurve = EllipticCurve { nid: 716 };
/// C analogs: `ECDSA_verify_pkcs1_signed_digest` (*ring* only),
/// `EC_POINT_oct2point` with `ECDSA_verify`.
pub fn verify_ecdsa_signed_digest_asn1(curve: &EllipticCurve,
digest: &[u8], sig: &[u8], key: &[u8])
-> Result<(),()> {
digest: &digest::Digest, sig: &[u8],
key: &[u8]) -> Result<(),()> {
ffi::map_bssl_result(unsafe {
ECDSA_verify_signed_digest(0, digest.as_ptr(),
digest.len() as libc::size_t,
ECDSA_verify_signed_digest(0, digest.as_ref().as_ptr(),
digest.as_ref().len() as libc::size_t,
sig.as_ptr(), sig.len() as libc::size_t,
curve.nid, key.as_ptr(),
key.len() as libc::size_t)

View File

@ -17,21 +17,8 @@ extern crate libc;
#[cfg(test)]
extern crate rustc_serialize;
// All code belongs in submodules, not in lib.rs. The public interface of all
// submodules is re-exported from this one, and users are expected to use this
// module instead of the submodules.
mod digest;
pub use digest::{
Digest, digest,
MD5, MD5_DIGEST_LEN,
SHA1, SHA1_DIGEST_LEN,
SHA256, SHA256_DIGEST_LEN,
SHA384, SHA384_DIGEST_LEN,
SHA512, SHA512_DIGEST_LEN,
};
mod ffi;
pub mod digest;
pub mod ecc;
mod ffi;
pub mod rand;
mod rsa;
pub mod rsa;

View File

@ -15,31 +15,7 @@
//! RSA signing and verification.
use libc;
/// Identifies a digest algorithm used in a signature.
#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(C)]
pub enum SignatureDigestAlgorithm {
/// SHA-1.
///
/// C analog: `NID_sha1`
SHA1 = 64,
/// SHA-256.
///
/// C analog: `NID_sha256'
SHA256 = 672,
/// SHA-384.
///
/// C analog: `NID_sha384'
SHA384 = 673,
/// SHA-512.
///
/// C analog: `NID_sha512'
SHA512 = 674,
}
use super::digest;
/// Verifies that the PKCS#1 1.5 RSA signature encoded in `sig` is valid for
/// the data hashed to `digest` using the ASN.1-DER-encoded public key `key`.
@ -47,14 +23,13 @@ pub enum SignatureDigestAlgorithm {
/// C analogs: `RSA_verify_pkcs1_signed_digest` (*ring* only),
/// `RSA_public_key_from_bytes` + `RSA_verify` (*ring* and BoringSSL),
/// `d2i_RSAPublicKey` + `RSA_verify`.
pub fn verify_rsa_pkcs1_signed_digest_asn1(
digest_alg: SignatureDigestAlgorithm, digest: &[u8], sig: &[u8],
key: &[u8]) -> Result<(),()> {
pub fn verify_rsa_pkcs1_signed_digest_asn1(digest: &digest::Digest, sig: &[u8],
key: &[u8]) -> Result<(),()> {
let x;
unsafe {
x = RSA_verify_pkcs1_signed_digest(digest_alg as libc::c_int,
digest.as_ptr(),
digest.len() as libc::size_t,
x = RSA_verify_pkcs1_signed_digest(digest.algorithm().nid,
digest.as_ref().as_ptr(),
digest.as_ref().len() as libc::size_t,
sig.as_ptr(),
sig.len() as libc::size_t,
key.as_ptr(),