Skip to content

Commit

Permalink
Merge pull request #228 from vlmutolo/io-traits
Browse files Browse the repository at this point in the history
impl standard IO traits for hashing
  • Loading branch information
vlmutolo authored Jan 19, 2022
2 parents 80baae0 + 848bf66 commit ec24ade
Show file tree
Hide file tree
Showing 5 changed files with 308 additions and 1 deletion.
65 changes: 65 additions & 0 deletions src/hazardous/hash/blake2/blake2b.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ use crate::errors::UnknownCryptoError;
use crate::hazardous::hash::blake2::blake2b_core;
use crate::hazardous::hash::blake2::blake2b_core::BLAKE2B_OUTSIZE;

#[cfg(feature = "safe_api")]
use std::io;

construct_public! {
/// A type to represent the `Digest` that BLAKE2b returns.
///
Expand Down Expand Up @@ -148,6 +151,48 @@ impl Hasher {
}
}

#[cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
/// Example: custom digest size.
/// ```rust
/// use orion::{
/// hazardous::hash::blake2::blake2b::{Blake2b, Digest},
/// errors::UnknownCryptoError,
/// };
/// use std::io::{self, Read, Write};
///
/// // `reader` could also be a `File::open(...)?`.
/// let mut reader = io::Cursor::new(b"some data");
/// let mut hasher = Blake2b::new(64)?; // 512-bit hash
/// std::io::copy(&mut reader, &mut hasher)?;
///
/// let digest: Digest = hasher.finalize()?;
///
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
#[cfg(feature = "safe_api")]
impl io::Write for Blake2b {
/// Update the hasher's internal state with *all* of the bytes given.
/// If this function returns the `Ok` variant, it's guaranteed that it
/// will contain the length of the buffer passed to [`Write`](std::io::Write).
/// Note that this function is just a small wrapper over
/// [`Blake2b::update`](crate::hazardous::hash::blake2::blake2b::Blake2b::update).
///
/// ## Errors:
/// This function will only ever return the [`std::io::ErrorKind::Other`]()
/// variant when it returns an error. Additionally, this will always contain Orion's
/// [`UnknownCryptoError`](crate::errors::UnknownCryptoError) type.
fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
self.update(bytes)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
Ok(bytes.len())
}

/// This type doesn't buffer writes, so flushing is a no-op.
fn flush(&mut self) -> Result<(), std::io::Error> {
Ok(())
}
}

#[cfg(test)]
mod public {
mod test_streaming_interface_no_key {
Expand Down Expand Up @@ -344,4 +389,24 @@ mod public {
assert!(Blake2b::new(64).is_ok());
}
}

#[cfg(feature = "safe_api")]
mod test_io_impls {
use crate::hazardous::hash::blake2::blake2b::Blake2b;
use std::io::Write;

#[quickcheck]
fn prop_hasher_write_same_as_update(data: Vec<u8>) -> bool {
let mut hasher_a = Blake2b::new(64).unwrap();
let mut hasher_b = hasher_a.clone();

hasher_a.update(&data).unwrap();
hasher_b.write_all(&data).unwrap();

let hash_a = hasher_a.finalize().unwrap();
let hash_b = hasher_b.finalize().unwrap();

hash_a == hash_b
}
}
}
65 changes: 65 additions & 0 deletions src/hazardous/hash/sha2/sha256.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@
use crate::errors::UnknownCryptoError;

#[cfg(feature = "safe_api")]
use std::io;

/// The blocksize for the hash function SHA256.
pub const SHA256_BLOCKSIZE: usize = 64;
/// The output size for the hash function SHA256.
Expand Down Expand Up @@ -229,6 +232,48 @@ impl crate::hazardous::mac::hmac::HmacHashFunction for Sha256 {
}
}

#[cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
/// Example: hashing from a [`Read`](std::io::Read)er with SHA256.
/// ```rust
/// use orion::{
/// hazardous::hash::sha2::sha256::{Sha256, Digest},
/// errors::UnknownCryptoError,
/// };
/// use std::io::{self, Read, Write};
///
/// // `reader` could also be a `File::open(...)?`.
/// let mut reader = io::Cursor::new(b"some data");
/// let mut hasher = Sha256::new();
/// std::io::copy(&mut reader, &mut hasher)?;
///
/// let digest: Digest = hasher.finalize()?;
///
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
#[cfg(feature = "safe_api")]
impl io::Write for Sha256 {
/// Update the hasher's internal state with *all* of the bytes given.
/// If this function returns the `Ok` variant, it's guaranteed that it
/// will contain the length of the buffer passed to [`Write`](std::io::Write).
/// Note that this function is just a small wrapper over
/// [`Sha256::update`](crate::hazardous::hash::sha2::sha256::Sha256::update).
///
/// ## Errors:
/// This function will only ever return the [`std::io::ErrorKind::Other`]()
/// variant when it returns an error. Additionally, this will always contain Orion's
/// [`UnknownCryptoError`](crate::errors::UnknownCryptoError) type.
fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
self.update(bytes)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
Ok(bytes.len())
}

/// This type doesn't buffer writes, so flushing is a no-op.
fn flush(&mut self) -> Result<(), std::io::Error> {
Ok(())
}
}

// Testing public functions in the module.
#[cfg(test)]
mod public {
Expand Down Expand Up @@ -313,6 +358,26 @@ mod public {
true
}
}

#[cfg(feature = "safe_api")]
mod test_io_impls {
use crate::hazardous::hash::sha2::sha256::Sha256;
use std::io::Write;

#[quickcheck]
fn prop_hasher_write_same_as_update(data: Vec<u8>) -> bool {
let mut hasher_a = Sha256::new();
let mut hasher_b = hasher_a.clone();

hasher_a.update(&data).unwrap();
hasher_b.write_all(&data).unwrap();

let hash_a = hasher_a.finalize().unwrap();
let hash_b = hasher_b.finalize().unwrap();

hash_a == hash_b
}
}
}

// Testing private functions in the module.
Expand Down
65 changes: 65 additions & 0 deletions src/hazardous/hash/sha2/sha384.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@
use crate::errors::UnknownCryptoError;

#[cfg(feature = "safe_api")]
use std::io;

construct_public! {
/// A type to represent the `Digest` that SHA384 returns.
///
Expand Down Expand Up @@ -209,6 +212,48 @@ impl crate::hazardous::mac::hmac::HmacHashFunction for Sha384 {
}
}

#[cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
/// Example: hashing from a [`Read`](std::io::Read)er with SHA384.
/// ```rust
/// use orion::{
/// hazardous::hash::sha2::sha384::{Sha384, Digest},
/// errors::UnknownCryptoError,
/// };
/// use std::io::{self, Read, Write};
///
/// // `reader` could also be a `File::open(...)?`.
/// let mut reader = io::Cursor::new(b"some data");
/// let mut hasher = Sha384::new();
/// std::io::copy(&mut reader, &mut hasher)?;
///
/// let digest: Digest = hasher.finalize()?;
///
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
#[cfg(feature = "safe_api")]
impl io::Write for Sha384 {
/// Update the hasher's internal state with *all* of the bytes given.
/// If this function returns the `Ok` variant, it's guaranteed that it
/// will contain the length of the buffer passed to [`Write`](std::io::Write).
/// Note that this function is just a small wrapper over
/// [`Sha384::update`](crate::hazardous::hash::sha2::sha384::Sha384::update).
///
/// ## Errors:
/// This function will only ever return the [`std::io::ErrorKind::Other`]()
/// variant when it returns an error. Additionally, this will always contain Orion's
/// [`UnknownCryptoError`](crate::errors::UnknownCryptoError) type.
fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
self.update(bytes)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
Ok(bytes.len())
}

/// This type doesn't buffer writes, so flushing is a no-op.
fn flush(&mut self) -> Result<(), std::io::Error> {
Ok(())
}
}

// Testing public functions in the module.
#[cfg(test)]
mod public {
Expand Down Expand Up @@ -293,6 +338,26 @@ mod public {
true
}
}

#[cfg(feature = "safe_api")]
mod test_io_impls {
use crate::hazardous::hash::sha2::sha384::Sha384;
use std::io::Write;

#[quickcheck]
fn prop_hasher_write_same_as_update(data: Vec<u8>) -> bool {
let mut hasher_a = Sha384::new();
let mut hasher_b = hasher_a.clone();

hasher_a.update(&data).unwrap();
hasher_b.write_all(&data).unwrap();

let hash_a = hasher_a.finalize().unwrap();
let hash_b = hasher_b.finalize().unwrap();

hash_a == hash_b
}
}
}

// Testing private functions in the module.
Expand Down
65 changes: 65 additions & 0 deletions src/hazardous/hash/sha2/sha512.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@
use crate::errors::UnknownCryptoError;

#[cfg(feature = "safe_api")]
use std::io;

construct_public! {
/// A type to represent the `Digest` that SHA512 returns.
///
Expand Down Expand Up @@ -232,6 +235,48 @@ impl crate::hazardous::mac::hmac::HmacHashFunction for Sha512 {
}
}

#[cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
/// Example: hashing from a [`Read`](std::io::Read)er with SHA512.
/// ```rust
/// use orion::{
/// hazardous::hash::sha2::sha512::{Sha512, Digest},
/// errors::UnknownCryptoError,
/// };
/// use std::io::{self, Read, Write};
///
/// // `reader` could also be a `File::open(...)?`.
/// let mut reader = io::Cursor::new(b"some data");
/// let mut hasher = Sha512::new();
/// std::io::copy(&mut reader, &mut hasher)?;
///
/// let digest: Digest = hasher.finalize()?;
///
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
#[cfg(feature = "safe_api")]
impl io::Write for Sha512 {
/// Update the hasher's internal state with *all* of the bytes given.
/// If this function returns the `Ok` variant, it's guaranteed that it
/// will contain the length of the buffer passed to [`Write`](std::io::Write).
/// Note that this function is just a small wrapper over
/// [`Sha512::update`](crate::hazardous::hash::sha2::sha512::Sha512::update).
///
/// ## Errors:
/// This function will only ever return the [`std::io::ErrorKind::Other`]()
/// variant when it returns an error. Additionally, this will always contain Orion's
/// [`UnknownCryptoError`](crate::errors::UnknownCryptoError) type.
fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
self.update(bytes)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
Ok(bytes.len())
}

/// This type doesn't buffer writes, so flushing is a no-op.
fn flush(&mut self) -> Result<(), std::io::Error> {
Ok(())
}
}

// Testing public functions in the module.
#[cfg(test)]
mod public {
Expand Down Expand Up @@ -316,6 +361,26 @@ mod public {
true
}
}

#[cfg(feature = "safe_api")]
mod test_io_impls {
use crate::hazardous::hash::sha2::sha512::Sha512;
use std::io::Write;

#[quickcheck]
fn prop_hasher_write_same_as_update(data: Vec<u8>) -> bool {
let mut hasher_a = Sha512::new();
let mut hasher_b = hasher_a.clone();

hasher_a.update(&data).unwrap();
hasher_b.write_all(&data).unwrap();

let hash_a = hasher_a.finalize().unwrap();
let hash_b = hasher_b.finalize().unwrap();

hash_a == hash_b
}
}
}

// Testing private functions in the module.
Expand Down
Loading

0 comments on commit ec24ade

Please sign in to comment.