// 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 #include #include "blowfish.h" #include "blowfish.h2" // holds the random digit tables #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]) BlowFish::BlowFish() { PArray = new DWORD[18]; SBoxes = new DWORD[4][256]; } BlowFish::~BlowFish() { delete PArray; delete[] SBoxes; } // the low level (private) encryption function void BlowFish::Blowfish_encipher( DWORD* xl, DWORD* xr ) { 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; } // the low level (private) decryption function void BlowFish::Blowfish_decipher( DWORD* xl, DWORD* xr ) { 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; } // constructs the enctryption sieve void BlowFish::initialize( BYTE key[], int32_t keybytes ) { int i, j; DWORD datal, datar; // first fill arrays from data tables for( i = 0; i < 18; i++ ) PArray[ i ] = bf_P[ i ]; for( i = 0; i < 4; i++ ) { for( j = 0; j < 256; j++ ) SBoxes[ i ][ j ] = bf_S[ i ][ j ]; } 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 int32_t v10 = keybytes; uintptr_t v9 = ( uintptr_t ) key; int32_t v8 = 0; int32_t v11 = 0; do { v13 = ( char ) ( *( BYTE* ) ( v8 + v9 ) ); v12 = v8 + 1; if( v12 >= v10 ) v12 = 0; v16 = ( char ) *( BYTE* ) ( v12 + v9 ); v14 = v12 + 1; v15 = ( v13 << 8 ) | v16; if( v14 >= v10 ) v14 = 0; v19 = ( char ) *( BYTE* ) ( v14 + v9 ); v17 = v14 + 1; v18 = ( v15 << 8 ) | v19; if( v17 >= v10 ) v17 = 0; v21 = ( char ) *( BYTE* ) ( v17 + v9 ); v8 = v17 + 1; v20 = ( v18 << 8 ) | v21; if( v8 >= v10 ) v8 = 0; *( ( 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; } } } // get output length, which must be even MOD 8 DWORD BlowFish::GetOutputLength( DWORD lInputLong ) { DWORD lVal; lVal = lInputLong % 8; // find out if uneven number of bytes at the end if( lVal != 0 ) return lInputLong + 8 - lVal; else return lInputLong; } // 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 ) { 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++ ) // copy bytes to output *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 ) { 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; } } }