Crypto++
|
00001 // idea.cpp - written and placed in the public domain by Wei Dai 00002 00003 #include "pch.h" 00004 #include "idea.h" 00005 #include "misc.h" 00006 00007 NAMESPACE_BEGIN(CryptoPP) 00008 00009 static const int IDEA_KEYLEN=(6*IDEA::ROUNDS+4); // key schedule length in # of word16s 00010 00011 #define low16(x) ((x)&0xffff) // compiler should be able to optimize this away if word is 16 bits 00012 #define high16(x) ((x)>>16) 00013 00014 CRYPTOPP_COMPILE_ASSERT(sizeof(IDEA::Word) >= 2); 00015 00016 // should use an inline function but macros are still faster in MSVC 4.0 00017 #define DirectMUL(a,b) \ 00018 { \ 00019 assert(b <= 0xffff); \ 00020 \ 00021 word32 p=(word32)low16(a)*b; \ 00022 \ 00023 if (p) \ 00024 { \ 00025 p = low16(p) - high16(p); \ 00026 a = (IDEA::Word)p - (IDEA::Word)high16(p); \ 00027 } \ 00028 else \ 00029 a = 1-a-b; \ 00030 } 00031 00032 #ifdef IDEA_LARGECACHE 00033 volatile bool IDEA::Base::tablesBuilt = false; 00034 word16 IDEA::Base::log[0x10000]; 00035 word16 IDEA::Base::antilog[0x10000]; 00036 00037 void IDEA::Base::BuildLogTables() 00038 { 00039 if (tablesBuilt) 00040 return; 00041 else 00042 { 00043 tablesBuilt = true; 00044 00045 IDEA::Word x=1; 00046 word32 i; 00047 00048 for (i=0; i<0x10000; i++) 00049 { 00050 antilog[i] = (word16)x; 00051 DirectMUL(x, 3); 00052 } 00053 00054 for (i=0; i<0x10000; i++) 00055 log[antilog[i]] = (word16)i; 00056 } 00057 } 00058 00059 void IDEA::Base::LookupKeyLogs() 00060 { 00061 IDEA::Word* Z=key; 00062 int r=ROUNDS; 00063 do 00064 { 00065 Z[0] = log[Z[0]]; 00066 Z[3] = log[Z[3]]; 00067 Z[4] = log[Z[4]]; 00068 Z[5] = log[Z[5]]; 00069 Z+=6; 00070 } while (--r); 00071 Z[0] = log[Z[0]]; 00072 Z[3] = log[Z[3]]; 00073 } 00074 00075 inline void IDEA::Base::LookupMUL(IDEA::Word &a, IDEA::Word b) 00076 { 00077 a = antilog[low16(log[low16(a)]+b)]; 00078 } 00079 #endif // IDEA_LARGECACHE 00080 00081 void IDEA::Base::UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs &) 00082 { 00083 AssertValidKeyLength(length); 00084 00085 #ifdef IDEA_LARGECACHE 00086 BuildLogTables(); 00087 #endif 00088 00089 EnKey(userKey); 00090 00091 if (!IsForwardTransformation()) 00092 DeKey(); 00093 00094 #ifdef IDEA_LARGECACHE 00095 LookupKeyLogs(); 00096 #endif 00097 } 00098 00099 void IDEA::Base::EnKey (const byte *userKey) 00100 { 00101 unsigned int i; 00102 00103 for (i=0; i<8; i++) 00104 m_key[i] = ((IDEA::Word)userKey[2*i]<<8) | userKey[2*i+1]; 00105 00106 for (; i<IDEA_KEYLEN; i++) 00107 { 00108 unsigned int j = RoundDownToMultipleOf(i,8U)-8; 00109 m_key[i] = low16((m_key[j+(i+1)%8] << 9) | (m_key[j+(i+2)%8] >> 7)); 00110 } 00111 } 00112 00113 static IDEA::Word MulInv(IDEA::Word x) 00114 { 00115 IDEA::Word y=x; 00116 for (unsigned i=0; i<15; i++) 00117 { 00118 DirectMUL(y,low16(y)); 00119 DirectMUL(y,x); 00120 } 00121 return low16(y); 00122 } 00123 00124 static inline IDEA::Word AddInv(IDEA::Word x) 00125 { 00126 return low16(0-x); 00127 } 00128 00129 void IDEA::Base::DeKey() 00130 { 00131 FixedSizeSecBlock<IDEA::Word, 6*ROUNDS+4> tempkey; 00132 size_t i; 00133 00134 for (i=0; i<ROUNDS; i++) 00135 { 00136 tempkey[i*6+0] = MulInv(m_key[(ROUNDS-i)*6+0]); 00137 tempkey[i*6+1] = AddInv(m_key[(ROUNDS-i)*6+1+(i>0)]); 00138 tempkey[i*6+2] = AddInv(m_key[(ROUNDS-i)*6+2-(i>0)]); 00139 tempkey[i*6+3] = MulInv(m_key[(ROUNDS-i)*6+3]); 00140 tempkey[i*6+4] = m_key[(ROUNDS-1-i)*6+4]; 00141 tempkey[i*6+5] = m_key[(ROUNDS-1-i)*6+5]; 00142 } 00143 00144 tempkey[i*6+0] = MulInv(m_key[(ROUNDS-i)*6+0]); 00145 tempkey[i*6+1] = AddInv(m_key[(ROUNDS-i)*6+1]); 00146 tempkey[i*6+2] = AddInv(m_key[(ROUNDS-i)*6+2]); 00147 tempkey[i*6+3] = MulInv(m_key[(ROUNDS-i)*6+3]); 00148 00149 m_key = tempkey; 00150 } 00151 00152 #ifdef IDEA_LARGECACHE 00153 #define MUL(a,b) LookupMUL(a,b) 00154 #else 00155 #define MUL(a,b) DirectMUL(a,b) 00156 #endif 00157 00158 void IDEA::Base::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const 00159 { 00160 typedef BlockGetAndPut<word16, BigEndian> Block; 00161 00162 const IDEA::Word *key = m_key; 00163 IDEA::Word x0,x1,x2,x3,t0,t1; 00164 Block::Get(inBlock)(x0)(x1)(x2)(x3); 00165 00166 for (unsigned int i=0; i<ROUNDS; i++) 00167 { 00168 MUL(x0, key[i*6+0]); 00169 x1 += key[i*6+1]; 00170 x2 += key[i*6+2]; 00171 MUL(x3, key[i*6+3]); 00172 t0 = x0^x2; 00173 MUL(t0, key[i*6+4]); 00174 t1 = t0 + (x1^x3); 00175 MUL(t1, key[i*6+5]); 00176 t0 += t1; 00177 x0 ^= t1; 00178 x3 ^= t0; 00179 t0 ^= x1; 00180 x1 = x2^t1; 00181 x2 = t0; 00182 } 00183 00184 MUL(x0, key[ROUNDS*6+0]); 00185 x2 += key[ROUNDS*6+1]; 00186 x1 += key[ROUNDS*6+2]; 00187 MUL(x3, key[ROUNDS*6+3]); 00188 00189 Block::Put(xorBlock, outBlock)(x0)(x2)(x1)(x3); 00190 } 00191 00192 NAMESPACE_END