Adds functionality for instantiating and using `Algorithm` This CL moves some methods that exist in every hashing algorithm implementation to the `Algorithm` trait; namely, `new`, `update`, and `digest`. This allows for clients to instantiate the hashing algorithms, and to call `update` and `digest` on objects that have this trait. It allows a generic representation of an algorithm that can be used. This CL also adds the block size as a const field in the `Algorithm` trait. Note: this specifically supports the hashing algorithm use in the style of what is done in AOSP's `packages/modules/Virtualization/libs/apkverify`, which was previously using the rust openssl `Hasher` to instantiate algorithms specified by their `MessageDigest`. Change-Id: Ic47691ee2a4303923519b246de7d9724da90f60d Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/68748 Commit-Queue: Ellen Arteca <emarteca@google.com> Commit-Queue: Adam Langley <agl@google.com> Reviewed-by: Adam Langley <agl@google.com>
diff --git a/rust/bssl-crypto/src/digest.rs b/rust/bssl-crypto/src/digest.rs index 645ab80..125f427 100644 --- a/rust/bssl-crypto/src/digest.rs +++ b/rust/bssl-crypto/src/digest.rs
@@ -45,6 +45,8 @@ pub trait Algorithm { /// The size of the resulting digest. const OUTPUT_LEN: usize; + /// The block length (in bytes). + const BLOCK_LEN: usize; /// Gets a reference to a message digest algorithm to be used by the HKDF implementation. #[doc(hidden)] @@ -52,6 +54,23 @@ /// Hashes a message. fn hash_to_vec(input: &[u8]) -> Vec<u8>; + + /// Create a new context for incremental hashing. + fn new() -> Self; + + /// Hash the contents of `input`. + fn update(&mut self, input: &[u8]); + + /// Finish the hashing and return the digest. + fn digest_to_vec(mut self) -> Vec<u8>; +} + +/// Trait parameterized by the size of the output of the digest +/// so that it can provide algorithm functions that depend on +/// this parameter. +pub trait WithOutputLength<const OUTPUT_LEN: usize> { + /// Finish the hashing and return the digest. + fn digest(mut self) -> [u8; OUTPUT_LEN]; } /// The insecure SHA-1 hash algorithm. @@ -67,6 +86,7 @@ unsafe_iuf_algo!( InsecureSha1, 20, + 64, EVP_sha1, SHA1, SHA1_Init, @@ -83,6 +103,7 @@ unsafe_iuf_algo!( Sha256, 32, + 64, EVP_sha256, SHA256, SHA256_Init, @@ -99,6 +120,7 @@ unsafe_iuf_algo!( Sha384, 48, + 128, EVP_sha384, SHA384, SHA384_Init, @@ -115,6 +137,7 @@ unsafe_iuf_algo!( Sha512, 64, + 128, EVP_sha512, SHA512, SHA512_Init, @@ -131,6 +154,7 @@ unsafe_iuf_algo!( Sha512_256, 32, + 128, EVP_sha512_256, SHA512_256, SHA512_256_Init,
diff --git a/rust/bssl-crypto/src/macros.rs b/rust/bssl-crypto/src/macros.rs index 6ac3d37..0d49646 100644 --- a/rust/bssl-crypto/src/macros.rs +++ b/rust/bssl-crypto/src/macros.rs
@@ -22,9 +22,10 @@ // Safety: see the "Safety" sections within about the requirements for the // functions named in the macro parameters. macro_rules! unsafe_iuf_algo { - ($name:ident, $output_len:expr, $evp_md:ident, $one_shot:ident, $init:ident, $update:ident, $final_func:ident) => { + ($name:ident, $output_len:expr, $block_len:expr, $evp_md:ident, $one_shot:ident, $init:ident, $update:ident, $final_func:ident) => { impl Algorithm for $name { const OUTPUT_LEN: usize = $output_len as usize; + const BLOCK_LEN: usize = $block_len as usize; fn get_md(_: sealed::Sealed) -> &'static MdRef { // Safety: @@ -35,6 +36,45 @@ fn hash_to_vec(input: &[u8]) -> Vec<u8> { Self::hash(input).as_slice().to_vec() } + + /// Create a new context for incremental hashing. + fn new() -> Self { + unsafe { + Self { + ctx: crate::initialized_struct(|ctx| { + // Safety: type checking will ensure that `ctx` is the + // correct type for `$init` to write into. + bssl_sys::$init(ctx); + }), + } + } + } + + /// Hash the contents of `input`. + fn update(&mut self, input: &[u8]) { + // Safety: arguments point to a valid buffer. + unsafe { + bssl_sys::$update(&mut self.ctx, input.as_ffi_void_ptr(), input.len()); + } + } + + /// Finish the hashing and return the digest. + fn digest_to_vec(mut self) -> alloc::vec::Vec<u8> { + WithOutputLength::<$output_len>::digest(self).to_vec() + } + } + + impl<const OUTPUT_LEN: usize> WithOutputLength<OUTPUT_LEN> for $name { + /// Finish the hashing and return the digest. + fn digest(mut self) -> [u8; OUTPUT_LEN] { + // Safety: it is assumed that `$final_func` indeed writes + // `$output_len` bytes. + unsafe { + crate::with_output_array(|out, _| { + bssl_sys::$final_func(out, &mut self.ctx); + }) + } + } } impl $name { @@ -48,38 +88,6 @@ }) } } - - /// Create a new context for incremental hashing. - pub fn new() -> Self { - unsafe { - Self { - ctx: crate::initialized_struct(|ctx| { - // Safety: type checking will ensure that `ctx` is the - // correct type for `$init` to write into. - bssl_sys::$init(ctx); - }), - } - } - } - - /// Hash the contents of `input`. - pub fn update(&mut self, input: &[u8]) { - // Safety: arguments point to a valid buffer. - unsafe { - bssl_sys::$update(&mut self.ctx, input.as_ffi_void_ptr(), input.len()); - } - } - - /// Finish the hashing and return the digest. - pub fn digest(mut self) -> [u8; $output_len] { - // Safety: it is assumed that `$final_func` indeed writes - // `$output_len` bytes. - unsafe { - crate::with_output_array(|out, _| { - bssl_sys::$final_func(out, &mut self.ctx); - }) - } - } } impl From<$name> for [u8; $output_len] { @@ -90,7 +98,7 @@ impl From<$name> for alloc::vec::Vec<u8> { fn from(ctx: $name) -> alloc::vec::Vec<u8> { - ctx.digest().into() + ctx.digest_to_vec() } }