1// authenc.cpp - written and placed in the public domain by Wei Dai
2
3#include "pch.h"
4
5#ifndef CRYPTOPP_IMPORTS
6
7#include "authenc.h"
8
9NAMESPACE_BEGIN(CryptoPP)
10
11void AuthenticatedSymmetricCipherBase::AuthenticateData(const byte *input, size_t len)
12{
13	unsigned int blockSize = AuthenticationBlockSize();
14	unsigned int &num = m_bufferedDataLength;
15	byte* data = m_buffer.begin();
16
17	if (num != 0)	// process left over data
18	{
19		if (num+len >= blockSize)
20		{
21			memcpy(data+num, input, blockSize-num);
22			AuthenticateBlocks(data, blockSize);
23			input += (blockSize-num);
24			len -= (blockSize-num);
25			num = 0;
26			// drop through and do the rest
27		}
28		else
29		{
30			memcpy(data+num, input, len);
31			num += (unsigned int)len;
32			return;
33		}
34	}
35
36	// now process the input data in blocks of blockSize bytes and save the leftovers to m_data
37	if (len >= blockSize)
38	{
39		size_t leftOver = AuthenticateBlocks(input, len);
40		input += (len - leftOver);
41		len = leftOver;
42	}
43
44	memcpy(data, input, len);
45	num = (unsigned int)len;
46}
47
48void AuthenticatedSymmetricCipherBase::SetKey(const byte *userKey, size_t keylength, const NameValuePairs &params)
49{
50	m_bufferedDataLength = 0;
51	m_state = State_Start;
52
53	SetKeyWithoutResync(userKey, keylength, params);
54	m_state = State_KeySet;
55
56	size_t length;
57	const byte *iv = GetIVAndThrowIfInvalid(params, length);
58	if (iv)
59		Resynchronize(iv, (int)length);
60}
61
62void AuthenticatedSymmetricCipherBase::Resynchronize(const byte *iv, int length)
63{
64	if (m_state < State_KeySet)
65		throw BadState(AlgorithmName(), "Resynchronize", "key is set");
66
67	m_bufferedDataLength = 0;
68	m_totalHeaderLength = m_totalMessageLength = m_totalFooterLength = 0;
69	m_state = State_KeySet;
70
71	Resync(iv, this->ThrowIfInvalidIVLength(length));
72	m_state = State_IVSet;
73}
74
75void AuthenticatedSymmetricCipherBase::Update(const byte *input, size_t length)
76{
77	if (length == 0)
78		return;
79
80	switch (m_state)
81	{
82	case State_Start:
83	case State_KeySet:
84		throw BadState(AlgorithmName(), "Update", "setting key and IV");
85	case State_IVSet:
86		AuthenticateData(input, length);
87		m_totalHeaderLength += length;
88		break;
89	case State_AuthUntransformed:
90	case State_AuthTransformed:
91		AuthenticateLastConfidentialBlock();
92		m_bufferedDataLength = 0;
93		m_state = State_AuthFooter;
94		// fall through
95	case State_AuthFooter:
96		AuthenticateData(input, length);
97		m_totalFooterLength += length;
98		break;
99	default:
100		assert(false);
101	}
102}
103
104void AuthenticatedSymmetricCipherBase::ProcessData(byte *outString, const byte *inString, size_t length)
105{
106	m_totalMessageLength += length;
107	if (m_state >= State_IVSet && m_totalMessageLength > MaxMessageLength())
108		throw InvalidArgument(AlgorithmName() + ": message length exceeds maximum");
109
110reswitch:
111	switch (m_state)
112	{
113	case State_Start:
114	case State_KeySet:
115		throw BadState(AlgorithmName(), "ProcessData", "setting key and IV");
116	case State_AuthFooter:
117		throw BadState(AlgorithmName(), "ProcessData was called after footer input has started");
118	case State_IVSet:
119		AuthenticateLastHeaderBlock();
120		m_bufferedDataLength = 0;
121		m_state = AuthenticationIsOnPlaintext()==IsForwardTransformation() ? State_AuthUntransformed : State_AuthTransformed;
122		goto reswitch;
123	case State_AuthUntransformed:
124		AuthenticateData(inString, length);
125		AccessSymmetricCipher().ProcessData(outString, inString, length);
126		break;
127	case State_AuthTransformed:
128		AccessSymmetricCipher().ProcessData(outString, inString, length);
129		AuthenticateData(outString, length);
130		break;
131	default:
132		assert(false);
133	}
134}
135
136void AuthenticatedSymmetricCipherBase::TruncatedFinal(byte *mac, size_t macSize)
137{
138	if (m_totalHeaderLength > MaxHeaderLength())
139		throw InvalidArgument(AlgorithmName() + ": header length of " + IntToString(m_totalHeaderLength) + " exceeds the maximum of " + IntToString(MaxHeaderLength()));
140
141	if (m_totalFooterLength > MaxFooterLength())
142	{
143		if (MaxFooterLength() == 0)
144			throw InvalidArgument(AlgorithmName() + ": additional authenticated data (AAD) cannot be input after data to be encrypted or decrypted");
145		else
146			throw InvalidArgument(AlgorithmName() + ": footer length of " + IntToString(m_totalFooterLength) + " exceeds the maximum of " + IntToString(MaxFooterLength()));
147	}
148
149	switch (m_state)
150	{
151	case State_Start:
152	case State_KeySet:
153		throw BadState(AlgorithmName(), "TruncatedFinal", "setting key and IV");
154
155	case State_IVSet:
156		AuthenticateLastHeaderBlock();
157		m_bufferedDataLength = 0;
158		// fall through
159
160	case State_AuthUntransformed:
161	case State_AuthTransformed:
162		AuthenticateLastConfidentialBlock();
163		m_bufferedDataLength = 0;
164		// fall through
165
166	case State_AuthFooter:
167		AuthenticateLastFooterBlock(mac, macSize);
168		m_bufferedDataLength = 0;
169		break;
170
171	default:
172		assert(false);
173	}
174
175	m_state = State_KeySet;
176}
177
178NAMESPACE_END
179
180#endif
181