Coverage Report

Created: 2021-06-10 10:30

/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_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
std::unique_ptr<MessageAuthenticationCode> GMAC::new_object() const
131
0
   {
132
0
   return std::make_unique<GMAC>(m_cipher->new_object());
133
0
   }
134
}