Coverage Report

Created: 2023-01-25 06:35

/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
}