xdoc-rs 0.1.1

Declarative XML engine for Rust
Documentation
use sha2::{Digest, Sha256, Sha512};

use crate::core::XmlResult;

use super::base64::encode_standard_base64;
use super::DigestAlgorithm;

/// Computes a digest for signature generation.
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"),
    }
}

/// Computes a digest and encodes it as standard Base64.
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"));
    }
}