// 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_consts.h" // 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]; (Xr.dword ^= ((((SBoxes[0][Xl.w.byte0]) + (SBoxes[1][Xl.w.byte1])) ^ (SBoxes[2][Xl.w.byte2])) + (SBoxes[3][Xl.w.byte3])) ^ PArray[1]); (Xl.dword ^= ((((SBoxes[0][Xr.w.byte0]) + (SBoxes[1][Xr.w.byte1])) ^ (SBoxes[2][Xr.w.byte2])) + (SBoxes[3][Xr.w.byte3])) ^ PArray[2]); (Xr.dword ^= ((((SBoxes[0][Xl.w.byte0]) + (SBoxes[1][Xl.w.byte1])) ^ (SBoxes[2][Xl.w.byte2])) + (SBoxes[3][Xl.w.byte3])) ^ PArray[3]); (Xl.dword ^= ((((SBoxes[0][Xr.w.byte0]) + (SBoxes[1][Xr.w.byte1])) ^ (SBoxes[2][Xr.w.byte2])) + (SBoxes[3][Xr.w.byte3])) ^ PArray[4]); (Xr.dword ^= ((((SBoxes[0][Xl.w.byte0]) + (SBoxes[1][Xl.w.byte1])) ^ (SBoxes[2][Xl.w.byte2])) + (SBoxes[3][Xl.w.byte3])) ^ PArray[5]); (Xl.dword ^= ((((SBoxes[0][Xr.w.byte0]) + (SBoxes[1][Xr.w.byte1])) ^ (SBoxes[2][Xr.w.byte2])) + (SBoxes[3][Xr.w.byte3])) ^ PArray[6]); (Xr.dword ^= ((((SBoxes[0][Xl.w.byte0]) + (SBoxes[1][Xl.w.byte1])) ^ (SBoxes[2][Xl.w.byte2])) + (SBoxes[3][Xl.w.byte3])) ^ PArray[7]); (Xl.dword ^= ((((SBoxes[0][Xr.w.byte0]) + (SBoxes[1][Xr.w.byte1])) ^ (SBoxes[2][Xr.w.byte2])) + (SBoxes[3][Xr.w.byte3])) ^ PArray[8]); (Xr.dword ^= ((((SBoxes[0][Xl.w.byte0]) + (SBoxes[1][Xl.w.byte1])) ^ (SBoxes[2][Xl.w.byte2])) + (SBoxes[3][Xl.w.byte3])) ^ PArray[9]); (Xl.dword ^= ((((SBoxes[0][Xr.w.byte0]) + (SBoxes[1][Xr.w.byte1])) ^ (SBoxes[2][Xr.w.byte2])) + (SBoxes[3][Xr.w.byte3])) ^ PArray[10]); (Xr.dword ^= ((((SBoxes[0][Xl.w.byte0]) + (SBoxes[1][Xl.w.byte1])) ^ (SBoxes[2][Xl.w.byte2])) + (SBoxes[3][Xl.w.byte3])) ^ PArray[11]); (Xl.dword ^= ((((SBoxes[0][Xr.w.byte0]) + (SBoxes[1][Xr.w.byte1])) ^ (SBoxes[2][Xr.w.byte2])) + (SBoxes[3][Xr.w.byte3])) ^ PArray[12]); (Xr.dword ^= ((((SBoxes[0][Xl.w.byte0]) + (SBoxes[1][Xl.w.byte1])) ^ (SBoxes[2][Xl.w.byte2])) + (SBoxes[3][Xl.w.byte3])) ^ PArray[13]); (Xl.dword ^= ((((SBoxes[0][Xr.w.byte0]) + (SBoxes[1][Xr.w.byte1])) ^ (SBoxes[2][Xr.w.byte2])) + (SBoxes[3][Xr.w.byte3])) ^ PArray[14]); (Xr.dword ^= ((((SBoxes[0][Xl.w.byte0]) + (SBoxes[1][Xl.w.byte1])) ^ (SBoxes[2][Xl.w.byte2])) + (SBoxes[3][Xl.w.byte3])) ^ PArray[15]); (Xl.dword ^= ((((SBoxes[0][Xr.w.byte0]) + (SBoxes[1][Xr.w.byte1])) ^ (SBoxes[2][Xr.w.byte2])) + (SBoxes[3][Xr.w.byte3])) ^ PArray[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; } } }