diff options
author | Wiktor Kwapisiewicz <wiktor@metacode.biz> | 2022-10-03 11:51:41 +0200 |
---|---|---|
committer | Wiktor Kwapisiewicz <wiktor@metacode.biz> | 2022-12-22 12:46:08 +0100 |
commit | 0d0d757f90b8b49010f998435a7e295cc0719ed2 (patch) | |
tree | e064d21b27c08b7e3371a5e51e30ba92da999381 /openpgp/src/crypto/backend/openssl/hash.rs | |
parent | 31564c1c6e5b5ff4ff3596bb755ba2f7395f83df (diff) |
openpgp: Add OpenSSL cryptographic backend.
- Adds the backend behind `crypto-openssl` feature.
- Add CI configuration to run tests with the new backend.
- See #333.
Diffstat (limited to 'openpgp/src/crypto/backend/openssl/hash.rs')
-rw-r--r-- | openpgp/src/crypto/backend/openssl/hash.rs | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/openpgp/src/crypto/backend/openssl/hash.rs b/openpgp/src/crypto/backend/openssl/hash.rs new file mode 100644 index 00000000..c379ac2e --- /dev/null +++ b/openpgp/src/crypto/backend/openssl/hash.rs @@ -0,0 +1,99 @@ +use crate::crypto::hash::Digest; +use crate::types::HashAlgorithm; +use crate::Result; + +use openssl::error::ErrorStack; +use openssl::hash::{Hasher, MessageDigest}; +use openssl::nid::Nid; + +#[derive(Clone)] +struct OpenSslDigest { + digest_size: usize, + algo: HashAlgorithm, + hasher: Hasher, + update_result: std::result::Result<(), ErrorStack>, +} + +impl OpenSslDigest { + fn new(algo: HashAlgorithm) -> Result<Self> { + if let Some(md) = get_md(algo) { + Ok(Self { + digest_size: md.size(), + algo, + update_result: Ok(()), + hasher: Hasher::new(md)?, + }) + } else { + Err(crate::Error::UnsupportedHashAlgorithm(algo).into()) + } + } +} + +impl Digest for OpenSslDigest { + fn algo(&self) -> HashAlgorithm { + self.algo + } + + fn digest_size(&self) -> usize { + self.digest_size + } + + fn update(&mut self, data: &[u8]) { + if self.update_result.is_ok() { + self.update_result = self.hasher.update(data); + } + } + + fn digest(&mut self, digest: &mut [u8]) -> Result<()> { + self.update_result.clone()?; + let result = self.hasher.finish()?; + digest.copy_from_slice(&result[..digest.len()]); + 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<()> { + // Do nothing. + Ok(()) + } +} + +fn get_md(algo: HashAlgorithm) -> Option<MessageDigest> { + use HashAlgorithm::*; + let nid = match algo { + MD5 => Nid::MD5, + RipeMD => Nid::RIPEMD160, + SHA1 => Nid::SHA1, + SHA256 => Nid::SHA256, + SHA384 => Nid::SHA384, + SHA512 => Nid::SHA512, + SHA224 => Nid::SHA224, + _ => return None, + }; + MessageDigest::from_nid(nid) +} + +impl HashAlgorithm { + /// Whether Sequoia supports this algorithm. + pub fn is_supported(self) -> bool { + get_md(self).is_some() + } + + /// Creates a new hash context for this algorithm. + /// + /// # Errors + /// + /// Fails with `Error::UnsupportedHashAlgorithm` if Sequoia does + /// not support this algorithm. See + /// [`HashAlgorithm::is_supported`]. + /// + /// [`HashAlgorithm::is_supported`]: HashAlgorithm::is_supported() + pub(crate) fn new_hasher(self) -> Result<Box<dyn Digest>> { + Ok(Box::new(OpenSslDigest::new(self)?)) + } +} |