sd_jwt_payload/
hasher.rs

1// Copyright 2020-2023 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4#[cfg(feature = "sha")]
5use crypto::hashes::sha::SHA256;
6
7#[cfg(feature = "sha")]
8use crypto::hashes::sha::SHA256_LEN;
9use multibase::Base;
10
11pub const SHA_ALG_NAME: &str = "sha-256";
12
13/// Used to implement hash functions to be used for encoding/decoding.
14///
15/// ## Note
16///
17/// Implementations of this trait are expected only for algorithms listed in
18/// the IANA "Named Information Hash Algorithm" registry.
19/// See [Hash Function Claim](https://www.ietf.org/archive/id/draft-ietf-oauth-selective-disclosure-jwt-07.html#name-hash-function-claim)
20pub trait Hasher {
21  /// Digests input to produce unique fixed-size hash value in bytes.
22  fn digest(&self, input: &[u8]) -> Vec<u8>;
23
24  /// Returns the name of hash function used.
25  ///
26  /// ## Note
27  ///
28  /// The hash algorithm identifier MUST be a hash algorithm value from the
29  /// "Hash Name String" column in the IANA "Named Information Hash Algorithm"  
30  fn alg_name(&self) -> &str;
31
32  /// Returns the base64url-encoded digest of a `disclosure`.
33  fn encoded_digest(&self, disclosure: &str) -> String {
34    let hash = self.digest(disclosure.as_bytes());
35    Base::Base64Url.encode(hash)
36  }
37}
38
39/// An implementation of [`Hasher`] that uses the `sha-256` hash function.
40#[derive(Default, Clone, Copy, Debug)]
41#[cfg(feature = "sha")]
42pub struct Sha256Hasher;
43
44#[cfg(feature = "sha")]
45impl Sha256Hasher {
46  /// Creates a new [`ShaHasher`]
47  pub fn new() -> Self {
48    Sha256Hasher {}
49  }
50}
51#[cfg(feature = "sha")]
52impl Hasher for Sha256Hasher {
53  fn digest(&self, input: &[u8]) -> Vec<u8> {
54    let mut digest: [u8; SHA256_LEN] = Default::default();
55    SHA256(input, &mut digest);
56    digest.to_vec()
57  }
58
59  fn alg_name(&self) -> &'static str {
60    SHA_ALG_NAME
61  }
62}
63
64// Some test values taken from https://www.ietf.org/archive/id/draft-ietf-oauth-selective-disclosure-jwt-07.html#name-disclosures
65#[cfg(test)]
66mod test {
67  use crate::Hasher;
68  use crate::Sha256Hasher;
69
70  #[test]
71  fn test1() {
72    let disclosure = "WyI2cU1RdlJMNWhhaiIsICJmYW1pbHlfbmFtZSIsICJNw7ZiaXVzIl0";
73    let hasher = Sha256Hasher::new();
74    let hash = hasher.encoded_digest(disclosure);
75    assert_eq!("uutlBuYeMDyjLLTpf6Jxi7yNkEF35jdyWMn9U7b_RYY", hash);
76  }
77
78  #[test]
79  fn test2() {
80    let disclosure =
81      "WyJlSThaV205UW5LUHBOUGVOZW5IZGhRIiwgImVtYWlsIiwgIlwidW51c3VhbCBlbWFpbCBhZGRyZXNzXCJAZXhhbXBsZS5qcCJd";
82    let hasher = Sha256Hasher::new();
83    let hash = hasher.encoded_digest(disclosure);
84    assert_eq!("Kuet1yAa0HIQvYnOVd59hcViO9Ug6J2kSfqYRBeowvE", hash);
85  }
86
87  #[test]
88  fn test3() {
89    let disclosure = "WyJsa2x4RjVqTVlsR1RQVW92TU5JdkNBIiwgIkZSIl0";
90    let hasher = Sha256Hasher::new();
91    let hash = hasher.encoded_digest(disclosure);
92    assert_eq!("w0I8EKcdCtUPkGCNUrfwVp2xEgNjtoIDlOxc9-PlOhs", hash);
93  }
94}