Coverage Report

Created: 2026-08-30 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/botan/src/lib/mac/gmac/gmac.cpp
Line
Count
Source
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/mem_ops.h>
14
#include <botan/internal/fmt.h>
15
#include <botan/internal/ghash.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
0
   if(m_cipher->block_size() != GCM_BS) {
22
0
      throw Invalid_Argument(fmt("Invalid block cipher {} for GMAC", m_cipher->name()));
23
0
   }
24
0
}
25
26
0
void GMAC::clear() {
27
0
   m_cipher->clear();
28
0
   m_ghash->clear();
29
0
   zeroise(m_H);
30
0
   m_initialized = false;
31
0
}
32
33
0
GMAC::~GMAC() = default;
34
35
0
Key_Length_Specification GMAC::key_spec() const {
36
0
   return m_cipher->key_spec();
37
0
}
38
39
0
std::string GMAC::name() const {
40
0
   return fmt("GMAC({})", m_cipher->name());
41
0
}
42
43
0
std::string GMAC::provider() const {
44
0
   return m_ghash->provider();
45
0
}
46
47
0
size_t GMAC::output_length() const {
48
0
   return GCM_BS;
49
0
}
50
51
0
void GMAC::add_data(std::span<const uint8_t> input) {
52
0
   if(!m_initialized) {
53
0
      throw Invalid_State("GMAC was not used with a fresh nonce");
54
0
   }
55
0
   m_ghash->update_associated_data(input);
56
0
}
57
58
0
bool GMAC::has_keying_material() const {
59
0
   return m_cipher->has_keying_material();
60
0
}
61
62
0
void GMAC::key_schedule(std::span<const uint8_t> key) {
63
0
   clear();
64
0
   m_cipher->set_key(key);
65
66
0
   m_cipher->encrypt(m_H);
67
0
   m_ghash->set_key(m_H);
68
0
}
69
70
0
void GMAC::start_msg(std::span<const uint8_t> nonce) {
71
0
   if(nonce.empty()) {
72
0
      throw Invalid_IV_Length(name(), nonce.size());
73
0
   }
74
75
0
   std::array<uint8_t, GCM_BS> y0 = {0};
76
77
   // Clear any AD accumulated by a prior start() that was never finalized
78
0
   m_ghash->reset_state();
79
0
   m_ghash->reset_associated_data();
80
81
0
   if(nonce.size() == 12) {
82
0
      copy_mem(y0.data(), nonce.data(), nonce.size());
83
0
      y0[GCM_BS - 1] = 1;
84
0
   } else {
85
0
      m_ghash->nonce_hash(y0, nonce);
86
0
   }
87
88
0
   m_cipher->encrypt(y0.data());
89
0
   m_ghash->start(y0);
90
0
   m_initialized = true;
91
0
}
92
93
0
void GMAC::final_result(std::span<uint8_t> mac) {
94
   // This ensures the GMAC computation has been initialized with a fresh
95
   // nonce. The aim of this check is to prevent developers from re-using
96
   // nonces (and potential nonce-reuse attacks).
97
0
   if(!m_initialized) {
98
0
      throw Invalid_State("GMAC was not used with a fresh nonce");
99
0
   }
100
101
0
   m_ghash->final(mac.first(output_length()));
102
0
   m_ghash->reset_associated_data();
103
0
}
104
105
0
std::unique_ptr<MessageAuthenticationCode> GMAC::new_object() const {
106
0
   return std::make_unique<GMAC>(m_cipher->new_object());
107
0
}
108
}  // namespace Botan