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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#![no_std]
extern crate generic_array;
extern crate digest;
extern crate crypto_mac;

pub use crypto_mac::{Mac, MacResult};
use digest::{Input, FixedOutput};
use generic_array::{ArrayLength, GenericArray};

const IPAD: u8 = 0x36;
const OPAD: u8 = 0x5c;

/// The `Hmac` struct represents an HMAC using a given hash function `D`.
pub struct Hmac<D>
    where D: Input + FixedOutput + Default,
          <D as Input>::BlockSize: ArrayLength<u8>
{
    digest: D,
    key: GenericArray<u8, D::BlockSize>,
}

/// The key that Hmac processes must be the same as the block size of the
/// underlying Digest. If the provided key is smaller than that, we just pad it
/// with zeros. If its larger, we hash it and then pad it with zeros.
fn expand_key<D>(key: &[u8]) -> GenericArray<u8, D::BlockSize>
    where D: Input + FixedOutput + Default,
          <D as Input>::BlockSize: ArrayLength<u8>
{
    let mut exp_key = GenericArray::default();
    
    if key.len() <= exp_key.len() {
        exp_key[..key.len()].copy_from_slice(key);
    } else {
        let mut digest = D::default();
        digest.digest(key);
        let output = digest.fixed_result();
        exp_key[..output.len()].copy_from_slice(output.as_slice());
    }
    exp_key
}

impl <D> Hmac<D>
    where D: Input + FixedOutput + Default,
          <D as Input>::BlockSize: ArrayLength<u8>
{
    fn derive_key(&self, mask: u8) -> GenericArray<u8, D::BlockSize> {
        let mut key = self.key.clone();
        for elem in key.iter_mut() {
            *elem ^= mask;
        }
        key
    }
}

impl <D> Mac for Hmac<D>
    where D: Input + FixedOutput + Default,
          <D as Input>::BlockSize: ArrayLength<u8>,
          <D as FixedOutput>::OutputSize: ArrayLength<u8>
{
    type OutputSize = D::OutputSize;

    fn new(key: &[u8]) -> Hmac<D> {
        let mut hmac = Hmac {
            digest: D::default(),
            key: expand_key::<D>(key),
        };
        let i_key_pad = hmac.derive_key(IPAD);
        hmac.digest.digest(&i_key_pad);
        hmac
    }

    fn input(&mut self, data: &[u8]) {
        self.digest.digest(data);
    }

    fn result(self) -> MacResult<D::OutputSize> {
        let o_key_pad = self.derive_key(OPAD);
        let output = self.digest.fixed_result();
        let mut digest = D::default();
        digest.digest(&o_key_pad);
        digest.digest(&output);
        MacResult::new(digest.fixed_result())
    }
}