aboutsummaryrefslogtreecommitdiff
path: root/src/passwordmaker/hmac.rs
blob: 4c9d6aad275f9118d55fad62e74595c8b79f32f3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
use crate::Hasher;

pub(super) fn hmac<T, K, M>(key : K, data : M) -> T::Output
    where T : Hasher,
    T::Output : AsRef<[u8]>,
    K : Iterator<Item=u8> + Clone,
    M : Iterator<Item=u8>,
{
    let key_len = key.clone().count();
    let key =  if key_len > 64 {
        KeyOrHash::from_hash(T::hash(&key.collect::<Vec<_>>()))
    } else {
        KeyOrHash::from_key(key)
    };
    let key = key.chain(std::iter::repeat(0)); //if key[i] does not exist, use 0 instead.

    let mut inner_pad = [0u8;64];
    let mut outer_pad = [0u8;64];

    let pads = inner_pad.iter_mut().zip(outer_pad.iter_mut());
    for ((i,o),k) in pads.zip(key) {
        *i = k ^ 0x36;
        *o = k ^ 0x5C;
    }

    let hash = T::hash(&inner_pad.iter().copied().chain(data).collect::<Vec<_>>());
    T::hash(&outer_pad.iter().chain(hash.as_ref().iter()).copied().collect::<Vec<_>>())
}

enum KeyOrHash<K: Iterator<Item=u8>, H: AsRef<[u8]>> {
    Key(K),
    Hash{
        hash : H,
        idx : usize
    }
}

impl<K: Iterator<Item=u8>, H: AsRef<[u8]>> KeyOrHash<K, H>{
    fn from_key(key : K) -> Self {
        Self::Key(key)
    }
    fn from_hash(hash : H) -> Self {
        Self::Hash { hash, idx: 0 }
    }
}

impl<K: Iterator<Item=u8>, H: AsRef<[u8]>> Iterator for KeyOrHash<K, H>{
    type Item = u8;
    fn next(&mut self) -> Option<Self::Item> {
        match self {
            KeyOrHash::Key(k) => k.next(),
            KeyOrHash::Hash { hash: owned, idx } => {
                *idx += 1;
                owned.as_ref().get(*idx-1).copied()
            },
        }
    }
}