1// square.cpp - written and placed in the public domain by Wei Dai
2// Based on Paulo S.L.M. Barreto's public domain implementation
3
4#include "pch.h"
5#include "square.h"
6#include "misc.h"
7#include "gf256.h"
8
9NAMESPACE_BEGIN(CryptoPP)
10
11// apply theta to a roundkey
12static void SquareTransform (word32 in[4], word32 out[4])
13{
14	static const byte G[4][4] =
15	{
16		0x02U, 0x01U, 0x01U, 0x03U,
17		0x03U, 0x02U, 0x01U, 0x01U,
18		0x01U, 0x03U, 0x02U, 0x01U,
19		0x01U, 0x01U, 0x03U, 0x02U
20	};
21
22	GF256 gf256(0xf5);
23
24	for (int i = 0; i < 4; i++)
25	{
26		word32 temp = 0;
27		for (int j = 0; j < 4; j++)
28			for (int k = 0; k < 4; k++)
29				temp ^= (word32)gf256.Multiply(GETBYTE(in[i], 3-k), G[k][j]) << ((3-j)*8);
30		out[i] = temp;
31	}
32}
33
34void Square::Base::UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs &)
35{
36	AssertValidKeyLength(length);
37
38	static const word32 offset[ROUNDS] = {
39	0x01000000UL, 0x02000000UL, 0x04000000UL, 0x08000000UL,
40	0x10000000UL, 0x20000000UL, 0x40000000UL, 0x80000000UL,
41	};
42
43	GetUserKey(BIG_ENDIAN_ORDER, roundkeys[0], KEYLENGTH/4, userKey, KEYLENGTH);
44
45	/* apply the key evolution function */
46	for (int i = 1; i < ROUNDS+1; i++)
47	{
48		roundkeys[i][0] = roundkeys[i-1][0] ^ rotlFixed(roundkeys[i-1][3], 8U) ^ offset[i-1];
49		roundkeys[i][1] = roundkeys[i-1][1] ^ roundkeys[i][0];
50		roundkeys[i][2] = roundkeys[i-1][2] ^ roundkeys[i][1];
51		roundkeys[i][3] = roundkeys[i-1][3] ^ roundkeys[i][2];
52	}
53
54	/* produce the round keys */
55	if (IsForwardTransformation())
56	{
57		for (int i = 0; i < ROUNDS; i++)
58			SquareTransform (roundkeys[i], roundkeys[i]);
59	}
60	else
61	{
62		for (int i = 0; i < ROUNDS/2; i++)
63			for (int j = 0; j < 4; j++)
64				std::swap(roundkeys[i][j], roundkeys[ROUNDS-i][j]);
65		SquareTransform (roundkeys[ROUNDS], roundkeys[ROUNDS]);
66	}
67}
68
69#define MSB(x) (((x) >> 24) & 0xffU)	/* most  significant byte */
70#define SSB(x) (((x) >> 16) & 0xffU)	/* second in significance */
71#define TSB(x) (((x) >>  8) & 0xffU)	/* third  in significance */
72#define LSB(x) (((x)      ) & 0xffU)	/* least significant byte */
73
74#define squareRound(text, temp, T0, T1, T2, T3, roundkey) \
75{ \
76	temp[0] = T0[MSB (text[0])] \
77			^ T1[MSB (text[1])] \
78			^ T2[MSB (text[2])] \
79			^ T3[MSB (text[3])] \
80			^ roundkey[0]; \
81	temp[1] = T0[SSB (text[0])] \
82			^ T1[SSB (text[1])] \
83			^ T2[SSB (text[2])] \
84			^ T3[SSB (text[3])] \
85			^ roundkey[1]; \
86	temp[2] = T0[TSB (text[0])] \
87			^ T1[TSB (text[1])] \
88			^ T2[TSB (text[2])] \
89			^ T3[TSB (text[3])] \
90			^ roundkey[2]; \
91	temp[3] = T0[LSB (text[0])] \
92			^ T1[LSB (text[1])] \
93			^ T2[LSB (text[2])] \
94			^ T3[LSB (text[3])] \
95			^ roundkey[3]; \
96} /* squareRound */
97
98#define squareFinal(text, temp, S, roundkey) \
99{ \
100	text[0] = ((word32) (S[MSB (temp[0])]) << 24) \
101			^ ((word32) (S[MSB (temp[1])]) << 16) \
102			^ ((word32) (S[MSB (temp[2])]) <<  8) \
103			^  (word32) (S[MSB (temp[3])]) \
104			^ roundkey[0]; \
105	text[1] = ((word32) (S[SSB (temp[0])]) << 24) \
106			^ ((word32) (S[SSB (temp[1])]) << 16) \
107			^ ((word32) (S[SSB (temp[2])]) <<  8) \
108			^  (word32) (S[SSB (temp[3])]) \
109			^ roundkey[1]; \
110	text[2] = ((word32) (S[TSB (temp[0])]) << 24) \
111			^ ((word32) (S[TSB (temp[1])]) << 16) \
112			^ ((word32) (S[TSB (temp[2])]) <<  8) \
113			^  (word32) (S[TSB (temp[3])]) \
114			^ roundkey[2]; \
115	text[3] = ((word32) (S[LSB (temp[0])]) << 24) \
116			^ ((word32) (S[LSB (temp[1])]) << 16) \
117			^ ((word32) (S[LSB (temp[2])]) <<  8) \
118			^  (word32) (S[LSB (temp[3])]) \
119			^ roundkey[3]; \
120} /* squareFinal */
121
122typedef BlockGetAndPut<word32, BigEndian> Block;
123
124void Square::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const
125{
126	word32 text[4], temp[4];
127	Block::Get(inBlock)(text[0])(text[1])(text[2])(text[3]);
128
129	/* initial key addition */
130	text[0] ^= roundkeys[0][0];
131	text[1] ^= roundkeys[0][1];
132	text[2] ^= roundkeys[0][2];
133	text[3] ^= roundkeys[0][3];
134
135	/* ROUNDS - 1 full rounds */
136	for (int i=1; i+1<ROUNDS; i+=2)
137	{
138		squareRound (text, temp, Te[0], Te[1], Te[2], Te[3], roundkeys[i]);
139		squareRound (temp, text, Te[0], Te[1], Te[2], Te[3], roundkeys[i+1]);
140	}
141	squareRound (text, temp, Te[0], Te[1], Te[2], Te[3], roundkeys[ROUNDS-1]);
142
143	/* last round (diffusion becomes only transposition) */
144	squareFinal (text, temp, Se, roundkeys[ROUNDS]);
145
146	Block::Put(xorBlock, outBlock)(text[0])(text[1])(text[2])(text[3]);
147}
148
149void Square::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const
150{
151	word32 text[4], temp[4];
152	Block::Get(inBlock)(text[0])(text[1])(text[2])(text[3]);
153
154	/* initial key addition */
155	text[0] ^= roundkeys[0][0];
156	text[1] ^= roundkeys[0][1];
157	text[2] ^= roundkeys[0][2];
158	text[3] ^= roundkeys[0][3];
159
160	/* ROUNDS - 1 full rounds */
161	for (int i=1; i+1<ROUNDS; i+=2)
162	{
163		squareRound (text, temp, Td[0], Td[1], Td[2], Td[3], roundkeys[i]);
164		squareRound (temp, text, Td[0], Td[1], Td[2], Td[3], roundkeys[i+1]);
165	}
166	squareRound (text, temp, Td[0], Td[1], Td[2], Td[3], roundkeys[ROUNDS-1]);
167
168	/* last round (diffusion becomes only transposition) */
169	squareFinal (text, temp, Sd, roundkeys[ROUNDS]);
170
171	Block::Put(xorBlock, outBlock)(text[0])(text[1])(text[2])(text[3]);
172}
173
174NAMESPACE_END
175