1 /**
2 * HMAC
3 * 
4 * Copyright:
5 * (C) 1999-2007,2014 Jack Lloyd
6 * (C) 2014-2015 Etienne Cimon
7 *
8 * License:
9 * Botan is released under the Simplified BSD License (see LICENSE.md)
10 */
11 module botan.mac.hmac;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_HMAC || BOTAN_HAS_PBE_PKCS_V20):
15 
16 public import botan.mac.mac;
17 import botan.hash.hash;
18 import std.algorithm : fill;
19 import botan.utils.xor_buf;
20 import botan.utils.mem_ops;
21 import std.range : refRange;
22 /**
23 * HMAC
24 */
25 final class HMAC : MessageAuthenticationCode
26 {
27 public:
28     /*
29     * Clear memory of sensitive data
30     */
31     override void clear()
32     {
33         m_hash.clear();
34         zap(m_ikey);
35         zap(m_okey);
36     }
37 
38     /*
39     * Return the name of this type
40     */
41     override @property string name() const
42     {
43         return "HMAC(" ~ m_hash.name ~ ")";
44     }
45 
46     /*
47     * Return a clone of this object
48     */
49     override MessageAuthenticationCode clone() const
50     {
51         return new HMAC(m_hash.clone());
52     }
53 
54     override @property size_t outputLength() const { return m_hash.outputLength; }
55 
56     KeyLengthSpecification keySpec() const
57     {
58         // Absurd max length here is to support PBKDF2
59         return KeyLengthSpecification(0, 512);
60     }
61 
62     /**
63     * Params:
64     *  hash = the hash to use for HMACing
65     */
66     this(HashFunction hash) 
67     {
68         m_hash = hash;
69         if (m_hash.hashBlockSize == 0)
70             throw new InvalidArgument("HMAC cannot be used with " ~ m_hash.name);
71     }
72 protected:
73     /*
74     * Update a HMAC Calculation
75     */
76     override void addData(const(ubyte)* input, size_t length)
77     {
78         m_hash.update(input, length);
79     }
80 
81     /*
82     * Finalize a HMAC Calculation
83     */
84     override void finalResult(ubyte* mac)
85     {
86         m_hash.flushInto(mac);
87         m_hash.update(m_okey);
88         m_hash.update(mac, outputLength());
89         m_hash.flushInto(mac);
90         m_hash.update(m_ikey);
91     }
92 
93     /*
94     * HMAC Key Schedule
95     */
96     override void keySchedule(const(ubyte)* key, size_t length)
97     {
98         m_hash.clear();
99         
100         m_ikey.resize(m_hash.hashBlockSize);
101         m_okey.resize(m_hash.hashBlockSize);
102         
103         fill(m_ikey.ptr[0 .. m_ikey.length], cast(ubyte)0x36);
104         fill(m_okey.ptr[0 .. m_okey.length], cast(ubyte)0x5C);
105         
106         if (length > m_hash.hashBlockSize)
107         {
108             SecureVector!ubyte hmac_key = m_hash.process(key, length);
109             xorBuf(m_ikey, hmac_key, hmac_key.length);
110             xorBuf(m_okey, hmac_key, hmac_key.length);
111         }
112         else
113         {
114             xorBuf(m_ikey, key, length);
115             xorBuf(m_okey, key, length);
116         }
117         
118         m_hash.update(m_ikey);
119     }
120 
121     Unique!HashFunction m_hash;
122     SecureVector!ubyte m_ikey, m_okey;
123 }