1use crate::base64::{Base64, Base64Url};
4use crate::types::{EncodingFormat, SHAFamily};
5use sha1::Sha1;
6use sha2::{Digest, Sha256, Sha384, Sha512};
7
8pub struct Hash {
9 algorithm: SHAFamily,
10 encoding: Option<EncodingFormat>,
11}
12
13impl Hash {
14 pub fn new(algorithm: SHAFamily, encoding: Option<EncodingFormat>) -> Self {
15 Self {
16 algorithm,
17 encoding,
18 }
19 }
20
21 pub async fn digest(
22 &self,
23 input: impl AsRef<[u8]>,
24 ) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
25 let data = input.as_ref();
26
27 let hash = match self.algorithm {
28 SHAFamily::SHA1 => {
29 let mut hasher = Sha1::new();
30 hasher.update(data);
31 hasher.finalize().to_vec()
32 }
33 SHAFamily::SHA256 => {
34 let mut hasher = Sha256::new();
35 hasher.update(data);
36 hasher.finalize().to_vec()
37 }
38 SHAFamily::SHA384 => {
39 let mut hasher = Sha384::new();
40 hasher.update(data);
41 hasher.finalize().to_vec()
42 }
43 SHAFamily::SHA512 => {
44 let mut hasher = Sha512::new();
45 hasher.update(data);
46 hasher.finalize().to_vec()
47 }
48 };
49
50 match self.encoding {
51 Some(EncodingFormat::Hex) => Ok(hash
52 .iter()
53 .map(|b| format!("{:02x}", b))
54 .collect::<String>()
55 .into_bytes()),
56 Some(EncodingFormat::Base64) => Ok(Base64::encode(&hash, None).into_bytes()),
57 Some(EncodingFormat::Base64Url) => {
58 Ok(Base64Url::encode(&hash, Some(true)).into_bytes())
59 }
60 Some(EncodingFormat::Base64UrlNoPad) => {
61 Ok(Base64Url::encode(&hash, Some(false)).into_bytes())
62 }
63 Some(EncodingFormat::None) | None => Ok(hash),
64 }
65 }
66
67 pub async fn digest_string(
68 &self,
69 input: impl AsRef<str>,
70 ) -> Result<String, Box<dyn std::error::Error>> {
71 let bytes = self.digest(input.as_ref().as_bytes()).await?;
72 Ok(String::from_utf8(bytes)?)
73 }
74}
75
76pub fn create_hash(algorithm: SHAFamily, encoding: Option<EncodingFormat>) -> Hash {
77 Hash::new(algorithm, encoding)
78}