2017-08-08 13:53:47 +02:00
|
|
|
// blowfish.cpp C++ class implementation of the BLOWFISH encryption algorithm
|
|
|
|
// _THE BLOWFISH ENCRYPTION ALGORITHM_
|
|
|
|
// by Bruce Schneier
|
|
|
|
// Revised code--3/20/94
|
|
|
|
// Converted to C++ class 5/96, Jim Conger
|
|
|
|
|
2017-08-09 23:49:00 +01:00
|
|
|
#include <cstdint>
|
2017-08-08 13:53:47 +02:00
|
|
|
#include "blowfish.h"
|
2018-08-29 21:40:59 +02:00
|
|
|
#include "blowfish.h2" // holds the random digit tables
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
#define S( x, i ) (SBoxes[i][x.w.byte##i])
|
|
|
|
#define bf_F( x ) (((S(x,0) + S(x,1)) ^ S(x,2)) + S(x,3))
|
|
|
|
#define ROUND( a, b, n ) (a.dword ^= bf_F(b) ^ PArray[n])
|
2017-08-08 13:53:47 +02:00
|
|
|
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
BlowFish::BlowFish()
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
PArray = new DWORD[18];
|
|
|
|
SBoxes = new DWORD[4][256];
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
BlowFish::~BlowFish()
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
delete PArray;
|
|
|
|
delete[] SBoxes;
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// the low level (private) encryption function
|
|
|
|
void BlowFish::Blowfish_encipher( DWORD* xl, DWORD* xr )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
union aword Xl, Xr;
|
|
|
|
|
|
|
|
Xl.dword = *xl;
|
|
|
|
Xr.dword = *xr;
|
|
|
|
|
|
|
|
Xl.dword ^= PArray[ 0 ];
|
|
|
|
ROUND ( Xr, Xl, 1 );
|
|
|
|
ROUND ( Xl, Xr, 2 );
|
|
|
|
ROUND ( Xr, Xl, 3 );
|
|
|
|
ROUND ( Xl, Xr, 4 );
|
|
|
|
ROUND ( Xr, Xl, 5 );
|
|
|
|
ROUND ( Xl, Xr, 6 );
|
|
|
|
ROUND ( Xr, Xl, 7 );
|
|
|
|
ROUND ( Xl, Xr, 8 );
|
|
|
|
ROUND ( Xr, Xl, 9 );
|
|
|
|
ROUND ( Xl, Xr, 10 );
|
|
|
|
ROUND ( Xr, Xl, 11 );
|
|
|
|
ROUND ( Xl, Xr, 12 );
|
|
|
|
ROUND ( Xr, Xl, 13 );
|
|
|
|
ROUND ( Xl, Xr, 14 );
|
|
|
|
ROUND ( Xr, Xl, 15 );
|
|
|
|
ROUND ( Xl, Xr, 16 );
|
|
|
|
Xr.dword ^= PArray[ 17 ];
|
|
|
|
|
|
|
|
*xr = Xl.dword;
|
|
|
|
*xl = Xr.dword;
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// the low level (private) decryption function
|
|
|
|
void BlowFish::Blowfish_decipher( DWORD* xl, DWORD* xr )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
union aword Xl;
|
|
|
|
union aword Xr;
|
|
|
|
|
|
|
|
Xl.dword = *xl;
|
|
|
|
Xr.dword = *xr;
|
|
|
|
|
|
|
|
Xl.dword ^= PArray[ 17 ];
|
|
|
|
ROUND ( Xr, Xl, 16 );
|
|
|
|
ROUND ( Xl, Xr, 15 );
|
|
|
|
ROUND ( Xr, Xl, 14 );
|
|
|
|
ROUND ( Xl, Xr, 13 );
|
|
|
|
ROUND ( Xr, Xl, 12 );
|
|
|
|
ROUND ( Xl, Xr, 11 );
|
|
|
|
ROUND ( Xr, Xl, 10 );
|
|
|
|
ROUND ( Xl, Xr, 9 );
|
|
|
|
ROUND ( Xr, Xl, 8 );
|
|
|
|
ROUND ( Xl, Xr, 7 );
|
|
|
|
ROUND ( Xr, Xl, 6 );
|
|
|
|
ROUND ( Xl, Xr, 5 );
|
|
|
|
ROUND ( Xr, Xl, 4 );
|
|
|
|
ROUND ( Xl, Xr, 3 );
|
|
|
|
ROUND ( Xr, Xl, 2 );
|
|
|
|
ROUND ( Xl, Xr, 1 );
|
|
|
|
Xr.dword ^= PArray[ 0 ];
|
|
|
|
|
|
|
|
*xl = Xr.dword;
|
|
|
|
*xr = Xl.dword;
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// constructs the enctryption sieve
|
|
|
|
void BlowFish::initialize( BYTE key[], int32_t keybytes )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
int i, j;
|
|
|
|
DWORD datal, datar;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// first fill arrays from data tables
|
|
|
|
for( i = 0; i < 18; i++ )
|
|
|
|
PArray[ i ] = bf_P[ i ];
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
for( i = 0; i < 4; i++ )
|
|
|
|
{
|
|
|
|
for( j = 0; j < 256; j++ )
|
|
|
|
SBoxes[ i ][ j ] = bf_S[ i ][ j ];
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2017-08-11 22:56:30 +01:00
|
|
|
int32_t v12; // eax@6
|
|
|
|
int32_t v13; // ecx@6
|
|
|
|
int32_t v14; // eax@8
|
|
|
|
int32_t v15; // edx@8
|
|
|
|
int32_t v16; // edx@8
|
|
|
|
int32_t v17; // eax@10
|
|
|
|
int32_t v18; // ecx@10
|
|
|
|
int32_t v19; // ecx@10
|
|
|
|
int32_t v20; // edx@12
|
|
|
|
int32_t v21; // edx@12
|
2017-08-08 13:53:47 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
2017-08-11 22:56:30 +01:00
|
|
|
int32_t v10 = keybytes;
|
2018-08-29 21:40:59 +02:00
|
|
|
uintptr_t v9 = ( uintptr_t ) key;
|
2017-08-11 22:56:30 +01:00
|
|
|
int32_t v8 = 0;
|
|
|
|
int32_t v11 = 0;
|
2018-08-29 21:40:59 +02:00
|
|
|
do
|
|
|
|
{
|
|
|
|
v13 = ( char ) ( *( BYTE* ) ( v8 + v9 ) );
|
2017-08-08 13:53:47 +02:00
|
|
|
v12 = v8 + 1;
|
2018-08-29 21:40:59 +02:00
|
|
|
if( v12 >= v10 )
|
2017-08-08 13:53:47 +02:00
|
|
|
v12 = 0;
|
2018-08-29 21:40:59 +02:00
|
|
|
v16 = ( char ) *( BYTE* ) ( v12 + v9 );
|
2017-08-08 13:53:47 +02:00
|
|
|
v14 = v12 + 1;
|
2018-08-29 21:40:59 +02:00
|
|
|
v15 = ( v13 << 8 ) | v16;
|
|
|
|
if( v14 >= v10 )
|
2017-08-08 13:53:47 +02:00
|
|
|
v14 = 0;
|
2018-08-29 21:40:59 +02:00
|
|
|
v19 = ( char ) *( BYTE* ) ( v14 + v9 );
|
2017-08-08 13:53:47 +02:00
|
|
|
v17 = v14 + 1;
|
2018-08-29 21:40:59 +02:00
|
|
|
v18 = ( v15 << 8 ) | v19;
|
|
|
|
if( v17 >= v10 )
|
2017-08-08 13:53:47 +02:00
|
|
|
v17 = 0;
|
2018-08-29 21:40:59 +02:00
|
|
|
v21 = ( char ) *( BYTE* ) ( v17 + v9 );
|
2017-08-08 13:53:47 +02:00
|
|
|
v8 = v17 + 1;
|
2018-08-29 21:40:59 +02:00
|
|
|
v20 = ( v18 << 8 ) | v21;
|
|
|
|
if( v8 >= v10 )
|
2017-08-08 13:53:47 +02:00
|
|
|
v8 = 0;
|
2018-08-29 21:40:59 +02:00
|
|
|
*( ( DWORD* ) PArray + v11++ ) ^= v20;
|
|
|
|
} while( v11 < 18 );
|
|
|
|
|
|
|
|
|
|
|
|
datal = 0;
|
|
|
|
datar = 0;
|
|
|
|
|
|
|
|
for( i = 0; i < NPASS + 2; i += 2 )
|
|
|
|
{
|
|
|
|
Blowfish_encipher( &datal, &datar );
|
|
|
|
PArray[ i ] = datal;
|
|
|
|
PArray[ i + 1 ] = datar;
|
|
|
|
}
|
|
|
|
|
|
|
|
for( i = 0; i < 4; ++i )
|
|
|
|
{
|
|
|
|
for( j = 0; j < 256; j += 2 )
|
|
|
|
{
|
|
|
|
Blowfish_encipher( &datal, &datar );
|
|
|
|
SBoxes[ i ][ j ] = datal;
|
|
|
|
SBoxes[ i ][ j + 1 ] = datar;
|
|
|
|
}
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// get output length, which must be even MOD 8
|
|
|
|
DWORD BlowFish::GetOutputLength( DWORD lInputLong )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
DWORD lVal;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
lVal = lInputLong % 8; // find out if uneven number of bytes at the end
|
|
|
|
if( lVal != 0 )
|
|
|
|
return lInputLong + 8 - lVal;
|
|
|
|
else
|
|
|
|
return lInputLong;
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// Encode pIntput into pOutput. Input length in lSize. Returned value
|
|
|
|
// is length of output which will be even MOD 8 bytes. Input buffer and
|
|
|
|
// output buffer can be the same, but be sure buffer length is even MOD 8.
|
|
|
|
DWORD BlowFish::Encode( BYTE* pInput, BYTE* pOutput, DWORD lSize )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
DWORD lCount, lOutSize, lGoodBytes;
|
|
|
|
BYTE* pi, * po;
|
|
|
|
int i, j;
|
|
|
|
int SameDest = ( pInput == pOutput ? 1 : 0 );
|
|
|
|
|
|
|
|
lOutSize = GetOutputLength( lSize );
|
|
|
|
for( lCount = 0; lCount < lOutSize; lCount += 8 )
|
|
|
|
{
|
|
|
|
if( SameDest ) // if encoded data is being written into input buffer
|
|
|
|
{
|
|
|
|
if( lCount < lSize - 7 ) // if not dealing with uneven bytes at end
|
|
|
|
{
|
|
|
|
Blowfish_encipher( ( DWORD* ) pInput,
|
|
|
|
( DWORD* ) ( pInput + 4 ) );
|
|
|
|
}
|
|
|
|
else // pad end of data with null bytes to complete encryption
|
|
|
|
{
|
|
|
|
po = pInput + lSize; // point at byte past the end of actual data
|
|
|
|
j = ( int ) ( lOutSize - lSize ); // number of bytes to set to null
|
|
|
|
for( i = 0; i < j; i++ )
|
|
|
|
*po++ = 0;
|
|
|
|
Blowfish_encipher( ( DWORD* ) pInput,
|
|
|
|
( DWORD* ) ( pInput + 4 ) );
|
|
|
|
}
|
|
|
|
pInput += 8;
|
|
|
|
}
|
|
|
|
else // output buffer not equal to input buffer, so must copy
|
|
|
|
{ // input to output buffer prior to encrypting
|
|
|
|
if( lCount < lSize - 7 ) // if not dealing with uneven bytes at end
|
|
|
|
{
|
|
|
|
pi = pInput;
|
|
|
|
po = pOutput;
|
|
|
|
for( i = 0; i < 8; i++ )
|
2017-08-08 13:53:47 +02:00
|
|
|
// copy bytes to output
|
2018-08-29 21:40:59 +02:00
|
|
|
*po++ = *pi++;
|
|
|
|
Blowfish_encipher( ( DWORD* ) pOutput, // now encrypt them
|
|
|
|
( DWORD* ) ( pOutput + 4 ) );
|
|
|
|
}
|
|
|
|
else // pad end of data with null bytes to complete encryption
|
|
|
|
{
|
|
|
|
lGoodBytes = lSize - lCount; // number of remaining data bytes
|
|
|
|
po = pOutput;
|
|
|
|
for( i = 0; i < ( int ) lGoodBytes; i++ )
|
|
|
|
*po++ = *pInput++;
|
|
|
|
for( j = i; j < 8; j++ )
|
|
|
|
*po++ = 0;
|
|
|
|
Blowfish_encipher( ( DWORD* ) pOutput,
|
|
|
|
( DWORD* ) ( pOutput + 4 ) );
|
|
|
|
}
|
|
|
|
pInput += 8;
|
|
|
|
pOutput += 8;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return lOutSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Decode pIntput into pOutput. Input length in lSize. Input buffer and
|
|
|
|
// output buffer can be the same, but be sure buffer length is even MOD 8.
|
|
|
|
void BlowFish::Decode( BYTE* pInput, BYTE* pOutput, DWORD lSize )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
DWORD lCount;
|
|
|
|
BYTE* pi, * po;
|
|
|
|
int i;
|
|
|
|
int SameDest = ( pInput == pOutput ? 1 : 0 );
|
|
|
|
|
|
|
|
for( lCount = 0; lCount < lSize; lCount += 8 )
|
|
|
|
{
|
|
|
|
if( SameDest ) // if encoded data is being written into input buffer
|
|
|
|
{
|
|
|
|
Blowfish_decipher( ( DWORD* ) pInput,
|
|
|
|
( DWORD* ) ( pInput + 4 ) );
|
|
|
|
pInput += 8;
|
|
|
|
}
|
|
|
|
else // output buffer not equal to input buffer
|
|
|
|
{ // so copy input to output before decoding
|
|
|
|
pi = pInput;
|
|
|
|
po = pOutput;
|
|
|
|
for( i = 0; i < 8; i++ )
|
|
|
|
*po++ = *pi++;
|
|
|
|
Blowfish_decipher( ( DWORD* ) pOutput,
|
|
|
|
( DWORD* ) ( pOutput + 4 ) );
|
|
|
|
pInput += 8;
|
|
|
|
pOutput += 8;
|
|
|
|
}
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|