/src/botan/src/lib/mac/gmac/gmac.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * GMAC |
3 | | * (C) 2016 Matthias Gierlings, René Korthaus |
4 | | * (C) 2017 Jack Lloyd |
5 | | * |
6 | | * Botan is released under the Simplified BSD License (see license.txt) |
7 | | */ |
8 | | |
9 | | #include <botan/internal/gmac.h> |
10 | | #include <botan/internal/ghash.h> |
11 | | #include <botan/exceptn.h> |
12 | | #include <botan/block_cipher.h> |
13 | | |
14 | | namespace Botan { |
15 | | |
16 | | GMAC::GMAC(BlockCipher* cipher) : |
17 | | m_cipher(cipher), |
18 | | m_ghash(new GHASH), |
19 | | m_aad_buf(GCM_BS), |
20 | | m_aad_buf_pos(0), |
21 | | m_initialized(false) |
22 | 0 | { |
23 | 0 | } |
24 | | |
25 | | void GMAC::clear() |
26 | 0 | { |
27 | 0 | m_cipher->clear(); |
28 | 0 | m_ghash->clear(); |
29 | 0 | zeroise(m_aad_buf); |
30 | 0 | m_aad_buf_pos = 0; |
31 | 0 | m_initialized = false; |
32 | 0 | } |
33 | | |
34 | 0 | GMAC::~GMAC() { /* for unique_ptr */ } |
35 | | |
36 | | Key_Length_Specification GMAC::key_spec() const |
37 | 0 | { |
38 | 0 | return m_cipher->key_spec(); |
39 | 0 | } |
40 | | |
41 | | std::string GMAC::name() const |
42 | 0 | { |
43 | 0 | return "GMAC(" + m_cipher->name() + ")"; |
44 | 0 | } |
45 | | |
46 | | size_t GMAC::output_length() const |
47 | 0 | { |
48 | 0 | return GCM_BS; |
49 | 0 | } |
50 | | |
51 | | void GMAC::add_data(const uint8_t input[], size_t size) |
52 | 0 | { |
53 | 0 | if(m_aad_buf_pos > 0) |
54 | 0 | { |
55 | 0 | const size_t taking = std::min(GCM_BS - m_aad_buf_pos, size); |
56 | 0 | copy_mem(&m_aad_buf[m_aad_buf_pos], input, taking); |
57 | 0 | m_aad_buf_pos += taking; |
58 | 0 | input += taking; |
59 | 0 | size -= taking; |
60 | |
|
61 | 0 | if(m_aad_buf_pos == GCM_BS) |
62 | 0 | { |
63 | 0 | m_ghash->update_associated_data(m_aad_buf.data(), GCM_BS); |
64 | 0 | m_aad_buf_pos = 0; |
65 | 0 | } |
66 | 0 | } |
67 | |
|
68 | 0 | const size_t left_over = size % GCM_BS; |
69 | 0 | const size_t full_blocks = size - left_over; |
70 | 0 | m_ghash->update_associated_data(input, full_blocks); |
71 | 0 | input += full_blocks; |
72 | |
|
73 | 0 | if(left_over > 0) |
74 | 0 | { |
75 | 0 | copy_mem(&m_aad_buf[m_aad_buf_pos], input, left_over); |
76 | 0 | m_aad_buf_pos += left_over; |
77 | 0 | } |
78 | 0 | } |
79 | | |
80 | | void GMAC::key_schedule(const uint8_t key[], size_t size) |
81 | 0 | { |
82 | 0 | clear(); |
83 | 0 | m_cipher->set_key(key, size); |
84 | |
|
85 | 0 | secure_vector<uint8_t> H(GCM_BS); |
86 | 0 | m_cipher->encrypt(H); |
87 | 0 | m_ghash->set_key(H); |
88 | 0 | } |
89 | | |
90 | | void GMAC::start_msg(const uint8_t nonce[], size_t nonce_len) |
91 | 0 | { |
92 | 0 | secure_vector<uint8_t> y0(GCM_BS); |
93 | |
|
94 | 0 | if(nonce_len == 12) |
95 | 0 | { |
96 | 0 | copy_mem(y0.data(), nonce, nonce_len); |
97 | 0 | y0[GCM_BS - 1] = 1; |
98 | 0 | } |
99 | 0 | else |
100 | 0 | { |
101 | 0 | m_ghash->ghash_update(y0, nonce, nonce_len); |
102 | 0 | m_ghash->add_final_block(y0, 0, nonce_len); |
103 | 0 | } |
104 | |
|
105 | 0 | secure_vector<uint8_t> m_enc_y0(GCM_BS); |
106 | 0 | m_cipher->encrypt(y0.data(), m_enc_y0.data()); |
107 | 0 | m_ghash->start(m_enc_y0.data(), m_enc_y0.size()); |
108 | 0 | m_initialized = true; |
109 | 0 | } |
110 | | |
111 | | void GMAC::final_result(uint8_t mac[]) |
112 | 0 | { |
113 | | // This ensures the GMAC computation has been initialized with a fresh |
114 | | // nonce. The aim of this check is to prevent developers from re-using |
115 | | // nonces (and potential nonce-reuse attacks). |
116 | 0 | if(m_initialized == false) |
117 | 0 | throw Invalid_State("GMAC was not used with a fresh nonce"); |
118 | | |
119 | | // process the rest of the aad buffer. Even if it is a partial block only |
120 | | // ghash_update will process it properly. |
121 | 0 | if(m_aad_buf_pos > 0) |
122 | 0 | { |
123 | 0 | m_ghash->update_associated_data(m_aad_buf.data(), m_aad_buf_pos); |
124 | 0 | } |
125 | |
|
126 | 0 | m_ghash->final(mac, output_length()); |
127 | 0 | clear(); |
128 | 0 | } |
129 | | |
130 | | MessageAuthenticationCode* GMAC::clone() const |
131 | 0 | { |
132 | 0 | return new GMAC(m_cipher->clone()); |
133 | 0 | } |
134 | | } |