http-signature-normalization-actix 0.11.3

An HTTP Signatures library that leaves the signing to you
Documentation
//! Types for creating digests with the `ring` cryptography library

use crate::digest::DigestName;

/// A Sha256 digest backed by ring
#[derive(Clone)]
pub struct Sha256 {
    ctx: ring::digest::Context,
}

/// A Sha384 digest backed by ring
#[derive(Clone)]
pub struct Sha384 {
    ctx: ring::digest::Context,
}

/// A Sha512 digest backed by ring
#[derive(Clone)]
pub struct Sha512 {
    ctx: ring::digest::Context,
}

impl Sha256 {
    /// Create a new empty digest
    pub fn new() -> Self {
        Self::default()
    }

    /// Extract the context
    pub fn into_inner(self) -> ring::digest::Context {
        self.ctx
    }
}

impl Default for Sha256 {
    fn default() -> Self {
        Sha256 {
            ctx: ring::digest::Context::new(&ring::digest::SHA256),
        }
    }
}

impl Sha384 {
    /// Create a new empty digest
    pub fn new() -> Self {
        Self::default()
    }

    /// Extract the context
    pub fn into_inner(self) -> ring::digest::Context {
        self.ctx
    }
}

impl Default for Sha384 {
    fn default() -> Self {
        Sha384 {
            ctx: ring::digest::Context::new(&ring::digest::SHA384),
        }
    }
}

impl Sha512 {
    /// Create a new empty digest
    pub fn new() -> Self {
        Self::default()
    }

    /// Extract the context
    pub fn into_inner(self) -> ring::digest::Context {
        self.ctx
    }
}

impl Default for Sha512 {
    fn default() -> Self {
        Sha512 {
            ctx: ring::digest::Context::new(&ring::digest::SHA512),
        }
    }
}

impl DigestName for Sha256 {
    const NAME: &'static str = "SHA-256";
}

impl DigestName for Sha384 {
    const NAME: &'static str = "SHA-384";
}

impl DigestName for Sha512 {
    const NAME: &'static str = "SHA-512";
}

#[cfg(feature = "client")]
mod client {
    use super::*;
    use crate::digest::DigestCreate;
    use base64::prelude::*;

    fn create(mut context: ring::digest::Context, input: &[u8]) -> String {
        context.update(input);
        let digest = context.finish();
        BASE64_STANDARD.encode(digest.as_ref())
    }

    impl DigestCreate for Sha256 {
        fn compute(&mut self, input: &[u8]) -> String {
            create(self.ctx.clone(), input)
        }
    }

    impl DigestCreate for Sha384 {
        fn compute(&mut self, input: &[u8]) -> String {
            create(self.ctx.clone(), input)
        }
    }

    impl DigestCreate for Sha512 {
        fn compute(&mut self, input: &[u8]) -> String {
            create(self.ctx.clone(), input)
        }
    }
}

#[cfg(feature = "server")]
mod server {
    use super::*;
    use crate::digest::{DigestPart, DigestVerify};
    use base64::prelude::*;
    use tracing::{debug, warn};

    fn verify(context: ring::digest::Context, name: &str, parts: &[DigestPart]) -> bool {
        if let Some(part) = parts
            .iter()
            .find(|p| p.algorithm.to_lowercase() == name.to_lowercase())
        {
            debug!("Verifying digest type, {}", name);
            let digest = context.finish();
            let encoded = BASE64_STANDARD.encode(digest.as_ref());

            return part.digest == encoded;
        }
        warn!("No matching digest algorithm found for {}", name);
        warn!(
            "Provided: [{}]",
            parts.iter().fold(String::new(), |mut acc, item| {
                if acc.is_empty() {
                } else {
                    acc.push_str(", ");
                }
                acc.push_str(&item.algorithm);
                acc
            })
        );

        false
    }

    impl DigestVerify for Sha256 {
        fn update(&mut self, part: &[u8]) {
            self.ctx.update(part);
        }

        fn verify(&mut self, parts: &[DigestPart]) -> bool {
            let alg = self.ctx.algorithm();
            let ctx = std::mem::replace(&mut self.ctx, ring::digest::Context::new(alg));

            verify(ctx, Self::NAME, parts)
        }
    }

    impl DigestVerify for Sha384 {
        fn update(&mut self, part: &[u8]) {
            self.ctx.update(part);
        }

        fn verify(&mut self, parts: &[DigestPart]) -> bool {
            let alg = self.ctx.algorithm();
            let ctx = std::mem::replace(&mut self.ctx, ring::digest::Context::new(alg));

            verify(ctx, Self::NAME, parts)
        }
    }

    impl DigestVerify for Sha512 {
        fn update(&mut self, part: &[u8]) {
            self.ctx.update(part);
        }

        fn verify(&mut self, parts: &[DigestPart]) -> bool {
            let alg = self.ctx.algorithm();
            let ctx = std::mem::replace(&mut self.ctx, ring::digest::Context::new(alg));

            verify(ctx, Self::NAME, parts)
        }
    }
}