I'm using the following implementation of blowfish (with some stuff cut out of the middle) to encrypt and decrypt messages. I am attempting to encrypt a message on a big endian machine (SunOS 5.10), and then send it over a socket to a little endian machine (linux). I can encrypt and decrypt on the same machine, and on different linux machines, but I can't get it to work between these two machines.
Because the blowfish implementation seems to break the message up into DWords, each of which contains two 32 bit integers, I have been breaking my encrypted message into 32 bit integers, applying htonl() to each, sending them over the network, applying ntohl() to each, and then attempting to decrypt. The result is not pretty, but interestingly enough, most of the correct characters are present after decryption, but they are garbled and some extra garbage characters appear in some places. I really can't imagine what I might be missing.
/********** blowfish.h **********/
#ifndef ___BLOWFISH_H___
#define ___BLOWFISH_H___
#define NUM_SUBKEYS 18
#define NUM_S_BOXES 4
#define NUM_ENTRIES 256
#define MAX_STRING 256
#define MAX_PASSWD 56 // 448bits
#ifdef BIG_ENDIAN
struct WordByte
{
unsigned int zero:8;
unsigned int one:8;
unsigned int two:8;
unsigned int three:8;
};
#endif
#ifdef LITTLE_ENDIAN
struct WordByte
{
unsigned int three:8;
unsigned int two:8;
unsigned int one:8;
unsigned int zero:8;
};
#endif
union Word
{
unsigned int word;
WordByte byte;
};
struct DWord
{
Word word0;
Word word1;
};
class Blowfish
{
private:
unsigned int PA[NUM_SUBKEYS];
unsigned int SB[NUM_S_BOXES][NUM_ENTRIES];
void Gen_Subkeys(char *);
inline void BF_En(Word *,Word *);
inline void BF_De(Word *,Word *);
public:
Blowfish();
~Blowfish();
void Reset();
void Set_Passwd(char * = NULL);
void Encrypt(void *,unsigned int);
void Decrypt(void *,unsigned int);
};
#endif
/********** blowfish.cc **********/
#include <iostream.h>
#include <string.h>
#include "blowfish.h"
#define F(x) (((SB[0][x.byte.zero] + SB[1][x.byte.one]) ^ SB[2][x.byte.two]) + SB[3][x.byte.three])
void Blowfish::Gen_Subkeys(char *Passwd)
{
unsigned int i,j,len=strlen(Passwd);
Word Work,null0,null1;
if (len > 0)
{
j = 0;
for (i=0;i<NUM_SUBKEYS;i++)
{
Work.byte.zero = Passwd[(j++)%len];
Work.byte.one = Passwd[(j++)%len];
Work.byte.two = Passwd[(j++)%len];
Work.byte.three = Passwd[(j++)%len];
PA[i] ^= Work.word;
}
null0.word = null1.word = 0;
for (i=0;i<NUM_SUBKEYS;i+=2)
{
BF_En(&null0,&null1);
PA[i] = null0.word;
PA[i+1] = null1.word;
}
for (j=0;j<NUM_S_BOXES;j++)
for (i=0;i<NUM_ENTRIES;i+=2)
{
BF_En(&null0,&null1);
SB[j][i] = null0.word;
SB[j][i+1] = null1.word;
}
}
Work.word = null0.word = null1.word = 0;
Passwd = NULL;
len = 0;
}
void Blowfish::BF_En(Word *x1,Word *x2)
{
Word w1=*x1,w2=*x2;
w1.word ^= PA[0];
w2.word ^= F(w1)^PA[1]; w1.word ^= F(w2)^PA[2];
w2.word ^= F(w1)^PA[3]; w1.word ^= F(w2)^PA[4];
w2.word ^= F(w1)^PA[5]; w1.word ^= F(w2)^PA[6];
w2.word ^= F(w1)^PA[7]; w1.word ^= F(w2)^PA[8];
w2.word ^= F(w1)^PA[9]; w1.word ^= F(w2)^PA[10];
w2.word ^= F(w1)^PA[11]; w1.word ^= F(w2)^PA[12];
w2.word ^= F(w1)^PA[13]; w1.word ^= F(w2)^PA[14];
w2.word ^= F(w1)^PA[15]; w1.word ^= F(w2)^PA[16];
w2.word ^= PA[17];
*x1 = w2;
*x2 = w1;
}
void Blowfish::BF_De(Word *x1,Word *x2)
{
Word w1=*x1,w2=*x2;
w1.word ^= PA[17];
w2.word ^= F(w1)^PA[16]; w1.word ^= F(w2)^PA[15];
w2.word ^= F(w1)^PA[14]; w1.word ^= F(w2)^PA[13];
w2.word ^= F(w1)^PA[12]; w1.word ^= F(w2)^PA[11];
w2.word ^= F(w1)^PA[10]; w1.word ^= F(w2)^PA[9];
w2.word ^= F(w1)^PA[8]; w1.word ^= F(w2)^PA[7];
w2.word ^= F(w1)^PA[6]; w1.word ^= F(w2)^PA[5];
w2.word ^= F(w1)^PA[4]; w1.word ^= F(w2)^PA[3];
w2.word ^= F(w1)^PA[2]; w1.word ^= F(w2)^PA[1];
w2.word ^= PA[0];
*x1 = w2;
*x2 = w1;
}
Blowfish::Blowfish()
{
Reset();
}
Blowfish::~Blowfish()
{
Reset();
}
void Blowfish::Reset()
{
unsigned int i,j;
unsigned int PA_Init[NUM_SUBKEYS] =
{
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
0x9216d5d9, 0x8979fb1b
};
unsigned int SB_Init[NUM_S_BOXES][NUM_ENTRIES] =
{
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
...
...
...
};
for (i=0;i<NUM_SUBKEYS;i++)
PA[i] = PA_Init[i];
for (j=0;j<NUM_S_BOXES;j++)
for (i=0;i<NUM_ENTRIES;i++)
SB[j][i] = SB_Init[j][i];
}
void Blowfish::Set_Passwd(char *Passwd)
{
char New_Passwd[MAX_STRING];
unsigned int i,len;
if (Passwd == NULL)
{
do
{
cout << "\aEnter your password: ";
cin.get(New_Passwd,MAX_STRING,'\n');
len = strlen(New_Passwd);
}
while (len > MAX_PASSWD);
Passwd = New_Passwd;
}
else
len = strlen(Passwd);
Reset();
if (len > 0)
Gen_Subkeys(Passwd);
for (i=0;i<MAX_STRING;i++)
New_Passwd[i] = '\0';
Passwd = NULL;
len = 0;
}
void Blowfish::Encrypt(void *Ptr,unsigned int N_Bytes)
{
unsigned int i;
DWord *Work;
if (N_Bytes%8)
{
cerr << "\aBlowfish requires the input to be a multiple of 8 bytes (64 bits) to work.\n";
return;
}
N_Bytes /= 8;
Work = (DWord *)Ptr;
for (i=0;i<N_Bytes;i++)
{
BF_En(&Work->word0,&Work->word1);
Work++;
}
Work = NULL;
}
void Blowfish::Decrypt(void *Ptr,unsigned int N_Bytes)
{
unsigned int i;
DWord *Work;
if (N_Bytes%8)
{
cerr << "\aBlowfish requires the input to be a multiple of 8 bytes (64 bits) to work.\n";
return;
}
N_Bytes /= 8;
Work = (DWord *)Ptr;
for (i=0;i<N_Bytes;i++)
{
BF_De(&Work->word0,&Work->word1);
Work++;
}
Work = NULL;
}
The following is the encrypted string on the big-endian machine:
11010011 11110110 01100110 10001101 01010011 11000110 00010001 11110110 00011010 11001010 00011111 00100001 10110000 10110100 10110000 11110000 11111100 11000010 00110011 00001111 10011110 01100111 00010101 10000101 00001010 01111110 10000101 00011100 10010010 10111010 10010111 11111001 00111101 01011100 00000010 01010011 11100000 11001101 11111010 00111100 00011101 10001001 01010111 01011010 11100001 10101111 10001100 10111001 00011111 10111100 10010101 01101110 10001101 11010100 11101110 11010001 10111011 11111110 10100111 01111000 11010001 01011101 00110100 01000001 01011011 01111100 10010011 00010001 10100011 10011011 10111100 01100000
This is the encrypted string after I have sent it over the network to the little-endian machine:
10001101 01100110 11110110 11010011 11110110 00010001 11000110 01010011 00100001 00011111 11001010 00011010 11110000 10110000 10110100 10110000 00001111 00110011 11000010 11111100 10000101 00010101 01100111 10011110 00011100 10000101 01111110 00001010 11111001 10010111 10111010 10010010 01010011 00000010 01011100 00111101 00111100 11111010 11001101 11100000 01011010 01010111 10001001 00011101 10111001 10001100 10101111 11100001 01101110 10010101 10111100 00011111 11010001 11101110 11010100 10001101 01111000 10100111 11111110 10111011 01000001 00110100 01011101 11010001 00010001 10010011 01111100 01011011 01100000 10111100 10011011 10100011
Finally, this is what the string needs to be, in order for it to be successfully decrypted on the little-endian machine (i.e. this is what I get when I encrypt the original string on the little-endian machine, instead of the big endian machine):
10001101 10111011 10110010 10111000 01110001 11000110 00110110 10101110 11000011 11000100 00001010 10011110 11111101 10101000 01110011 10110110 00011001 10000011 11111000 11010001 01101001 00101100 10110001 00010001 11101101 10001011 01101110 01101011 11110001 01101010 00111010 00010110 11101111 01001111 11001100 00011101 01101010 11110000 00110000 01110100 10111010 01000101 01011001 11111001 11011101 01000011 10000110 01000001 11101110 00100001 00111000 00101001 11110011 00001111 01000011 11000000 10110010 10011101 11110000 00000001 10001011 10110101 10010011 01010010 01110100 11100000 10010011 10111101 00111110 00100001 10101111 11010000
I'm currently trying to compare the strings, but I can't find a pattern.
WordByte
structures are obviously an attempt to handle endianness, yet you say you're usinghtonl
/ntohl
too - might they not then conflict? Also, you might want to check both programs are being compiled 32 bit, as e.g. your using ofunsigned
inWord
is broken otherwise. – Tony Delroy