MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
blowfish.cpp
1 /*
2  Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; version 2 of the License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; see the file COPYING. If not, write to the
15  Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
16  MA 02110-1301 USA.
17 */
18 
19 /* C++ code based on Wei Dai's blowfish.cpp from CryptoPP */
20 /* x86 asm is original */
21 
22 
23 #if defined(TAOCRYPT_KERNEL_MODE)
24  #define DO_TAOCRYPT_KERNEL_MODE
25 #endif // only some modules now support this
26 
27 
28 #include "runtime.hpp"
29 #include "blowfish.hpp"
30 
31 
32 
33 
34 
35 namespace TaoCrypt {
36 
37 
38 #if defined(DO_BLOWFISH_ASM)
39 
40 // ia32 optimized version
41 void Blowfish::Process(byte* out, const byte* in, word32 sz)
42 {
43  if (!isMMX) {
44  Mode_BASE::Process(out, in, sz);
45  return;
46  }
47 
48  word32 blocks = sz / BLOCK_SIZE;
49 
50  if (mode_ == ECB)
51  while (blocks--) {
52  AsmProcess(in, out);
53  out += BLOCK_SIZE;
54  in += BLOCK_SIZE;
55  }
56  else if (mode_ == CBC) {
57  if (dir_ == ENCRYPTION)
58  while (blocks--) {
59  r_[0] ^= *(word32*)in;
60  r_[1] ^= *(word32*)(in + 4);
61 
62  AsmProcess((byte*)r_, (byte*)r_);
63 
64  memcpy(out, r_, BLOCK_SIZE);
65 
66  out += BLOCK_SIZE;
67  in += BLOCK_SIZE;
68  }
69  else
70  while (blocks--) {
71  AsmProcess(in, out);
72 
73  *(word32*)out ^= r_[0];
74  *(word32*)(out + 4) ^= r_[1];
75 
76  memcpy(r_, in, BLOCK_SIZE);
77 
78  out += BLOCK_SIZE;
79  in += BLOCK_SIZE;
80  }
81  }
82 }
83 
84 #endif // DO_BLOWFISH_ASM
85 
86 
87 void Blowfish::SetKey(const byte* key_string, word32 keylength, CipherDir dir)
88 {
89  if (keylength < 4)
90  keylength = 4;
91  else if (keylength > 56)
92  keylength = 56;
93 
94  unsigned i, j=0, k;
95  word32 data, dspace[2] = {0, 0};
96 
97  memcpy(pbox_, p_init_, sizeof(p_init_));
98  memcpy(sbox_, s_init_, sizeof(s_init_));
99 
100  // Xor key string into encryption key vector
101  for (i=0 ; i<ROUNDS+2 ; ++i) {
102  data = 0;
103  for (k=0 ; k<4 ; ++k )
104  data = (data << 8) | key_string[j++ % keylength];
105  pbox_[i] ^= data;
106  }
107 
108  crypt_block(dspace, pbox_);
109 
110  for (i=0; i<ROUNDS; i+=2)
111  crypt_block(pbox_ + i, pbox_ + i + 2);
112 
113  crypt_block(pbox_ + ROUNDS, sbox_);
114 
115  for (i=0; i < 4*256-2; i+=2)
116  crypt_block(sbox_ + i, sbox_ + i + 2);
117 
118  if (dir==DECRYPTION)
119  for (i=0; i<(ROUNDS+2)/2; i++)
120  STL::swap(pbox_[i], pbox_[ROUNDS+1-i]);
121 }
122 
123 
124 #define BFBYTE_0(x) ( x &0xFF)
125 #define BFBYTE_1(x) ((x>> 8)&0xFF)
126 #define BFBYTE_2(x) ((x>>16)&0xFF)
127 #define BFBYTE_3(x) ( x>>24)
128 
129 
130 #define BF_S(Put, Get, I) (\
131  Put ^= p[I], \
132  tmp = p[18 + BFBYTE_3(Get)], \
133  tmp += p[274+ BFBYTE_2(Get)], \
134  tmp ^= p[530+ BFBYTE_1(Get)], \
135  tmp += p[786+ BFBYTE_0(Get)], \
136  Put ^= tmp \
137  )
138 
139 
140 #define BF_ROUNDS \
141  BF_S(right, left, 1); \
142  BF_S(left, right, 2); \
143  BF_S(right, left, 3); \
144  BF_S(left, right, 4); \
145  BF_S(right, left, 5); \
146  BF_S(left, right, 6); \
147  BF_S(right, left, 7); \
148  BF_S(left, right, 8); \
149  BF_S(right, left, 9); \
150  BF_S(left, right, 10); \
151  BF_S(right, left, 11); \
152  BF_S(left, right, 12); \
153  BF_S(right, left, 13); \
154  BF_S(left, right, 14); \
155  BF_S(right, left, 15); \
156  BF_S(left, right, 16);
157 
158 #define BF_EXTRA_ROUNDS \
159  BF_S(right, left, 17); \
160  BF_S(left, right, 18); \
161  BF_S(right, left, 19); \
162  BF_S(left, right, 20);
163 
164 
165 // Used by key setup, no byte swapping
166 void Blowfish::crypt_block(const word32 in[2], word32 out[2]) const
167 {
168  word32 left = in[0];
169  word32 right = in[1];
170 
171  const word32 *const s = sbox_;
172  const word32* p = pbox_;
173 
174  left ^= p[0];
175 
176  // roll back up and use s and p index instead of just p
177  for (unsigned i = 0; i < ROUNDS / 2; i++) {
178  right ^= (((s[GETBYTE(left,3)] + s[256+GETBYTE(left,2)])
179  ^ s[2*256+GETBYTE(left,1)]) + s[3*256+GETBYTE(left,0)])
180  ^ p[2*i+1];
181 
182  left ^= (((s[GETBYTE(right,3)] + s[256+GETBYTE(right,2)])
183  ^ s[2*256+GETBYTE(right,1)]) + s[3*256+GETBYTE(right,0)])
184  ^ p[2*i+2];
185  }
186 
187  right ^= p[ROUNDS + 1];
188 
189  out[0] = right;
190  out[1] = left;
191 }
192 
193 
194 typedef BlockGetAndPut<word32, BigEndian> gpBlock;
195 
196 void Blowfish::ProcessAndXorBlock(const byte* in, const byte* xOr, byte* out)
197  const
198 {
199  word32 left, right;
200  const word32 *const s = sbox_;
201  const word32* p = pbox_;
202 
203  gpBlock::Get(in)(left)(right);
204  left ^= p[0];
205 
206  // roll back up and use s and p index instead of just p
207  for (unsigned i = 0; i < ROUNDS / 2; i++) {
208  right ^= (((s[GETBYTE(left,3)] + s[256+GETBYTE(left,2)])
209  ^ s[2*256+GETBYTE(left,1)]) + s[3*256+GETBYTE(left,0)])
210  ^ p[2*i+1];
211 
212  left ^= (((s[GETBYTE(right,3)] + s[256+GETBYTE(right,2)])
213  ^ s[2*256+GETBYTE(right,1)]) + s[3*256+GETBYTE(right,0)])
214  ^ p[2*i+2];
215  }
216 
217  right ^= p[ROUNDS + 1];
218 
219  gpBlock::Put(xOr, out)(right)(left);
220 }
221 
222 
223 #if defined(DO_BLOWFISH_ASM)
224  #ifdef __GNUC__
225  #define AS1(x) asm(#x);
226  #define AS2(x, y) asm(#x ", " #y);
227 
228  #define PROLOG() \
229  asm(".intel_syntax noprefix"); \
230  AS2( movd mm3, edi ) \
231  AS2( movd mm4, ebx ) \
232  AS2( movd mm5, esi ) \
233  AS2( mov ecx, DWORD PTR [ebp + 8] ) \
234  AS2( mov esi, DWORD PTR [ebp + 12] )
235 
236  #define EPILOG() \
237  AS2( movd esi, mm5 ) \
238  AS2( movd ebx, mm4 ) \
239  AS2( movd edi, mm3 ) \
240  AS1( emms ) \
241  asm(".att_syntax");
242  #else
243  #define AS1(x) __asm x
244  #define AS2(x, y) __asm x, y
245 
246  #define PROLOG() \
247  AS1( push ebp ) \
248  AS2( mov ebp, esp ) \
249  AS2( movd mm3, edi ) \
250  AS2( movd mm4, ebx ) \
251  AS2( movd mm5, esi ) \
252  AS2( mov esi, DWORD PTR [ebp + 8] )
253 
254  #define EPILOG() \
255  AS2( movd esi, mm5 ) \
256  AS2( movd ebx, mm4 ) \
257  AS2( movd edi, mm3 ) \
258  AS2( mov esp, ebp ) \
259  AS1( pop ebp ) \
260  AS1( emms ) \
261  AS1( ret 8 )
262 
263  #endif
264 
265 
266 #define BF_ROUND(P, G, I) \
267  /* Put ^= p[I] */ \
268  AS2( xor P, [edi + I*4] ) \
269  /* tmp = p[18 + BFBYTE_3(Get)] */ \
270  AS2( mov ecx, G ) \
271  AS2( shr ecx, 16 ) \
272  AS2( movzx edx, ch ) \
273  AS2( mov esi, [edi + edx*4 + 72] ) \
274  /* tmp += p[274+ BFBYTE_2(Get)] */ \
275  AS2( movzx ecx, cl ) \
276  AS2( add esi, [edi + ecx*4 + 1096] ) \
277  /* tmp ^= p[530+ BFBYTE_1(Get)] */ \
278  AS2( mov ecx, G ) \
279  AS2( movzx edx, ch ) \
280  AS2( xor esi, [edi + edx*4 + 2120] ) \
281  /* tmp += p[786+ BFBYTE_0(Get)] */ \
282  AS2( movzx ecx, cl ) \
283  AS2( add esi, [edi + ecx*4 + 3144] ) \
284  /* Put ^= tmp */ \
285  AS2( xor P, esi )
286 
287 
288 #ifdef _MSC_VER
289  __declspec(naked)
290 #endif
291 void Blowfish::AsmProcess(const byte* inBlock, byte* outBlock) const
292 {
293  PROLOG()
294 
295  #ifdef OLD_GCC_OFFSET
296  AS2( lea edi, [ecx + 60] ) // pbox
297  #else
298  AS2( lea edi, [ecx + 56] ) // pbox
299  #endif
300 
301  AS2( mov eax, DWORD PTR [esi] )
302  AS2( mov edx, DWORD PTR [edi] )
303  AS1( bswap eax )
304 
305  AS2( mov ebx, DWORD PTR [esi + 4] )
306  AS2( xor eax, edx ) // left
307  AS1( bswap ebx ) // right
308 
309 
310  BF_ROUND(ebx, eax, 1)
311  BF_ROUND(eax, ebx, 2)
312  BF_ROUND(ebx, eax, 3)
313  BF_ROUND(eax, ebx, 4)
314  BF_ROUND(ebx, eax, 5)
315  BF_ROUND(eax, ebx, 6)
316  BF_ROUND(ebx, eax, 7)
317  BF_ROUND(eax, ebx, 8)
318  BF_ROUND(ebx, eax, 9)
319  BF_ROUND(eax, ebx, 10)
320  BF_ROUND(ebx, eax, 11)
321  BF_ROUND(eax, ebx, 12)
322  BF_ROUND(ebx, eax, 13)
323  BF_ROUND(eax, ebx, 14)
324  BF_ROUND(ebx, eax, 15)
325  BF_ROUND(eax, ebx, 16)
326  #if ROUNDS == 20
327  BF_ROUND(ebx, eax, 17)
328  BF_ROUND(eax, ebx, 18)
329  BF_ROUND(ebx, eax, 19)
330  BF_ROUND(eax, ebx, 20)
331 
332  AS2( xor ebx, [edi + 84] ) // 20 + 1 (x4)
333  #else
334  AS2( xor ebx, [edi + 68] ) // 16 + 1 (x4)
335  #endif
336 
337  #ifdef __GNUC__
338  AS2( mov edi, [ebp + 16] ) // outBlock
339  #else
340  AS2( mov edi, [ebp + 12] ) // outBlock
341  #endif
342 
343  AS1( bswap ebx )
344  AS1( bswap eax )
345 
346  AS2( mov [edi] , ebx )
347  AS2( mov [edi + 4], eax )
348 
349  EPILOG()
350 }
351 
352 
353 #endif // DO_BLOWFISH_ASM
354 
355 
356 } // namespace
357