|
The code for decryption is
if(iMode == CBC) //CBC mode, using the Chain
{
SBlock chain(m_oChain);
for(; n >= 8; n -= 8)
{
BytesToBlock(buf, work);
work ^= chain;
Encrypt(work);
chain = work;
BlockToBytes(work, buf+=8);
}
}
Everytime you call Decrypt, the system sets the local variable chain to m_oChain. Looking at the code, we see that m_oChain is never changed in any function (which implies that the function ResetChain has no effect).
Thus if you call decrypt twice, the local variable chain is initialized, used to decrypt the first block which chages the variable chain. The desired behavior is to use the new value of chain to decrypt the second block. Hence the loop.
But if you call Decrypt once yourself to decrypt each block, the local variable chain gets initialized to m_oChain all over again. Thus you lose the effect of chaining, and cannot decrypt.
The same holds for encrypting (ie. you have to encrypt everything at once), and CFB mode.
One may try to change the code to set m_oChain = chain at the end.
if(iMode == CBC) //CBC mode, using the Chain
{
SBlock chain(m_oChain);
for(; n >= 8; n -= 8)
{
BytesToBlock(buf, work);
work ^= chain;
Encrypt(work);
chain = work;
BlockToBytes(work, buf+=8);
}
m_oChain = chain;
}
I think this is what the original code author may have intended. In this case, the function ResetChain makes sense.
|
|
|
|
|
Hello,
I would like to use this class with the Borland's C++. When compiling some errors occur related to the "exception" class and the ambiguity between Byte and System:Byte.
Can anyone tell me how can I do this?
Thank You and Best Regards,
Marius
|
|
|
|
|
Just replace the 'Byte' with 'System:Byte'
|
|
|
|
|
Sorry, i was wrong. I am noob. Correct solution is to change the 'Byte' to 'Char'
|
|
|
|
|
See my recent new thread about compile errors. One must replace the use of std::exception with std::runtime_error or an equivalent. As for Byte, the function is defined in BlowFish.h as an inline function at global scope. The compiler did compile my code correctly.
|
|
|
|
|
I'm a bit unsure about this:
Am I allowed to use this code in my open source project? I'm developing a mail server (www.hmailserver.com) and liked this blowfish implementation.
|
|
|
|
|
Hi !
I used this class to make a simple file encryption utility.The encryption part is working fine , and the resultant file size etc is absolutely as calculated.However , decryption was not working.While looking around my source code , and that of the author, i found some interesting stuff which i could not explain.They seem to be causing the error in my case.Please scroll down to see the code snippets and the outputs.Can anyone explain why they are , well, the way they are ??
//////////////start of snippet///////////////////////////////////////////
CBlowFish oBlowFish((unsigned char*)key, 16);<br />
char szDataIn[8];<br />
char szDataIn2[8]="\0\0\0\0";<br />
memcpy(szDataIn,block1,8);<br />
MessageBox(szDataIn);<br />
char szDataOut[17] = "\0\0\0\0\0\0\0\0";<br />
<br />
oBlowFish.Encrypt((unsigned char*)szDataIn, (unsigned char*)szDataOut, 8);<br />
memset(szDataIn2, 0, 8);<br />
<br />
<br />
<br />
<br />
oBlowFish.Decrypt((unsigned char*)szDataOut,(unsigned char*)szDataIn2, 8);<br />
<br />
MessageBox(szDataIn2);<br />
fwrite(&szDataOut,sizeof(szDataOut),1,fp3);<br />
/////////////end of snippet///////////////////////////////////////////
here , i am using fread to read 8 bytes of data into the variable block1, which i am copying to szDataIn.After encrypting the output is coming into the variable szDataOut.I am taking that as an input to decrypt the string , and saving it into szDataIn2 , which is initialised as you can see.Now ,szDataIn and szDataIn2 should be the same , but it isn't.if szDataIn is "whatever", then szDataIn2 is coming out as seen by MessageBox(szDataIn2) is "whateverwhatever".Like the outputting is concatenating to itself.What bewilders me more is how could a 16 char string be the output ,when i already initialised szDataIn2 's dimension as 8 ?The second thing is that if i change the target variable of the encryption function from szDataIn2 to szDataIn , the output is coming correctly !
Now the second snippet ( part1 ) :
here block1 is initialised as char block1[8];
CBlowFish oBlowFish((unsigned char*)key, 16);<br />
char szDataIn[8];<br />
char szDataIn2[8]="\0\0\0\0";<br />
memcpy(szDataIn,block1,8);<br />
MessageBox(szDataIn);<br />
char szDataOut[17] = "\0\0\0\0\0\0\0\0";<br />
<br />
oBlowFish.Encrypt((unsigned char*)szDataIn, (unsigned char*)szDataOut, 8);<br />
<br />
<br />
<br />
fwrite(&szDataOut,sizeof(szDataOut),1,fp3);<br />
this is a part to encrypt a 8 byte data block.which i am writing to a file as you can see.The decryption part is as follows(2nd snippet part 2 )
here block1 is initialised as char block1[17]; :
fread(&block1,sizeof(block1),1,fp2);<br />
CBlowFish oBlowFish((unsigned char*)key, 16);<br />
char szDataIn[8]="\0\0\0\0";<br />
char szDataOut[17] ;<br />
memcpy(szDataOut,block1,17);<br />
memset(szDataIn, 0, 8);<br />
oBlowFish.Decrypt((unsigned char*)szDataOut, (unsigned char*)szDataIn, 8);<br />
fwrite(&szDataIn,sizeof(szDataIn),1,fp3);
Although a MessageBox() shows me that the output for each block in the encryption snippet , is same as the data that i am reading into the variable block1, and subsequently copying to the variable szDataOut.Still , the decryption function is not giving me the original text back , which i passed onto the encryption function. Here , the output is not even near to the input.It's a lot of gibberish.the padding is not the problem , because it is not even able to read the first block.
Can anyone point out where i went wrong ?Got kinda stuck back in here
Thanks in advance.
Regards
Kane
"Some guys hack just to get themselves a girlfriend.What a pathetic reason , huh ? "
|
|
|
|
|
char szDataOut[17] = "\0\0\0\0\0\0\0\0";
...
oBlowFish.Decrypt((unsigned char*)szDataOut,(unsigned char*)szDataIn2, 8);
...
MessageBox(szDataIn2);
szDataIn2 is 17 chars long, but you decrypt 8 bytes into it. Then you print szDataIn2, which could print an infinite number of chars, assuming the string is not null terminated.
Try this instead:
char szDataIn[9];
char szDataIn2[9];
memcpy(szDataIn,block1,8);
szDataIn[8] = 0;
MessageBox(szDataIn);
char szDataOut[9];
oBlowFish.Encrypt((unsigned char*)szDataIn, (unsigned char*)szDataOut, 8);
oBlowFish.Decrypt((unsigned char*)szDataOut,(unsigned char*)szDataIn2, 8);
szDataIn2[8] = 0;
MessageBox(szDataIn2);
|
|
|
|
|
Hello all,
could you please let me know how to execute the program without using VC++ in only c++. I have done this implementation as my project earlier. But when I faced the interview, the question, I got was "WHY HAVE YOU IMPLEMENTED THIS PROGRAM, AS MicroSoft itself provides security to files, THEN WHY TO USE MS VC++. Please reply, thank you in advance.
Athar Hussain
|
|
|
|
|
hi
i do not have a big experience in C++ developement and i have used this implementation under VC++ 6.0 in order to encrypt , decrypt any string with any length. i have encoutered a problem and would like to know if you have any suggestion about it:
when i copy the Decrypted data to a temporary char table and decrypt the temporary char table , the result is not correct:
this is an example of string :
char * szDataIn1 = "Hello World Hello World Hello World Hello World Hello World Hello World Hello World";
below how i encrypt:
size_t llen = strlen(szDataIn1);//83
size_t llen2 = g_getLong(llen+1);//88 , make the buffer length MOD 8 = 0
char* sout = new char[llen2];// encrypted data
char* sin = new char[llen2]; // copy of szDataIn1
memset(sin,0,llen2);
memset(sout,0,llen2);
strcpy(sin,szDataIn1);// same result when using strncpy + strlen(szDataIn1)+1 as third arg
oFS.Encrypt((unsigned char*) sin,(unsigned char*)sout,llen2,1);
char* sout2 = new char[llen2];
memset (sout2,0,llen2);
// it will work if you comment the following line and call oFS.Decrypt((unsigned char*) sout,(unsigned char*) sout2,llen2,1)
memcpy(sout2,sout,strlen(sout));
memset(sout,0,llen2);
oFS.Decrypt((unsigned char*) sout2,(unsigned char*) sout,llen2,1);
cout<<sout<<endl;
i need to make a copy in a temprary table because i need to implement a com object and to convert from BSTR to char
thnak you in advance for any suggestion.
|
|
|
|
|
Hey Luc,
I believe your problem is that you use strlen(sout).
sout is not a null-terminated string.
instead of using
memcpy(sout2,sout,strlen(sout));
try to use
memcpy(sout2,sout,llen2);
for the same reason
memset(sout,0,llen2);
is useless.
Also i think you have a problem with your paddind.
try something like this (untested):
strcp(data,input);
len=strlen(data);
pad = 8-(len%8);
pad = pad?pad:8;
memset(data+len,pad,pad);
len+=pad;
Encrypt(data,cipher,len);
Decrypt(cipher,data,len)
pad=data[len-1];
memset(data+len-pad,pad,0);
/NL
nirl at realcommerce dot co dot il
|
|
|
|
|
Would a CString interface be a good idea? That way your users would not have to worry over padding their data.
So like this:
CString Encrypt(const char *);
A good idea yes? How could this be done?
|
|
|
|
|
I've added a CString interface to the original project.
You will need to add the functions to the class definition.
public:
CString Encrypt(CString in, int iMode=ECB);
CString Decrypt(CString hex, int iMode=ECB);
private:
char *Char2Hex(const unsigned char ch, char* szHex);
unsigned char Hex2Char(const char* szHex);
NOTE: There is a "similar overload functions" problem for the old
encrypt if you dont pass a mode. I dont have time or
need to fix it now
===================================
Add to blowfish.h
===================================
inline char *CBlowFish::Char2Hex(const unsigned char ch, char* szHex)
{
unsigned char byte[2];
byte[0] = ch/16;
byte[1] = ch%16;
for(int i=0; i<2; i++)
{
if(byte[i] >= 0 && byte[i] <= 9)
szHex[i] = '0' + byte[i];
else
szHex[i] = 'A' + byte[i] - 10;
}
szHex[2] = 0;
return szHex;
}
inline unsigned char CBlowFish::Hex2Char(const char* szHex)
{
char rch = 0;
for(int i=0; i<2; i++)
{
if(*(szHex + i) >='0' && *(szHex + i) <= '9')
rch = (rch << 4) + (*(szHex + i) - '0');
else if(*(szHex + i) >='A' && *(szHex + i) <= 'F')
rch = (rch << 4) + (*(szHex + i) - 'A' + 10);
else
break;
}
return rch;
}
===================================
Add to blowfish.cpp
===================================
CString CBlowFish::Encrypt(CString in, int iMode) {
CByteArray cbaData;
DWORD len,pad;
BYTE *data;
CString cipher;
char hex[3];
len = in.GetLength();
pad = 8-(len%8);
cbaData.SetSize(len+9);
data = cbaData.GetData();
CopyMemory(data,(LPCTSTR)in,len);
pad = pad?pad:8;
FillMemory((void *)(data+len),pad,(BYTE)pad);
len+=pad;
Encrypt((unsigned char *)data, len, iMode);
for ( int i=0; i < len; i++ ) {
cipher += (CString)Char2Hex((const unsigned char)data[i],hex);
}
return cipher;
}
CString CBlowFish::Decrypt(CString hex, int iMode) {
CByteArray cbaData;
BYTE *data;
DWORD len, pad;
len=hex.GetLength()/2;
cbaData.SetSize(len+1);
data=cbaData.GetData();
for ( int i=0; i < len; i++ ) {
data[i]=Hex2Char((LPCTSTR)hex.Mid(i*2,2));
}
Decrypt(data,len,iMode);
pad = data[len-1];
FillMemory((void *)(data+len-pad),pad,0);
return (CString)data;
}
best regards
/NL
nirL at realcommerce dot co dot il
|
|
|
|
|
Thanks for the code!!! I am having a problem using it in UNICODE though. Do you happen to have the same CString ready blowfish class that will compile under UNICODE?
thanks,
steve
|
|
|
|
|
Heloo Steve,
you are absolutly right.
When i wrote
CopyMemory(data,(LPCTSTR)in,len);
and
return (CString)data; //data is BYTE*
I assumed that LPCTSTR returns BYTE* and that casting is possible between BTYE* and CString. Obviously this is not the case in _UNICODE when LPCTSTR returns wide-char (TCHAR).
I am not sure how to fix this at the moment. basically you will need to convert the CString to BYTE* and BYTE* to CString (the encryption uses BYTE arrays).
perhaps you can get some ideas from http://www.codeproject.com/string/UTF8.asp[^]
best regards
/NL
polynr69 at gmail dot com
|
|
|
|
|
Now I need the CString interface,haha,you give me.Thank you!
今天没有时间,以后再写吧。
|
|
|
|
|
>Would a CString interface be a good idea?
No, it's not. As soon as you start using CString, you loose the portability.
I haven't yet tried to compile this code on compiler other than cl (but I do have such plans), but as far as I can see - it's pure C++, and should work find on any compiler.
There is nothing compared to pure ANSI C++ and I don't see any reason to choke up general purpose code with platform/compiler specific stuff.
"To protect people you must slay people. To let people live you must let people die. This is the true teaching of the sword."
-Seijuro Hiko, "Rurouni Kensin"
|
|
|
|
|
Worse still, a CString is a null-terminated string, so if you try to hold an encrypted data stream in a CString you will find it appears to be truncated at the first '\0'
Also, under UNICODE builds, CString will try and convert the each character to a wchar_t which you almost certaintly don't want.
Always deal in BYTEs (unsigned chars) and you know where you are on most systems. Start to deal in characters (char under ANSI and wchar_t under UNICODE) and you start to get some real problems.
|
|
|
|
|
Just curious if this class is thread safe, or if I have to create a new instance for each call
Tim
|
|
|
|
|
I would like an (official) answer to this as well, if possible.
From reading the code it seems that the only writing done to member variables is done in the constructor, which makes the class threadable. I would like to hear from other people since i am not sure i fully understand all the code and all the issues with thread-safety
/NL
(27/6/04 fixed a typo)
|
|
|
|
|
At present it is thread safe as the member variables don't change m_oChain or any other variables. However, it is possible that the Encrypt and Decrypt functions are supposed to change m_oChain, otherwise why would the original author have put the function ResetChain there?
Supposing we do this, then the code is no longer thread safe, because two threads may try to change the same members. So it makes sense for a CBlowFish object to not be shared between threads. Thus a global CBlowFish object might not be a good idea.
|
|
|
|
|
Hi,
I checked the web site with Blowfish algorithm (in the link provided) and found there a "reference implementation" of the algorithm for C++.
What is the difference between this impl. and that one?
Was it properly tested, too?
Does it handle correctly the so-called implementation bug(http://www.schneier.com/blowfish-bug.txt)?
With regards,
Andru
|
|
|
|
|
I included CBlowFish class into my VC++ project, and used it to encrypt the password. I encrypt the password entered in the editbox and then store it into a password file. Later when I read that password back from the stored file and decrypt it, I don't get the same text back. Below is my code snippet.
unsigned char* cPassword = new unsigned char[MAX_PWD_SIZE];
unsigned char* cCreptedPwd = new unsigned char[MAX_PWD_SIZE];
unsigned int iPwdBytes;
unsigned char aucKey[8];
CFile filePwd;
CFileException *e;
iPwdBytes = filePwd.Read(cCreptedPwd, MAX_PWD_SIZE);
//Decrypt the password
if (iPwdBytes < MAX_PWD_SIZE)
cCreptedPwd[iPwdBytes] = '\0';
oBlowFish.Decrypt(cCreptedPwd, cPassword, 8);
cPassword[iPwdBytes+1] = '\0';
CString csStoredPwd(cPassword);
LRTrim(csStoredPwd, ' ');
if (m_csOldPwd.Compare(csStoredPwd) != 0)
{
AfxMessageBox("Incorrect Old Password, Please try again");
m_csOldPwd.Empty();
UpdateData(false);
}
else
{
//Set the new password
filePwd.SeekToBegin();
LRTrim(m_csNewPwd, ' ');
const char *pNewPwd = m_csNewPwd.operator LPCTSTR();
unsigned char* pucNewPwd = (unsigned char*)pNewPwd;
int i= m_csNewPwd.GetLength();
pucNewPwd[i]='\0';
//Encrypt the new Password
oBlowFish.Encrypt(pucNewPwd, cCreptedPwd, 8);
filePwd.Write(cCreptedPwd, i);
filePwd.Close();
}
|
|
|
|
|
Hello,
I'm confused. I followed the second example with the 16 byte key size and the ECB algorithm:
CBlowFish oBlowFish((unsigned char*)"1234567890123456", 16);
char szDataIn1[49] = "ababababccccccccababababccccccccababababcccccccc";
I set szDataIn1 to 4 different strings; "smith", "cooper", "washington",
and "administrator". None of these strings are a multiple of 8-bytes,
but each string encrypted/decrypted perfectly. I did not pad any of the strings.
What's the padding about? Will the encryption/decryption fail with
other strings? If so, what type of strings; ie. long, short, binary,...
Please advise.
Thanks,
Jacques
|
|
|
|
|
I've had a go at adapting the class to encrypt and decrypt files. I keeo getting a problem at the end of the files.
Can anyone see the problem? Code appended...
Dave
void BlowFishEnc::EncryptFile(CString sFrom, CString sTo)
{
BYTE buffer[4105];
BYTE outBuffer[4105];
DWORD dwRead;
CString s;
CFile fIn, fOut;
int n, m;
if(!fIn.Open(sFrom, CFile::modeRead)) return;
if(!fOut.Open(sTo, CFile::modeCreate|CFile::modeWrite)) return;
do
{
dwRead = fIn.Read(buffer, 4096);
n = (dwRead % 8);
m = n;
while(n)
{
buffer[dwRead + n] = ' ';
n--;
}
encryptStream((const char*)buffer, dwRead + m, (char*)outBuffer);
fOut.Write(outBuffer, dwRead + m);
}
while (dwRead > 0);
}
Dave Leighton
- Spurious borrowed comment to show I'm not really a geek...
|
|
|
|
|