/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(std::unique_ptr<BlockCipher> cipher) : |
17 | | m_cipher(std::move(cipher)), |
18 | | m_ghash(new GHASH), |
19 | | m_aad_buf(GCM_BS), |
20 | | m_H(GCM_BS), |
21 | | m_aad_buf_pos(0), |
22 | | m_initialized(false) |
23 | 0 | { |
24 | 0 | } |
25 | | |
26 | | void GMAC::clear() |
27 | 0 | { |
28 | 0 | m_cipher->clear(); |
29 | 0 | m_ghash->clear(); |
30 | 0 | zeroise(m_aad_buf); |
31 | 0 | zeroise(m_H); |
32 | 0 | m_aad_buf_pos = 0; |
33 | 0 | m_initialized = false; |
34 | 0 | } |
35 | | |
36 | 0 | GMAC::~GMAC() { /* for unique_ptr */ } |
37 | | |
38 | | Key_Length_Specification GMAC::key_spec() const |
39 | 0 | { |
40 | 0 | return m_cipher->key_spec(); |
41 | 0 | } |
42 | | |
43 | | std::string GMAC::name() const |
44 | 0 | { |
45 | 0 | return "GMAC(" + m_cipher->name() + ")"; |
46 | 0 | } |
47 | | |
48 | | size_t GMAC::output_length() const |
49 | 0 | { |
50 | 0 | return GCM_BS; |
51 | 0 | } |
52 | | |
53 | | void GMAC::add_data(const uint8_t input[], size_t size) |
54 | 0 | { |
55 | 0 | if(m_aad_buf_pos > 0) |
56 | 0 | { |
57 | 0 | const size_t taking = std::min(GCM_BS - m_aad_buf_pos, size); |
58 | 0 | copy_mem(&m_aad_buf[m_aad_buf_pos], input, taking); |
59 | 0 | m_aad_buf_pos += taking; |
60 | 0 | input += taking; |
61 | 0 | size -= taking; |
62 | |
|
63 | 0 | if(m_aad_buf_pos == GCM_BS) |
64 | 0 | { |
65 | 0 | m_ghash->update_associated_data(m_aad_buf.data(), GCM_BS); |
66 | 0 | m_aad_buf_pos = 0; |
67 | 0 | } |
68 | 0 | } |
69 | |
|
70 | 0 | const size_t left_over = size % GCM_BS; |
71 | 0 | const size_t full_blocks = size - left_over; |
72 | 0 | m_ghash->update_associated_data(input, full_blocks); |
73 | 0 | input += full_blocks; |
74 | |
|
75 | 0 | if(left_over > 0) |
76 | 0 | { |
77 | 0 | copy_mem(&m_aad_buf[m_aad_buf_pos], input, left_over); |
78 | 0 | m_aad_buf_pos += left_over; |
79 | 0 | } |
80 | 0 | } |
81 | | |
82 | | void GMAC::key_schedule(const uint8_t key[], size_t size) |
83 | 0 | { |
84 | 0 | clear(); |
85 | 0 | m_cipher->set_key(key, size); |
86 | |
|
87 | 0 | m_cipher->encrypt(m_H); |
88 | 0 | m_ghash->set_key(m_H); |
89 | 0 | } |
90 | | |
91 | | void GMAC::start_msg(const uint8_t nonce[], size_t nonce_len) |
92 | 0 | { |
93 | 0 | secure_vector<uint8_t> y0(GCM_BS); |
94 | |
|
95 | 0 | if(nonce_len == 12) |
96 | 0 | { |
97 | 0 | copy_mem(y0.data(), nonce, nonce_len); |
98 | 0 | y0[GCM_BS - 1] = 1; |
99 | 0 | } |
100 | 0 | else |
101 | 0 | { |
102 | 0 | m_ghash->ghash_update(y0, nonce, nonce_len); |
103 | 0 | m_ghash->add_final_block(y0, 0, nonce_len); |
104 | 0 | } |
105 | |
|
106 | 0 | secure_vector<uint8_t> m_enc_y0(GCM_BS); |
107 | 0 | m_cipher->encrypt(y0.data(), m_enc_y0.data()); |
108 | 0 | m_ghash->start(m_enc_y0.data(), m_enc_y0.size()); |
109 | 0 | m_initialized = true; |
110 | 0 | } |
111 | | |
112 | | void GMAC::final_result(uint8_t mac[]) |
113 | 0 | { |
114 | | // This ensures the GMAC computation has been initialized with a fresh |
115 | | // nonce. The aim of this check is to prevent developers from re-using |
116 | | // nonces (and potential nonce-reuse attacks). |
117 | 0 | if(m_initialized == false) |
118 | 0 | throw Invalid_State("GMAC was not used with a fresh nonce"); |
119 | | |
120 | | // process the rest of the aad buffer. Even if it is a partial block only |
121 | | // ghash_update will process it properly. |
122 | 0 | if(m_aad_buf_pos > 0) |
123 | 0 | { |
124 | 0 | m_ghash->update_associated_data(m_aad_buf.data(), m_aad_buf_pos); |
125 | 0 | } |
126 | |
|
127 | 0 | m_ghash->final(mac, output_length()); |
128 | 0 | m_ghash->set_key(m_H); |
129 | 0 | m_aad_buf_pos = 0; |
130 | 0 | } |
131 | | |
132 | | std::unique_ptr<MessageAuthenticationCode> GMAC::new_object() const |
133 | 0 | { |
134 | 0 | return std::make_unique<GMAC>(m_cipher->new_object()); |
135 | 0 | } |
136 | | } |