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()
}
}