use sha2::{Digest, Sha256, Sha512};
use crate::core::XmlResult;
use super::base64::encode_standard_base64;
use super::DigestAlgorithm;
pub fn digest_bytes(algorithm: DigestAlgorithm, input: impl AsRef<[u8]>) -> XmlResult<Vec<u8>> {
algorithm.ensure_allowed_for_generation()?;
match algorithm {
DigestAlgorithm::Sha256 => Ok(Sha256::digest(input).to_vec()),
DigestAlgorithm::Sha512 => Ok(Sha512::digest(input).to_vec()),
DigestAlgorithm::Sha1 => unreachable!("SHA-1 is rejected before digesting"),
}
}
pub fn digest_base64(algorithm: DigestAlgorithm, input: impl AsRef<[u8]>) -> XmlResult<String> {
digest_bytes(algorithm, input).map(encode_standard_base64)
}
#[cfg(test)]
mod tests {
use crate::core::ErrorKind;
use super::*;
#[test]
fn signature_digest_computes_sha256_known_vector() {
let digest = digest_bytes(DigestAlgorithm::Sha256, b"abc").expect("sha256 digest");
assert_eq!(
digest,
vec![
0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae,
0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61,
0xf2, 0x00, 0x15, 0xad,
]
);
}
#[test]
fn signature_digest_encodes_sha256_base64() {
let digest = digest_base64(DigestAlgorithm::Sha256, b"abc").expect("sha256 digest");
assert_eq!(digest, "ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0=");
}
#[test]
fn signature_digest_encodes_sha512_base64() {
let digest = digest_base64(DigestAlgorithm::Sha512, b"abc").expect("sha512 digest");
assert_eq!(
digest,
"3a81oZNherrMQXNJriBBMRLm+k6JqX6iCp7u5ktV05ohkpkqJ0/BqDa6PCOj/uu9RU1EI2Q86A4qmslPpUyknw=="
);
}
#[test]
fn signature_digest_rejects_sha1_for_generation() {
let error = digest_bytes(DigestAlgorithm::Sha1, b"abc").expect_err("sha1 must be rejected");
assert_eq!(error.kind(), &ErrorKind::Signature);
assert!(error.message().contains("SHA-1"));
}
}