|
Also If you use a 32 byte key instead of 16 for the following text using the same two functions listed in the previous thread (EncryptStr, DecryptStr), it fails to decrypt the string correctly (it works with the 16 byte key, but not with the 32 byte key)
Change the following in main for the test below:
char szKey[] = "X71^&9;/8j5lu1qX71zK49x/8j5lu1q!";
//char szKey[] = "xxx^&9;/4j5l81qX";
char szDataIn[2000] = {0};
char szDataOut[2000] = {0};
char szTemp[2000] = {0};
strcpy(szDataIn, "driver={Microsoft Access Driver(*.mdb)};dbq=c:\inetpub\wwwroot\ContractsGen\lib\MRL06052002.mdb;uid=Admin");
EncryptStr(szDataIn, szKey, szDataOut);
strcpy(szTemp, szDataOut);
memset(szDataOut, 0, 2000);
DecryptStr(szTemp, szKey, szDataOut);
cout << szDataOut << endl;
|
|
|
|
|
It seems there is a bug in the Encryption Decryption algorithm.
Try the following test program with the two functions below and you will see the problem: (the decrypted string is not the same as the original string)
Also, different combinations of keys every once in a while seem to cause errors in the decryption / encryption.
void EncryptStr(char *szDataIn, char *szKey, char *szDataOut);
void DecryptStr(char *szDataIn, char *szKey, char *szDataOut);
void main()
{
//char szKey[] = "X71^&9;/8j5lu1qX71zK49x/8j5lu1q!";
char szKey[] = "xxx^&9;/4j5l81qX";
char szDataIn[2000] = {0};
char szDataOut[2000] = {0};
char szTemp[2000] = {0};
strcpy(szDataIn, "hello world hola amigos como estan ustedes?dfdfdfdfdfdfdfhello world hola amigos como estan ustedes?dfdfdfdfdfdfdfhello world hola amigos como estan ustedes?dfdfdfdfdfdfdf");
EncryptStr(szDataIn, szKey, szDataOut);
strcpy(szTemp, szDataOut);
memset(szDataOut, 0, 2000);
DecryptStr(szTemp, szKey, szDataOut);
cout << szDataOut << endl;
}
void EncryptStr(char *szDataIn, char *szKey, char *szDataOut)
{
try
{
int inlen, outlen, hexlen, keylen, rounds, block_size, i;
CRijndael oR;
keylen = strlen(szKey);
char *szPad = new char[keylen+1];
memset(szPad, 0, keylen+1);
oR.MakeKey(szKey, szPad, keylen, keylen);
inlen = strlen(szDataIn);
block_size = oR.GetBlockSize();
//initialize input and output buffers
char *pInBuffer = new char[block_size+1];
memset(pInBuffer, 0, block_size+1);
char *pOutBuffer = new char[block_size+1];
memset(pOutBuffer, 0, block_size+1);
rounds = inlen / block_size + 1;
for (i=0; i<rounds; i++)
{
if (*(szDataIn+(i*block_size)) == 0)
break;
strncpy(pInBuffer, szDataIn+(i*block_size), block_size);
oR.EncryptBlock(pInBuffer, pOutBuffer);
strcat(szDataOut, pOutBuffer);
memset(pInBuffer, 0, block_size+1);
memset(pOutBuffer, 0, block_size+1);
}
outlen = strlen(szDataOut);
hexlen = outlen * 2 + 1;
char *szHex = new char[hexlen];
memset(szHex, 0, hexlen);
CharStr2HexStr((unsigned char*)szDataOut, szHex, outlen);
strcpy(szDataOut, szHex);
//cleanup
delete [] szPad;
delete [] pInBuffer;
delete [] pOutBuffer;
delete [] szHex;
}
catch(exception& e)
{
cout << e.what() << endl;
}
}
void DecryptStr(char *szDataIn, char *szKey, char *szDataOut)
{
try
{
int inlen, keylen, rounds, block_size, i;
CRijndael oR;
keylen = strlen(szKey);
char *szPad = new char[keylen+1];
memset(szPad, 0, keylen+1);
oR.MakeKey(szKey, szPad, keylen, keylen);
block_size = oR.GetBlockSize();
char szTemp[2000] = {0};
inlen = strlen(szDataIn)/2;
HexStr2CharStr(szDataIn, (unsigned char*)szTemp, inlen);
inlen = strlen(szTemp);
rounds = inlen / block_size + 1;
//initialize input and output buffers
char *pInBuffer = new char[block_size+1];
memset(pInBuffer, 0, block_size+1);
char *pOutBuffer = new char[block_size+1];
memset(pOutBuffer, 0, block_size+1);
for (i=0; i<rounds; i++)
{
if (*(szTemp+(i*block_size)) == 0)
break;
strncpy(pInBuffer, szTemp+(i*block_size), block_size);
oR.DecryptBlock(pInBuffer, pOutBuffer);
strcat(szDataOut, pOutBuffer);
memset(pInBuffer, 0, block_size+1);
memset(pOutBuffer, 0, block_size+1);
}
//cleanup
delete [] szPad;
delete [] pInBuffer;
delete [] pOutBuffer;
}
catch(exception& e)
{
cout << e.what() << endl;
}
}
|
|
|
|
|
It is OK !
Problem is in your code !
You love much str.... functions !
Please use memcpy ...., and should work !
|
|
|
|
|
According to this article referenced by slashdot
Rijndael (AES) has been broken. (Of course that
doesn't mean that it is entirely secure, but that
it is less secure that originally thought. In essence
what it means is that there is attack against Rijndael
better than brute force.)
See at:
<http://www.counterpane.com/crypto-gram-0209.html#1>
FWIW
(However, as usual, George is the crypto God of codeproject.)
|
|
|
|
|
Well, not really, but fascinating reading nonetheless. Thanks for the link.
|
|
|
|
|
The zipped project file was updated on Nov 8 2002. In this new version the use of dynamic memory (new and delete operators) was totally eliminated by reserving enough memory on the stack for all the arrays used in the class. This is improving the speed and is solving the alleged problem with memory leaks. The article's text doesn't need changes.
|
|
|
|
|
Code is great. But there is a memory leak. I used the example test.cpp and enclosed the code in main withing a for-loop. I then run the process for several minutes an watched it in the task bar. The memory and virtual memory kept increasing. I also had Bounce Checker software attached to MS VC++ 6.0 and it reports a memory leak as follows:
Memory Leak:320 Bytes allocated by HeapAlloc in sbcheap.c (102), HANDLE: 0x02060650
Thanks,
Joe Roberts
|
|
|
|
|
I carefully examined the code and I couldn't find any source of memory leaks. I repeated your test with the code in an infinite loop and I watched the Memory Usage column in Windows NT Task Manager under the Processes Tab, the memory usage displayed was constant. After that I intentionally commented a delete statement from the destructor and repeated the test. In this case the memory usage was increasing constantly, showing that if there is any memory leak it should be detected by the Task Manager.
Maybe there were other processes running on your computer!
|
|
|
|
|
Can you show how to encrypt/decrypt a whole file?
Remember I am a serious beginner at this.
|
|
|
|
|
I'm a beginner in this subject, too. I will have to try to de- and encrypt a whole file too. I think you have to divide the file into blocks with the same length (e.g. 32 bytes) and encrypt each block. Put the encrypted blocks together again in the correct sequence to built the new "encrypted" File. Decrypt the File in the sam way. I am not sure if this is the correct way but ist should work.
Good luck Jo
|
|
|
|
|
yes, this is the correct way.
read a block, encrypt it, write the block.
-c
30% of your base are belong to the IRS!
|
|
|
|
|
Here's a slight modification of Encrypt and Decrypt.
Basically, the file to be crypted is read, crypted and written to the output file so memory use is minimal. The hash size
is m_blockSize .
To handle the end of file problem when the file size is not a multiple of m_blockSize , the file size is written at the beginning of the crypted file.
void CRijndael::EncryptFile(const char *szInFileName, const char *szOutFileName, int iMode, CProgressCtrl* pProgress)
{
char* pInBuffer = NULL;
char* pOutBuffer = NULL;
int sizeChar = sizeof(char);
int sizeLong = sizeof(long);
int result;
long fileSize, bufferSize;
int i;
if(false==m_bKeyInit)
throw exception(sm_szErrorMsg1);
int pInFile = _open( szInFileName, _O_BINARY | _O_RDONLY);
if (!pInFile)
throw exception(sm_szErrorMsgNoInFile);
int pOutFile = _open( szOutFileName, _O_BINARY | _O_CREAT | _O_WRONLY , _S_IWRITE );
if (!pOutFile)
throw exception(sm_szErrorMsgNoOutFile);
fileSize=_lseek(pInFile, 0, SEEK_END);
_lseek(pInFile, 0, SEEK_SET);
_write(pOutFile, &fileSize, sizeLong);
bufferSize = fileSize+GetKeyLength()-fileSize%GetKeyLength();
if(0==bufferSize || bufferSize%m_blockSize!=0)
throw exception(sm_szErrorMsg2);
pInBuffer = new char[m_blockSize];
if (!pInBuffer)
throw exception(sm_szErrorMsgNoMemory);
memset(pInBuffer, 0, sizeChar * m_blockSize );
pOutBuffer = new char[m_blockSize];
if (!pOutBuffer)
throw exception(sm_szErrorMsgNoMemory);
memset(pOutBuffer, 0, sizeChar * m_blockSize );
if (pProgress)
{
pProgress->SetRange32(0,bufferSize/m_blockSize+1);
pProgress->SetStep(100);
pProgress->SetPos(0);
}
if(CBC == iMode)
{
for(i=0; i<bufferSize/m_blockSize; i++)
{
result=_read( pInFile, pInBuffer, m_blockSize * sizeChar);
Xor(m_chain, pInBuffer);
EncryptBlock(m_chain, pOutBuffer);
memcpy(m_chain, pOutBuffer, m_blockSize);
_write(pOutFile, pOutBuffer, m_blockSize * sizeChar);
if (pProgress && i%100==0)
pProgress->StepIt();
}
}
else if(CFB == iMode)
{
for(i=0; i<bufferSize/m_blockSize; i++)
{
result=_read( pInFile, pInBuffer, m_blockSize * sizeChar);
EncryptBlock(m_chain, pOutBuffer);
Xor(pOutBuffer, pInBuffer);
memcpy(m_chain, pOutBuffer, m_blockSize);
_write(pOutFile, pOutBuffer, m_blockSize * sizeChar);
if (pProgress && i%100==0)
pProgress->StepIt();
}
}
else
{
for(i=0; i<bufferSize/m_blockSize; i++)
{
result=_read( pInFile, pInBuffer, m_blockSize * sizeChar);
EncryptBlock(pInBuffer, pOutBuffer);
_write(pOutFile, pOutBuffer, m_blockSize * sizeChar);
if (pProgress && i%100==0)
pProgress->StepIt();
}
}
_close( pOutFile );
_close( pInFile );
if (pInBuffer)
{
delete[] pInBuffer;
pInBuffer = NULL;
}
if (pOutBuffer)
{
delete[] pOutBuffer;
pOutBuffer = NULL;
}
}
And the decryption of the crypted file...
void CRijndael::DecryptFile(const char *szInFileName, const char *szOutFileName, int iMode, CProgressCtrl* pProgress)
{
char* pInBuffer = NULL;
char* pOutBuffer = NULL;
int sizeChar = sizeof(char);
int sizeLong = sizeof(long);
int result;
long fileSize, bufferSize;
int i;
if(false==m_bKeyInit)
throw exception(sm_szErrorMsg1);
int pInFile = _open( szInFileName, _O_BINARY | _O_RDONLY);
if (!pInFile)
throw exception(sm_szErrorMsgNoInFile);
int pOutFile = _open( szOutFileName, _O_BINARY | _O_CREAT | _O_WRONLY , _S_IWRITE );
if (!pOutFile)
throw exception(sm_szErrorMsgNoOutFile);
_read(pInFile, &fileSize, sizeChar * sizeLong);
bufferSize = fileSize+GetKeyLength()-fileSize%GetKeyLength();
if(0==bufferSize || bufferSize%m_blockSize!=0)
throw exception(sm_szErrorMsg2);
pInBuffer = new char[m_blockSize];
if (!pInBuffer)
throw exception(sm_szErrorMsgNoMemory);
memset(pInBuffer, 0, sizeChar * m_blockSize );
pOutBuffer = new char[m_blockSize];
if (!pOutBuffer)
throw exception(sm_szErrorMsgNoMemory);
memset(pOutBuffer, 0, sizeChar * m_blockSize );
if (pProgress)
{
pProgress->SetRange32(0,bufferSize/m_blockSize+1);
pProgress->SetStep(100);
pProgress->SetPos(0);
}
if(CBC == iMode)
{
for(i=0; i<bufferSize/m_blockSize; i++)
{
result=_read( pInFile, pInBuffer, m_blockSize * sizeChar);
DecryptBlock(pInBuffer, pOutBuffer);
Xor(pOutBuffer, m_chain);
memcpy(m_chain, pInBuffer, m_blockSize);
_write(pOutFile, pOutBuffer, m_blockSize * sizeChar);
if (pProgress && i%100==0)
pProgress->StepIt();
}
}
else if(CFB == iMode)
{
for(i=0; i<bufferSize/m_blockSize; i++)
{
result=_read( pInFile, pInBuffer, m_blockSize * sizeChar);
EncryptBlock(m_chain, pOutBuffer);
Xor(pOutBuffer, pInBuffer);
memcpy(m_chain, pInBuffer, m_blockSize);
_write(pOutFile, pOutBuffer, m_blockSize * sizeChar);
if (pProgress && i%100==0)
pProgress->StepIt();
}
}
else
{
for(i=0; i<bufferSize/m_blockSize; i++)
{
result=_read( pInFile, pInBuffer, m_blockSize * sizeChar);
DecryptBlock(pInBuffer, pOutBuffer);
_write(pOutFile, pOutBuffer, m_blockSize * sizeChar);
if (pProgress && i%100==0)
pProgress->StepIt();
}
}
_close( pOutFile );
_close( pInFile );
if (pInBuffer)
{
delete[] pInBuffer;
pInBuffer = NULL;
}
if (pOutBuffer)
{
delete[] pOutBuffer;
pOutBuffer = NULL;
}
}
|
|
|
|
|
If a use a string like "abcdefghabcdefgh" as a key value then you can easily find it in the executable. How can I create a more sophisticated (time and computer independent) key?
|
|
|
|
|
that's the problem with symmetric ciphers (such as this) - the key does both encryption and decryption. so the problem of secure data goes from one of encryption to one of key distribution.
if you want to avoid putting the encryption key into the app, you should take a look at asymmetric (AKA public-key) encryption (RSA, etc.). with asymmetric encryption, you can safely embed the decryption key in your EXE. anyone can decrypt the data but only the holder of the private key can encrypt it.
-c
Smaller Animals Software, Inc.
You're the icing - on the cake - on the table - at my wake. Modest Mouse
|
|
|
|
|
What about encryption of the key, or multiple encryptions of the key (or data). Are there any good examples?
|
|
|
|
|
multiple encryption, or encrypting the key, is simply security by obscurity - you're assuming that the attacker is lazy and will give up if it takes too long to figure out your algorithm. and that may be a perfectly valid way to go, if you're trying to secure a data in an app that has a small distribution. but if is app gets popular, like to the point where the zero-day warez guys pay attention to it, that kind of security won't work.
know your enemy.
there is at least one article on CP about Crypto++ - a great crypto library. it does PKE (public key encryption) as well as symmetric encryption, hashes, stream and block ciphers, everything.
-c
Smaller Animals Software, Inc.
You're the icing - on the cake - on the table - at my wake. Modest Mouse
|
|
|
|
|
Do you have any working examples of Crypto++ that you mentioned?
I am doing symetric encryption using a session key.
I tried to use it but it simply wouldn't work for me.
Seamus
|
|
|
|
|
I think you mean the other way 'round Chris
In public key cryptography, it's the PUBLIC key that encrypts and the PRIVATE key that decrypts. This way anybody with the public key can ENCRYPT data, but only the person with the PRIVATE key can actually DECRYPT that data
It makes sense when you think about it. What good is encrypting something when anyone who has the public key (which should be anyone that wants to send you encrypted data) can decrypt it? It's the other way 'round, so that only the intended recipient of the encrypted data (i.e. the private key holder) can decrypt it.
-- Tom L [http://www.informetech.com]
|
|
|
|
|
errr... yeah. what you said.
-c
As I bit into the nectarine, it had a crisp juiciness about it that was very pleasurable - until I realized it wasn't a nectarine at all, but A HUMAN HEAD!!
Jack Handey
|
|
|
|
|
Here's one reason to do it this way: if you want to prove to someone else that the encrypted file really comes from you.
|
|
|
|
|
In fact, the way Chris told is also true. If you use the private key to encrypt your data, then only with private key, you can decrypt it. So, both ways are fine in RSA...
Mustafa Demirhan
http://www.macroangel.com
Sonork ID 100.9935:zoltrix
<nobr>They say I'm lazy but it takes all my time
|
|
|
|
|
Correct me if I'm wrong here....
You could ask for both the key and the text to be decrypted each time a user logs on. That way you are not exposing the decryption key to hackers. Of course you have to trust the people you give the key to!
|
|
|
|
|
Well, what i do is just encrypt the key and then use the encrypted key as the cipher key. That way, if they find the encrypted key from the exe. then if they try usin it, it will be double encrypted and will be useless.
If this is overthrown, use the real key to encrypt and then just kill all the variables in memory with diff hex values (0xFF, 0x00, etc or just do an unreversable encryption algoithm). Good luck!
|
|
|
|
|
Can someone briefly explain the difference between the Encrypt and EncryptBlock class members?
Thanks.
|
|
|
|
|
EncryptBlock works on a single block of data (16, 24 or 32 bytes). The block size is a function of the encryption algorithm and the key.
Ciphers can only process fixed-length chunks (blocks) of data. That block size may be as small as one bit, but then we're talking about stream ciphers not block ciphers like this one. Modern block ciphers generally use 64-bits or more per block.
The Encrypt function will encrypt many blocks at once, though you are required to make sure that the number of bytes you put in is a multiple of the cipher's block size. You often have to pad the end of your data stream to meet the next-highest block size multiple.
-c
Smaller Animals Software, Inc.
You're the icing - on the cake - on the table - at my wake. Modest Mouse
|
|
|
|
|