use crate::crypto::hash::Digest;
use crate::types::HashAlgorithm;
use crate::Result;
use ossl::digest::{DigestAlg, OsslDigest};
impl TryFrom<HashAlgorithm> for DigestAlg {
type Error = crate::Error;
fn try_from(a: HashAlgorithm) -> std::result::Result<Self, Self::Error> {
match a {
HashAlgorithm::MD5 => Ok(DigestAlg::Md5),
HashAlgorithm::SHA1 => Ok(DigestAlg::Sha1),
HashAlgorithm::SHA256 => Ok(DigestAlg::Sha2_256),
HashAlgorithm::SHA384 => Ok(DigestAlg::Sha2_384),
HashAlgorithm::SHA512 => Ok(DigestAlg::Sha2_512),
HashAlgorithm::SHA224 => Ok(DigestAlg::Sha2_224),
HashAlgorithm::SHA3_256 => Ok(DigestAlg::Sha3_256),
HashAlgorithm::SHA3_512 => Ok(DigestAlg::Sha3_512),
HashAlgorithm::Private(_)
| HashAlgorithm::Unknown (_)
| HashAlgorithm::RipeMD
=> Err(crate::Error::UnsupportedHashAlgorithm(a)),
}
}
}
struct OpenSslDigest {
digest: OsslDigest,
digest_size: usize,
update_result: std::result::Result<(), ossl::Error>,
}
impl Clone for OpenSslDigest {
fn clone(&self) -> Self {
Self {
digest: self.digest.try_clone()
.expect("Sequoia requires clone to succeed"),
digest_size: self.digest_size,
update_result: self.update_result.clone(),
}
}
}
impl OpenSslDigest {
fn new(algo: HashAlgorithm) -> Result<Self> {
let ctx = super::context();
Ok(Self {
digest: OsslDigest::new(&ctx, algo.try_into()?, None)?,
digest_size: algo.digest_size()?,
update_result: Ok(()),
})
}
}
impl Digest for OpenSslDigest {
fn update(&mut self, data: &[u8]) {
if self.update_result.is_ok() {
self.update_result = self.digest.update(data);
}
}
fn digest(&mut self, digest: &mut [u8]) -> Result<()> {
self.update_result.clone()?;
let mut buf = vec![0; self.digest_size];
self.digest.finalize(&mut buf)?;
let l = digest.len().min(buf.len());
digest[..l].copy_from_slice(&buf[..l]);
Ok(())
}
}
impl std::io::Write for OpenSslDigest {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.update(buf);
Ok(buf.len())
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
impl HashAlgorithm {
pub fn is_supported(self) -> bool {
OpenSslDigest::new(self).is_ok()
}
pub(crate) fn new_hasher(self) -> Result<Box<dyn Digest>> {
Ok(Box::new(OpenSslDigest::new(self)?))
}
}