1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
/*
* GMAC
* (C) 2016 Matthias Gierlings, René Korthaus
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include <botan/gmac.h>
namespace Botan {
GMAC::GMAC(BlockCipher* cipher)
: GHASH(),
m_aad_buf(),
m_cipher(cipher),
m_initialized(false)
{}
void GMAC::clear()
{
GHASH::clear();
m_H.resize(GCM_BS);
m_H_ad.resize(GCM_BS);
m_ghash.resize(GCM_BS);
m_cipher->clear();
m_aad_buf.clear();
m_initialized = false;
}
std::string GMAC::name() const
{
return "GMAC(" + m_cipher->name() + ")";
}
size_t GMAC::output_length() const
{
return GCM_BS;
}
void GMAC::add_data(const byte input[], size_t size)
{
m_ad_len += size;
// buffer partial blocks till we received a full input block
// or final is called.
m_aad_buf.insert(m_aad_buf.end(), input, input + size);
if(m_aad_buf.size() >= GCM_BS)
{
// process all complete input blocks.
ghash_update(m_ghash,
m_aad_buf.data(),
m_aad_buf.size() - (m_aad_buf.size() % GCM_BS));
// remove all processed blocks from buffer.
m_aad_buf.erase(m_aad_buf.begin(),
m_aad_buf.end() - (m_aad_buf.size() % GCM_BS));
}
}
void GMAC::key_schedule(const byte key[], size_t size)
{
clear();
m_cipher->set_key(key, size);
m_cipher->encrypt(m_H_ad.data(), m_H.data());
}
void GMAC::start(const std::vector<byte>& nonce)
{
start(nonce.data(), nonce.size());
}
void GMAC::start(const secure_vector<byte>& nonce)
{
start(nonce.data(), nonce.size());
}
void GMAC::start(const byte nonce[], size_t nonce_len)
{
secure_vector<byte> y0(GCM_BS);
if(nonce_len == 12)
{
copy_mem(y0.data(), nonce, nonce_len);
y0[GCM_BS - 1] = 1;
}
else
{
ghash_update(y0, nonce, nonce_len);
add_final_block(y0, 0, nonce_len);
}
secure_vector<byte> m_enc_y0(GCM_BS);
m_cipher->encrypt(y0.data(), m_enc_y0.data());
GHASH::start(m_enc_y0.data(), m_enc_y0.size());
m_initialized = true;
}
void GMAC::final_result(byte mac[])
{
// This ensures the GMAC computation has been initialized with a fresh
// nonce. The aim of this check is to prevent developers from re-using
// nonces (and potential nonce-reuse attacks).
BOTAN_ASSERT(m_initialized,
"The GMAC computation has not been initialized with a fresh "
"nonce.");
// process the rest of the aad buffer. Even if it is a partial block only
// ghash_update will process it properly.
if(m_aad_buf.size() > 0)
{
ghash_update(m_ghash,
m_aad_buf.data(),
m_aad_buf.size());
}
secure_vector<byte> result = GHASH::final();
std::copy(result.begin(), result.end(), mac);
clear();
}
MessageAuthenticationCode* GMAC::clone() const
{
return new GMAC(BlockCipher::create(m_cipher->name()).release());
}
}
|