/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 | | |
11 | | #include <botan/block_cipher.h> |
12 | | #include <botan/exceptn.h> |
13 | | #include <botan/internal/fmt.h> |
14 | | #include <botan/internal/ghash.h> |
15 | | #include <botan/internal/stl_util.h> |
16 | | |
17 | | namespace Botan { |
18 | | |
19 | | GMAC::GMAC(std::unique_ptr<BlockCipher> cipher) : |
20 | 0 | m_cipher(std::move(cipher)), m_ghash(std::make_unique<GHASH>()), m_H(GCM_BS), m_initialized(false) {} |
21 | | |
22 | 0 | void GMAC::clear() { |
23 | 0 | m_cipher->clear(); |
24 | 0 | m_ghash->clear(); |
25 | 0 | m_aad_buf.clear(); |
26 | 0 | zeroise(m_H); |
27 | 0 | m_initialized = false; |
28 | 0 | } |
29 | | |
30 | 0 | GMAC::~GMAC() = default; |
31 | | |
32 | 0 | Key_Length_Specification GMAC::key_spec() const { |
33 | 0 | return m_cipher->key_spec(); |
34 | 0 | } |
35 | | |
36 | 0 | std::string GMAC::name() const { |
37 | 0 | return fmt("GMAC({})", m_cipher->name()); |
38 | 0 | } |
39 | | |
40 | 0 | size_t GMAC::output_length() const { |
41 | 0 | return GCM_BS; |
42 | 0 | } |
43 | | |
44 | 0 | void GMAC::add_data(std::span<const uint8_t> input) { |
45 | 0 | BufferSlicer in(input); |
46 | |
|
47 | 0 | while(!in.empty()) { |
48 | 0 | if(const auto one_block = m_aad_buf.handle_unaligned_data(in)) { |
49 | 0 | m_ghash->update_associated_data(one_block.value()); |
50 | 0 | } |
51 | |
|
52 | 0 | if(m_aad_buf.in_alignment()) { |
53 | 0 | const auto [aligned_data, full_blocks] = m_aad_buf.aligned_data_to_process(in); |
54 | 0 | if(full_blocks > 0) { |
55 | 0 | m_ghash->update_associated_data(aligned_data); |
56 | 0 | } |
57 | 0 | } |
58 | 0 | } |
59 | 0 | } |
60 | | |
61 | 0 | bool GMAC::has_keying_material() const { |
62 | 0 | return m_cipher->has_keying_material(); |
63 | 0 | } |
64 | | |
65 | 0 | void GMAC::key_schedule(std::span<const uint8_t> key) { |
66 | 0 | clear(); |
67 | 0 | m_cipher->set_key(key); |
68 | |
|
69 | 0 | m_cipher->encrypt(m_H); |
70 | 0 | m_ghash->set_key(m_H); |
71 | 0 | } |
72 | | |
73 | 0 | void GMAC::start_msg(std::span<const uint8_t> nonce) { |
74 | 0 | secure_vector<uint8_t> y0(GCM_BS); |
75 | |
|
76 | 0 | if(nonce.size() == 12) { |
77 | 0 | copy_mem(y0.data(), nonce.data(), nonce.size()); |
78 | 0 | y0[GCM_BS - 1] = 1; |
79 | 0 | } else { |
80 | 0 | m_ghash->ghash_update(y0, nonce); |
81 | 0 | m_ghash->add_final_block(y0, 0, nonce.size()); |
82 | 0 | } |
83 | |
|
84 | 0 | secure_vector<uint8_t> m_enc_y0(GCM_BS); |
85 | 0 | m_cipher->encrypt(y0.data(), m_enc_y0.data()); |
86 | 0 | m_ghash->start(m_enc_y0); |
87 | 0 | m_initialized = true; |
88 | 0 | } |
89 | | |
90 | 0 | void GMAC::final_result(std::span<uint8_t> mac) { |
91 | | // This ensures the GMAC computation has been initialized with a fresh |
92 | | // nonce. The aim of this check is to prevent developers from re-using |
93 | | // nonces (and potential nonce-reuse attacks). |
94 | 0 | if(m_initialized == false) { |
95 | 0 | throw Invalid_State("GMAC was not used with a fresh nonce"); |
96 | 0 | } |
97 | | |
98 | | // Process the rest of the aad buffer. |
99 | 0 | if(!m_aad_buf.in_alignment()) { |
100 | 0 | m_ghash->update_associated_data(m_aad_buf.consume_partial()); |
101 | 0 | } |
102 | |
|
103 | 0 | m_ghash->final(mac.first(output_length())); |
104 | 0 | m_ghash->set_key(m_H); |
105 | 0 | m_aad_buf.clear(); |
106 | 0 | } |
107 | | |
108 | 0 | std::unique_ptr<MessageAuthenticationCode> GMAC::new_object() const { |
109 | 0 | return std::make_unique<GMAC>(m_cipher->new_object()); |
110 | 0 | } |
111 | | } // namespace Botan |