1
2.. _mac:
3
4Message Authentication Codes (MAC)
5===================================
6
7A Message Authentication Code algorithm computes a tag over a message utilizing
8a shared secret key. Thus a valid tag confirms the authenticity and integrity of
9the message. Only entities in possession of the shared secret key are able to
10verify the tag.
11
12.. note::
13
14    When combining a MAC with unauthenticated encryption mode, prefer to first
15    encrypt the message and then MAC the ciphertext. The alternative is to MAC
16    the plaintext, which depending on exact usage can suffer serious security
17    issues. For a detailed discussion of this issue see the paper "The Order of
18    Encryption and Authentication for Protecting Communications" by Hugo
19    Krawczyk
20
21The Botan MAC computation is split into five stages.
22
23#. Instantiate the MAC algorithm.
24#. Set the secret key.
25#. Process IV.
26#. Process data.
27#. Finalize the MAC computation.
28
29.. cpp:class:: MessageAuthenticationCode
30
31  .. cpp:function:: std::string name() const
32
33     Returns a human-readable string of the name of this algorithm.
34
35  .. cpp:function:: void clear()
36
37     Clear the key.
38
39  .. cpp:function:: MessageAuthenticationCode* clone() const
40
41     Return a newly allocated object of the same type as this one.
42
43  .. cpp:function:: void set_key(const uint8_t* key, size_t length)
44
45    Set the shared MAC key for the calculation. This function has to be called before the data is processed.
46
47  .. cpp:function:: bool valid_keylength(size_t length) const
48
49     This function returns true if and only if *length* is a valid
50     keylength for the algorithm.
51
52  .. cpp:function:: size_t minimum_keylength() const
53
54     Return the smallest key length (in bytes) that is acceptable for the
55     algorithm.
56
57  .. cpp:function:: size_t maximum_keylength() const
58
59     Return the largest key length (in bytes) that is acceptable for the
60     algorithm.
61
62  .. cpp:function:: void start(const uint8_t* nonce, size_t nonce_len)
63
64    Set the IV for the MAC calculation. Note that not all MAC algorithms require an IV.
65    If an IV is required, the function has to be called before the data is processed.
66    For algorithms that don't require it, the call can be omitted, or else called
67    with ``nonce_len`` of zero.
68
69  .. cpp:function:: void update(const uint8_t* input, size_t length)
70
71     Process the passed data.
72
73  .. cpp:function:: void update(const secure_vector<uint8_t>& in)
74
75    Process the passed data.
76
77  .. cpp:function:: void update(uint8_t in)
78
79    Process a single byte.
80
81  .. cpp:function:: void final(uint8_t* out)
82
83    Complete the MAC computation and write the calculated tag to the passed byte array.
84
85  .. cpp:function:: secure_vector<uint8_t> final()
86
87    Complete the MAC computation and return the calculated tag.
88
89  .. cpp:function:: bool verify_mac(const uint8_t* mac, size_t length)
90
91    Finalize the current MAC computation and compare the result to the passed
92    ``mac``. Returns ``true``, if the verification is successful and false
93    otherwise.
94
95
96Code Examples
97------------------------
98
99The following example computes an HMAC with a random key then verifies the tag.
100
101    #include <botan/mac.h>
102    #include <botan/hex.h>
103    #include <botan/system_rng.h>
104    #include <assert.h>
105
106    std::string compute_mac(const std::string& msg, const Botan::secure_vector<uint8_t>& key)
107       {
108       auto hmac = Botan::MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)");
109
110       hmac->set_key(key);
111       hmac->update(msg);
112
113       return Botan::hex_encode(hmac->final());
114       }
115
116    int main()
117       {
118       Botan::System_RNG rng;
119
120       const auto key = rng.random_vec(32); // 256 bit random key
121
122       // "Message" != "Mussage" so tags will also not match
123       std::string tag1 = compute_mac("Message", key);
124       std::string tag2 = compute_mac("Mussage", key);
125       assert(tag1 != tag2);
126
127       // Recomputing with original input message results in identical tag
128       std::string tag3 = compute_mac("Message", key);
129       assert(tag1 == tag3);
130       }
131
132
133The following example code computes a AES-256 GMAC and subsequently verifies the
134tag.  Unlike most other MACs, GMAC requires a nonce *which must not repeat or
135all security is lost*.
136
137.. code-block:: cpp
138
139    #include <botan/mac.h>
140    #include <botan/hex.h>
141    #include <iostream>
142
143    int main()
144       {
145       const std::vector<uint8_t> key = Botan::hex_decode("1337133713371337133713371337133713371337133713371337133713371337");
146       const std::vector<uint8_t> nonce = Botan::hex_decode("FFFFFFFFFFFFFFFFFFFFFFFF");
147       const std::vector<uint8_t> data = Botan::hex_decode("6BC1BEE22E409F96E93D7E117393172A");
148       std::unique_ptr<Botan::MessageAuthenticationCode> mac(Botan::MessageAuthenticationCode::create("GMAC(AES-256)"));
149       if(!mac)
150          return 1;
151       mac->set_key(key);
152       mac->start(nonce);
153       mac->update(data);
154       Botan::secure_vector<uint8_t> tag = mac->final();
155       std::cout << mac->name() << ": " << Botan::hex_encode(tag) << std::endl;
156
157       //Verify created MAC
158       mac->start(nonce);
159       mac->update(data);
160       std::cout << "Verification: " << (mac->verify_mac(tag) ? "success" : "failure");
161       return 0;
162       }
163
164The following example code computes a valid AES-128 CMAC tag and modifies the
165data to demonstrate a MAC verification failure.
166
167.. code-block:: cpp
168
169  #include <botan/mac.h>
170  #include <botan/hex.h>
171  #include <iostream>
172
173    int main()
174       {
175       const std::vector<uint8_t> key = Botan::hex_decode("2B7E151628AED2A6ABF7158809CF4F3C");
176       std::vector<uint8_t> data = Botan::hex_decode("6BC1BEE22E409F96E93D7E117393172A");
177       std::unique_ptr<Botan::MessageAuthenticationCode> mac(Botan::MessageAuthenticationCode::create("CMAC(AES-128)"));
178       if(!mac)
179          return 1;
180       mac->set_key(key);
181       mac->update(data);
182       Botan::secure_vector<uint8_t> tag = mac->final();
183       //Corrupting data
184       data.back()++;
185       //Verify with corrupted data
186       mac->update(data);
187       std::cout << "Verification with malformed data: " << (mac->verify_mac(tag) ? "success" : "failure");
188       return 0;
189       }
190
191Available MACs
192------------------------------------------
193
194Currently the following MAC algorithms are available in Botan. In new code,
195default to HMAC with a strong hash like SHA-256 or SHA-384.
196
197CBC-MAC
198~~~~~~~~~~~~
199
200An older authentication code based on a block cipher. Serious security problems,
201in particular **insecure** if messages of several different lengths are
202authenticated. Avoid unless required for compatibility.
203
204Available if ``BOTAN_HAS_CBC_MAC`` is defined.
205
206.. warning::
207   CBC-MAC support is deprecated and will be removed in a future major release.
208
209CMAC
210~~~~~~~~~~~~
211
212A modern CBC-MAC variant that avoids the security problems of plain CBC-MAC.
213Approved by NIST. Also sometimes called OMAC.
214
215Available if ``BOTAN_HAS_CMAC`` is defined.
216
217GMAC
218~~~~~~~~~~~~
219
220GMAC is related to the GCM authenticated cipher mode. It is quite slow unless
221hardware support for carryless multiplications is available. A new nonce
222must be used with **each** message authenticated, or otherwise all security is
223lost.
224
225Available if ``BOTAN_HAS_GMAC`` is defined.
226
227.. warning::
228   Due to the nonce requirement, GMAC is exceptionally fragile. Avoid it unless
229   absolutely required.
230
231HMAC
232~~~~~~~~~~~~
233
234A message authentication code based on a hash function. Very commonly used.
235
236Available if ``BOTAN_HAS_HMAC`` is defined.
237
238Poly1305
239~~~~~~~~~~~~
240
241A polynomial mac (similar to GMAC). Very fast, but tricky to use safely. Forms
242part of the ChaCha20Poly1305 AEAD mode. A new key must be used for **each**
243message, or all security is lost.
244
245Available if ``BOTAN_HAS_POLY1305`` is defined.
246
247.. warning::
248   Due to the nonce requirement, Poly1305 is exceptionally fragile. Avoid it unless
249   absolutely required.
250
251SipHash
252~~~~~~~~~~~~
253
254A modern and very fast PRF. Produces only a 64-bit output. Defaults to
255"SipHash(2,4)" which is the recommended configuration, using 2 rounds for each
256input block and 4 rounds for finalization.
257
258Available if ``BOTAN_HAS_SIPHASH`` is defined.
259
260X9.19-MAC
261~~~~~~~~~~~~
262
263A CBC-MAC variant sometimes used in finance. Always uses DES.
264Sometimes called the "DES retail MAC", also standardized in ISO 9797-1.
265
266It is slow and has known attacks. Avoid unless required.
267
268Available if ``BOTAN_HAS_X919_MAC`` is defined.
269