1
Fork 0
mirror of https://github.com/redstrate/Kawari.git synced 2025-04-26 00:37:44 +00:00
kawari/src/blowfish/blowfish.cpp

317 lines
9 KiB
C++
Raw Normal View History

// 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 <cstdint>
#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;
}
}
}