2 Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
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.
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.
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,
19 /* C++ code based on Wei Dai's blowfish.cpp from CryptoPP */
20 /* x86 asm is original */
23 #if defined(TAOCRYPT_KERNEL_MODE)
24 #define DO_TAOCRYPT_KERNEL_MODE
25 #endif // only some modules now support this
28 #include "runtime.hpp"
29 #include "blowfish.hpp"
38 #if defined(DO_BLOWFISH_ASM)
40 // ia32 optimized version
41 void Blowfish::Process(byte
* out
, const byte
* in
, word32 sz
)
44 Mode_BASE::Process(out
, in
, sz
);
48 word32 blocks
= sz
/ BLOCK_SIZE
;
56 else if (mode_
== CBC
) {
57 if (dir_
== ENCRYPTION
)
59 r_
[0] ^= *(word32
*)in
;
60 r_
[1] ^= *(word32
*)(in
+ 4);
62 AsmProcess((byte
*)r_
, (byte
*)r_
);
64 memcpy(out
, r_
, BLOCK_SIZE
);
73 *(word32
*)out
^= r_
[0];
74 *(word32
*)(out
+ 4) ^= r_
[1];
76 memcpy(r_
, in
, BLOCK_SIZE
);
84 #endif // DO_BLOWFISH_ASM
87 void Blowfish::SetKey(const byte
* key_string
, word32 keylength
, CipherDir dir
)
91 else if (keylength
> 56)
95 word32 data
, dspace
[2] = {0, 0};
97 memcpy(pbox_
, p_init_
, sizeof(p_init_
));
98 memcpy(sbox_
, s_init_
, sizeof(s_init_
));
100 // Xor key string into encryption key vector
101 for (i
=0 ; i
<ROUNDS
+2 ; ++i
) {
103 for (k
=0 ; k
<4 ; ++k
)
104 data
= (data
<< 8) | key_string
[j
++ % keylength
];
108 crypt_block(dspace
, pbox_
);
110 for (i
=0; i
<ROUNDS
; i
+=2)
111 crypt_block(pbox_
+ i
, pbox_
+ i
+ 2);
113 crypt_block(pbox_
+ ROUNDS
, sbox_
);
115 for (i
=0; i
< 4*256-2; i
+=2)
116 crypt_block(sbox_
+ i
, sbox_
+ i
+ 2);
119 for (i
=0; i
<(ROUNDS
+2)/2; i
++)
120 STL::swap(pbox_
[i
], pbox_
[ROUNDS
+1-i
]);
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)
130 #define BF_S(Put, Get, 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)], \
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);
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);
165 // Used by key setup, no byte swapping
166 void Blowfish::crypt_block(const word32 in
[2], word32 out
[2]) const
169 word32 right
= in
[1];
171 const word32
*const s
= sbox_
;
172 const word32
* p
= pbox_
;
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)])
182 left
^= (((s
[GETBYTE(right
,3)] + s
[256+GETBYTE(right
,2)])
183 ^ s
[2*256+GETBYTE(right
,1)]) + s
[3*256+GETBYTE(right
,0)])
187 right
^= p
[ROUNDS
+ 1];
194 typedef BlockGetAndPut
<word32
, BigEndian
> gpBlock
;
196 void Blowfish::ProcessAndXorBlock(const byte
* in
, const byte
* xOr
, byte
* out
)
200 const word32
*const s
= sbox_
;
201 const word32
* p
= pbox_
;
203 gpBlock::Get(in
)(left
)(right
);
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)])
212 left
^= (((s
[GETBYTE(right
,3)] + s
[256+GETBYTE(right
,2)])
213 ^ s
[2*256+GETBYTE(right
,1)]) + s
[3*256+GETBYTE(right
,0)])
217 right
^= p
[ROUNDS
+ 1];
219 gpBlock::Put(xOr
, out
)(right
)(left
);
223 #if defined(DO_BLOWFISH_ASM)
225 #define AS1(x) asm(#x);
226 #define AS2(x, y) asm(#x ", " #y);
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] )
237 AS2( movd esi, mm5 ) \
238 AS2( movd ebx, mm4 ) \
239 AS2( movd edi, mm3 ) \
243 #define AS1(x) __asm x
244 #define AS2(x, y) __asm x, y
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] )
255 AS2( movd esi, mm5 ) \
256 AS2( movd ebx, mm4 ) \
257 AS2( movd edi, mm3 ) \
258 AS2( mov esp, ebp ) \
266 #define BF_ROUND(P, G, I) \
268 AS2( xor P, [edi + I*4] ) \
269 /* tmp = p[18 + BFBYTE_3(Get)] */ \
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)] */ \
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] ) \
291 void Blowfish::AsmProcess(const byte
* inBlock
, byte
* outBlock
) const
295 #ifdef OLD_GCC_OFFSET
296 AS2( lea edi
, [ecx
+ 60] ) // pbox
298 AS2( lea edi
, [ecx
+ 56] ) // pbox
301 AS2( mov eax
, DWORD PTR
[esi
] )
302 AS2( mov edx
, DWORD PTR
[edi
] )
305 AS2( mov ebx
, DWORD PTR
[esi
+ 4] )
306 AS2( xor eax
, edx
) // left
307 AS1( bswap ebx
) // right
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)
327 BF_ROUND(ebx
, eax
, 17)
328 BF_ROUND(eax
, ebx
, 18)
329 BF_ROUND(ebx
, eax
, 19)
330 BF_ROUND(eax
, ebx
, 20)
332 AS2( xor ebx
, [edi
+ 84] ) // 20 + 1 (x4)
334 AS2( xor ebx
, [edi
+ 68] ) // 16 + 1 (x4)
338 AS2( mov edi
, [ebp
+ 16] ) // outBlock
340 AS2( mov edi
, [ebp
+ 12] ) // outBlock
346 AS2( mov
[edi
] , ebx
)
347 AS2( mov
[edi
+ 4], eax
)
353 #endif // DO_BLOWFISH_ASM