Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

impl standard IO traits for hashing #228

Merged
merged 4 commits into from
Jan 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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>>(())
/// ```
vlmutolo marked this conversation as resolved.
Show resolved Hide resolved
#[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