Blow fish and Macintosh architecture

Hi all,
Had a question, If I use blowfish to encrypt a string on a Intel Macintosh can I decrypt it on power pc Macintosh and get the original string. I don’t have a power pc to test it. Or does blow fish handles the architecture issues.

Yes, that should certainly work regardless of processor type.

Thanks Jules.

Hi all,
I am pretty sure I am doing something wrong. My key is “lucianwasthefirstlycan” and textToEncrypt is “testproduct”

I try to encrypt the text using the key using blow fish algorithm. This is my code

// encrypting the string
      juce::String key = T("lucianwasthefirstlycan");
		juce::BlowFish blown((juce::uint8*)key.toUTF8(), key.length());
		juce::String textToEncrypt = T("testproduct");
		juce::String encryptedString = juce::String::empty;
		juce::String subString1 = juce::String::empty;
		juce::String subString2 = juce::String::empty;
		
		while ( textToEncrypt.isNotEmpty() )
		{
			subString1 = textToEncrypt.substring(0, 4);
			subString2 = textToEncrypt.substring(4, 8);
			textToEncrypt = textToEncrypt.substring(8);
			juce::uint32 text1 = subString1.getIntValue();
			juce::uint32 text2 = subString2.getIntValue();

			blown.encrypt(text1,text2);
			// am not sure whether this is the right way to convert text1 to string.
			subString1 = juce::String(text1);
			subString2 = juce::String(text2);
			
			encryptedString<<subString1<<subString2;
		}
		juce::Logger::outputDebugString(T("encrypted string : ") + encryptedString);

textToEncrypt = juce::String::empty;
		
// decrypting encrypted string
		while ( encryptedString.isNotEmpty() )
		{
			subString1 = encryptedString.substring(0, 4);
			subString2 = encryptedString.substring(4, 8);
			encryptedString = encryptedString.substring(8);
			juce::uint32 text1 = subString1.getIntValue();
			juce::uint32 text2 = subString2.getIntValue();
			
			blown.decrypt(text1,text2);
			subString1 = juce::String(text1);
			subString2 = juce::String(text2);
			
			textToEncrypt<<subString1<<subString2;
		}
		juce::Logger::outputDebugString(T("decrypted string : ") + textToEncrypt);

This returns
encrypted string : 1085998750416093475710859987504160934757
decrypted string : 26100046913416357712233382017100562083110672313398869693519604419351447430119123640987697415412

Erm… I sort of see what you thought you were trying to do, but I’m afraid that code is gibberish! Hint: String::getIntValue does not cast the raw character data into an int (!!)

The best way to convert between a string and its raw data is with a MemoryBlock.

Well, I doubted it too. Thanks for the suggestion. I will give it a try. I don’t know why memory block didn’t come to my mind.

I tried using MemoryBlock, for some reason I couldn’t get it to work. I ended up writing the strings to a file and using file streams for reading them as binary data. This is my code. I will give another shot at getting my memory block code working.

[code]
static const char* pKeyData = “I hope it works this time.”;

void Decrypt()
{
juce::File decryptedFile( T("/blowFishde.ini"));
juce::File encryptedFile(T("/blowFishen.ini"));
if( decryptedFile.existsAsFile() )
decryptedFile.deleteFile();
decryptedFile.create();

int keyBytes = sizeof(pKeyData);
juce::BlowFish bFish( (juce::uint8*)pKeyData,keyBytes);

juce::FileInputStream *pInPutStream   = new juce::FileInputStream( encryptedFile );
juce::FileOutputStream *pOutPutStream = new juce::FileOutputStream( decryptedFile );

if( pInPutStream != 0L  || pOutPutStream != 0L )
{
	while( !pInPutStream->isExhausted() )
	{
		juce::uint32 iData1 = 0;
		juce::uint32 iData2 = 0;
		
		iData1 = pInPutStream->readIntBigEndian();
		iData2 = pInPutStream->readIntBigEndian();
		
		bFish.decrypt(iData1, iData2);
		
		pOutPutStream->writeIntBigEndian(iData1);
		pOutPutStream->writeIntBigEndian(iData2);
		
		pOutPutStream->flush();
	}
	
	delete pInPutStream;
	delete pOutPutStream;
}

}

void Encrypt()
{
juce::File actualFile(T("/blowFish.ini"));
juce::File encryptedFile(T("/blowFishen.ini"));

if( encryptedFile.existsAsFile() )
	encryptedFile.deleteFile();
encryptedFile.create();


int keyBytes = sizeof(pKeyData);
juce::BlowFish bFish( (juce::uint8*)pKeyData,keyBytes);

juce::FileInputStream *pInPutStream = new juce::FileInputStream(actualFile);
juce::FileOutputStream *pOutPutStream = new juce::FileOutputStream(encryptedFile);

if( pInPutStream != 0L  || pOutPutStream != 0L )
{
	while( !pInPutStream->isExhausted() )
	{
		juce::uint32 iData1 = 0;
		juce::uint32 iData2 = 0;
		
		iData1 =  pInPutStream->readIntBigEndian(); 
		iData2 =  pInPutStream->readIntBigEndian(); 
		
		bFish.encrypt(iData1,iData2);
		
		pOutPutStream->writeIntBigEndian (iData1);
		pOutPutStream->writeIntBigEndian (iData2);
		
		pOutPutStream->flush();
	}
}
delete pInPutStream;
delete pOutPutStream;

}[/code]

If these are temporary files, you could also have just used a MemoryInputStream and MemoryOutputStream, you know?

…and OT, I seem to be seeing a lot of code posted recently which makes terrible use of heap objects. In C++ you should never use the new operator if you can put the object on the stack. If you don’t fully understand why RAII is good, do some reading and improve your C++ style!

That was just a demo code.(So I didn’t care about using new) I was testing if I could get it working. I never looked in the direction of MemoryInputStream and MemoryOutputStream, Memory operations are faster and more efficient than the file operation so I will definitely give it a shot(Pretty sure it will work since the file version worked.). I will make the required changes. Thanks for the suggestion.

Dragging up this thread again, and back to the original question, I just ran into this issue myself. The BlowFish routines to encrypt/decrypt take 4-byte values, and they do not handle any endian issues. So if you are reading/writing encrypted data to/from a file, you have to handle the endian-ness yourself. You have to choose a canonical endian format and make sure you byteswap into/out of that format before and after calls to encrypt/decrypt.

It should work in the last code snippet above because that’s exactly what you’re doing with the readIntBigEndian/writeIntBigEndian calls.