1// idea.cpp - written and placed in the public domain by Wei Dai
2
3#include "pch.h"
4#include "idea.h"
5#include "misc.h"
6
7NAMESPACE_BEGIN(CryptoPP)
8
9static const int IDEA_KEYLEN=(6*IDEA::ROUNDS+4);  // key schedule length in # of word16s
10
11#define low16(x) ((x)&0xffff)	// compiler should be able to optimize this away if word is 16 bits
12#define high16(x) ((x)>>16)
13
14CRYPTOPP_COMPILE_ASSERT(sizeof(IDEA::Word) >= 2);
15
16// should use an inline function but macros are still faster in MSVC 4.0
17#define DirectMUL(a,b)					\
18{										\
19	assert(b <= 0xffff);				\
20										\
21	word32 p=(word32)low16(a)*b;		\
22										\
23	if (p)								\
24	{									\
25		p = low16(p) - high16(p);		\
26		a = (IDEA::Word)p - (IDEA::Word)high16(p);	\
27	}									\
28	else								\
29		a = 1-a-b;						\
30}
31
32#ifdef IDEA_LARGECACHE
33bool IDEA::Base::tablesBuilt = false;
34word16 IDEA::Base::log[0x10000];
35word16 IDEA::Base::antilog[0x10000];
36
37void IDEA::Base::BuildLogTables()
38{
39	if (tablesBuilt)
40		return;
41	else
42	{
43		tablesBuilt = true;
44
45		IDEA::Word x=1;
46		word32 i;
47
48		for (i=0; i<0x10000; i++)
49		{
50			antilog[i] = (word16)x;
51			DirectMUL(x, 3);
52		}
53
54		for (i=0; i<0x10000; i++)
55			log[antilog[i]] = (word16)i;
56	}
57}
58
59void IDEA::Base::LookupKeyLogs()
60{
61	IDEA::Word* Z=key;
62	int r=ROUNDS;
63	do
64	{
65		Z[0] = log[Z[0]];
66		Z[3] = log[Z[3]];
67		Z[4] = log[Z[4]];
68		Z[5] = log[Z[5]];
69		Z+=6;
70	} while (--r);
71	Z[0] = log[Z[0]];
72	Z[3] = log[Z[3]];
73}
74
75inline void IDEA::Base::LookupMUL(IDEA::Word &a, IDEA::Word b)
76{
77	a = antilog[low16(log[low16(a)]+b)];
78}
79#endif // IDEA_LARGECACHE
80
81void IDEA::Base::UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs &)
82{
83	AssertValidKeyLength(length);
84
85#ifdef IDEA_LARGECACHE
86	BuildLogTables();
87#endif
88
89	EnKey(userKey);
90
91	if (!IsForwardTransformation())
92		DeKey();
93
94#ifdef IDEA_LARGECACHE
95	LookupKeyLogs();
96#endif
97}
98
99void IDEA::Base::EnKey (const byte *userKey)
100{
101	unsigned int i;
102
103	for (i=0; i<8; i++)
104		m_key[i] = ((IDEA::Word)userKey[2*i]<<8) | userKey[2*i+1];
105
106	for (; i<IDEA_KEYLEN; i++)
107	{
108		unsigned int j = RoundDownToMultipleOf(i,8U)-8;
109		m_key[i] = low16((m_key[j+(i+1)%8] << 9) | (m_key[j+(i+2)%8] >> 7));
110	}
111}
112
113static IDEA::Word MulInv(IDEA::Word x)
114{
115	IDEA::Word y=x;
116	for (unsigned i=0; i<15; i++)
117	{
118		DirectMUL(y,low16(y));
119		DirectMUL(y,x);
120	}
121	return low16(y);
122}
123
124static inline IDEA::Word AddInv(IDEA::Word x)
125{
126	return low16(0-x);
127}
128
129void IDEA::Base::DeKey()
130{
131	FixedSizeSecBlock<IDEA::Word, 6*ROUNDS+4> tempkey;
132	unsigned int i;
133
134	for (i=0; i<ROUNDS; i++)
135	{
136		tempkey[i*6+0] = MulInv(m_key[(ROUNDS-i)*6+0]);
137		tempkey[i*6+1] = AddInv(m_key[(ROUNDS-i)*6+1+(i>0)]);
138		tempkey[i*6+2] = AddInv(m_key[(ROUNDS-i)*6+2-(i>0)]);
139		tempkey[i*6+3] = MulInv(m_key[(ROUNDS-i)*6+3]);
140		tempkey[i*6+4] =        m_key[(ROUNDS-1-i)*6+4];
141		tempkey[i*6+5] =        m_key[(ROUNDS-1-i)*6+5];
142	}
143
144	tempkey[i*6+0] = MulInv(m_key[(ROUNDS-i)*6+0]);
145	tempkey[i*6+1] = AddInv(m_key[(ROUNDS-i)*6+1]);
146	tempkey[i*6+2] = AddInv(m_key[(ROUNDS-i)*6+2]);
147	tempkey[i*6+3] = MulInv(m_key[(ROUNDS-i)*6+3]);
148
149	m_key = tempkey;
150}
151
152#ifdef IDEA_LARGECACHE
153#define MUL(a,b) LookupMUL(a,b)
154#else
155#define MUL(a,b) DirectMUL(a,b)
156#endif
157
158void IDEA::Base::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const
159{
160	typedef BlockGetAndPut<word16, BigEndian> Block;
161
162	const IDEA::Word *key = m_key;
163	IDEA::Word x0,x1,x2,x3,t0,t1;
164	Block::Get(inBlock)(x0)(x1)(x2)(x3);
165
166	for (unsigned int i=0; i<ROUNDS; i++)
167	{
168		MUL(x0, key[i*6+0]);
169		x1 += key[i*6+1];
170		x2 += key[i*6+2];
171		MUL(x3, key[i*6+3]);
172		t0 = x0^x2;
173		MUL(t0, key[i*6+4]);
174		t1 = t0 + (x1^x3);
175		MUL(t1, key[i*6+5]);
176		t0 += t1;
177		x0 ^= t1;
178		x3 ^= t0;
179		t0 ^= x1;
180		x1 = x2^t1;
181		x2 = t0;
182	}
183
184	MUL(x0, key[ROUNDS*6+0]);
185	x2 += key[ROUNDS*6+1];
186	x1 += key[ROUNDS*6+2];
187	MUL(x3, key[ROUNDS*6+3]);
188
189	Block::Put(xorBlock, outBlock)(x0)(x2)(x1)(x3);
190}
191
192NAMESPACE_END
193