1 // cmac.cpp - originally written and placed in the public domain by Wei Dai
2 
3 #include "pch.h"
4 
5 #ifndef CRYPTOPP_IMPORTS
6 
7 #include "cmac.h"
8 #include "misc.h"
9 
10 ANONYMOUS_NAMESPACE_BEGIN
11 
12 using CryptoPP::byte;
13 using CryptoPP::IsPowerOf2;
14 
MulU(byte * k,unsigned int len)15 void MulU(byte *k, unsigned int len)
16 {
17 	byte carry = 0;
18 	for (int i=len-1; i>=1; i-=2)
19 	{
20 		byte carry2 = k[i] >> 7;
21 		k[i] += k[i] + carry;
22 		carry = k[i-1] >> 7;
23 		k[i-1] += k[i-1] + carry2;
24 	}
25 
26 #ifndef CRYPTOPP_CMAC_WIDE_BLOCK_CIPHERS
27 	CRYPTOPP_ASSERT(len == 16);
28 
29 	if (carry)
30 	{
31 		k[15] ^= 0x87;
32 		return;
33 	}
34 #else
35 	CRYPTOPP_ASSERT(IsPowerOf2(len));
36 	CRYPTOPP_ASSERT(len >= 8);
37 	CRYPTOPP_ASSERT(len <= 128);
38 
39 	if (carry)
40 	{
41 		switch (len)
42 		{
43 		case 8:
44 			k[7] ^= 0x1b;
45 			break;
46 		case 16:
47 			k[15] ^= 0x87;
48 			break;
49 		case 32:
50 			// https://crypto.stackexchange.com/q/9815/10496
51 			// Polynomial x^256 + x^10 + x^5 + x^2 + 1
52 			k[30] ^= 4;
53 			k[31] ^= 0x25;
54 			break;
55 		case 64:
56 			// https://crypto.stackexchange.com/q/9815/10496
57 			// Polynomial x^512 + x^8 + x^5 + x^2 + 1
58 			k[62] ^= 1;
59 			k[63] ^= 0x25;
60 			break;
61 		case 128:
62 			// https://crypto.stackexchange.com/q/9815/10496
63 			// Polynomial x^1024 + x^19 + x^6 + x + 1
64 			k[125] ^= 8;
65 			k[126] ^= 0x00;
66 			k[127] ^= 0x43;
67 			break;
68 		default:
69 			CRYPTOPP_ASSERT(0);
70 		}
71 	}
72 #endif  // CRYPTOPP_CMAC_WIDE_BLOCK_CIPHERS
73 }
74 
75 ANONYMOUS_NAMESPACE_END
76 
NAMESPACE_BEGIN(CryptoPP)77 NAMESPACE_BEGIN(CryptoPP)
78 
79 void CMAC_Base::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs &params)
80 {
81 	BlockCipher &cipher = AccessCipher();
82 	cipher.SetKey(key, length, params);
83 
84 	unsigned int blockSize = cipher.BlockSize();
85 	m_reg.CleanNew(3*blockSize);
86 	m_counter = 0;
87 
88 	cipher.ProcessBlock(m_reg, m_reg+blockSize);
89 	MulU(m_reg+blockSize, blockSize);
90 	memcpy(m_reg+2*blockSize, m_reg+blockSize, blockSize);
91 	MulU(m_reg+2*blockSize, blockSize);
92 }
93 
Update(const byte * input,size_t length)94 void CMAC_Base::Update(const byte *input, size_t length)
95 {
96 	CRYPTOPP_ASSERT((input && length) || !(input || length));
97 	if (!length)
98 		return;
99 
100 	BlockCipher &cipher = AccessCipher();
101 	unsigned int blockSize = cipher.BlockSize();
102 
103 	if (m_counter > 0)
104 	{
105 		const unsigned int len = UnsignedMin(blockSize - m_counter, length);
106 		if (len)
107 		{
108 			xorbuf(m_reg+m_counter, input, len);
109 			length -= len;
110 			input += len;
111 			m_counter += len;
112 		}
113 
114 		if (m_counter == blockSize && length > 0)
115 		{
116 			cipher.ProcessBlock(m_reg);
117 			m_counter = 0;
118 		}
119 	}
120 
121 	if (length > blockSize)
122 	{
123 		CRYPTOPP_ASSERT(m_counter == 0);
124 		size_t leftOver = 1 + cipher.AdvancedProcessBlocks(m_reg, input, m_reg, length-1, BlockTransformation::BT_DontIncrementInOutPointers|BlockTransformation::BT_XorInput);
125 		input += (length - leftOver);
126 		length = leftOver;
127 	}
128 
129 	if (length > 0)
130 	{
131 		CRYPTOPP_ASSERT(m_counter + length <= blockSize);
132 		xorbuf(m_reg+m_counter, input, length);
133 		m_counter += (unsigned int)length;
134 	}
135 
136 	CRYPTOPP_ASSERT(m_counter > 0);
137 }
138 
TruncatedFinal(byte * mac,size_t size)139 void CMAC_Base::TruncatedFinal(byte *mac, size_t size)
140 {
141 	ThrowIfInvalidTruncatedSize(size);
142 
143 	BlockCipher &cipher = AccessCipher();
144 	unsigned int blockSize = cipher.BlockSize();
145 
146 	if (m_counter < blockSize)
147 	{
148 		m_reg[m_counter] ^= 0x80;
149 		cipher.AdvancedProcessBlocks(m_reg, m_reg+2*blockSize, m_reg, blockSize, BlockTransformation::BT_DontIncrementInOutPointers|BlockTransformation::BT_XorInput);
150 	}
151 	else
152 		cipher.AdvancedProcessBlocks(m_reg, m_reg+blockSize, m_reg, blockSize, BlockTransformation::BT_DontIncrementInOutPointers|BlockTransformation::BT_XorInput);
153 
154 	// UBsan finding
155 	if (mac)
156 		memcpy(mac, m_reg, size);
157 
158 	m_counter = 0;
159 	memset(m_reg, 0, blockSize);
160 }
161 
162 NAMESPACE_END
163 
164 #endif
165