wwarby
asked on
Two-way Encryption that works consistently across Classic ASP and PHP
I have what should be a fairly simple requirement. I want two pairs of functions, to encode and decode a string in ASP and PHP respectively, where the encryption key is hard-coded into the functions. It isn't to protect a bank vault so as long as the only vulnerability is access to the source code, that's good enough. I'm not wedded to any particular implementation method or algorithm so long as it's a good algorithm like AES or TripleDES and not a home-made one or something. The critical thing is that a string encoded with the function in ASP must be decoded correctly in PHP and vice-versa. I am licenced for Chilkat.Crypt so I planned to use that on the ASP side. I'm having terrible trouble writing functions that work consistently across the two platforms, although I feel like I'm very close to a solution. Current working code attached (the keys are made up and not sensitive).
<?php
function aes_encrypt_string($text) {
return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, 'GpAeScw2LQWaYnRddbh4cPksce76gQ1', $text, MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_RAND))));
}
function aes_decrypt_string($text) {
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, 'GpAeScw2LQWaYnRddbh4cPksce76gQ1', base64_decode($text), MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_RAND)));
}
echo('Encrypted: '.aes_encrypt_string('ch1ck!NLi77L£').'<br /><br />');
//Output: TWF88j6Tt/YHrIyCqMCWiA== <-- note the output is completely different from the ASP output
echo('Decrypted (PHP): '.aes_decrypt_string('TWF88j6Tt/YHrIyCqMCWiA==').'<br /><br />');
//Expected output: ch1ck!NLi77L£
//Actual output: ch1ck!NLi77L£ <-- note the insertion of an "Â" character
echo('Decrypted (ASP): '.aes_decrypt_string('OIKi5I0lkUU3m5dt7fBDUw==').'<br /><br />');
//Expected output: ch1ck!NLi77L£
//Actual output: ch1ck!NLi77L£ <-- note the insertion of an "Â" character and two weird characters on the end
?>
<%
Function AESEncryptString(text)
Dim objCrypt
Set objCrypt = CreateObject("Chilkat.Crypt2")
With objCrypt
.UnlockComponent("LONDONCrypt_SkO3CEBVVREY")
.CryptAlgorithm = "rijndael"
.CipherMode = "ECB"
.EncodingMode = "base64"
.SetEncodedKey "GpAeScw2LQWaYnRddbh4cPksce76gQ1", "ascii"
.Charset = "utf-8"
AESEncryptString = .EncryptStringENC(text)
End With
End Function
Function AESDecryptString(text)
Dim objCrypt
Set objCrypt = CreateObject("Chilkat.Crypt2")
With objCrypt
.UnlockComponent("LONDONCrypt_SkO3CEBVVREY")
.CryptAlgorithm = "rijndael"
.CipherMode = "ECB"
.EncodingMode = "base64"
.SetEncodedKey "GpAeScw2LQWaYnRddbh4cPksce76gQ1", "ascii"
.Charset = "utf-8"
AESDecryptString = .DecryptStringENC(text)
End With
End Function
'Note the use of a string for encryption containing a "£" character. When I tried encrypting the string "This is a test", everything worked perfectly (albeit with very slightly different output from the encryption functions but both decryption functions decrypted both outputs perfectly.)
Response.Write "Encrypted: " & AESEncryptString("ch1ck!NLi77L£") & "<br /><br />"
'Output: OIKi5I0lkUU3m5dt7fBDUw== <-- note the output is completely different from the PHP output
Response.Write "Decrypted (ASP): " & AESDecryptString("TWF88j6Tt/YHrIyCqMCWiA==") & "<br /><br />"
'Expected output: ch1ck!NLi77L£
'Actual output: ch1ck!NLi77L£ <-- note the output is correct
Response.Write "Decrypted (PHP): " & AESDecryptString("OIKi5I0lkUU3m5dt7fBDUw==") & "<br /><br />"
'Expected output: ch1ck!NLi77L£
'Actual output: ch1ck!NLi77L£ <-- again note the output is correct even though the encrypted string is completely different
%>
Many of these codes are BLOCK ciphers and must be made up to a given block length. You may need to pad your stings. I had similar behaviour when doing some Blowfish encryption and wound up padding code
$dataLen = strlen( $data );
if ( ( $dataLen % $this->blockSize ) > 0 ) {
$extra = $this->blockSize - ( $dataLen % $this->blockSize );
$data = $data . str_pad(" ", $extra);
}
Once I did that everything was ticketty-boo!
$dataLen = strlen( $data );
if ( ( $dataLen % $this->blockSize ) > 0 ) {
$extra = $this->blockSize - ( $dataLen % $this->blockSize );
$data = $data . str_pad(" ", $extra);
}
Once I did that everything was ticketty-boo!
"pad your stings"????
Whoops! I meant "pad your strings".
Whoops! I meant "pad your strings".
ASKER
@Ray:
I hadn't thought it worth mentioning before (stupidly) but I'm stuck on PHP 4 (the code I'm writing is an extension to a third party product and to much huge annoyance they still have not upgraded to PHP 5). When your code didn't work on my PHP 4 server (it didn't like the keyword "private") I tried it on a PHP 5 server, and from there discovered the core of the problem:- there's something wrong with PHP 4 that breaks both your code and mine. I tried an identical test file on both servers. They produce completely different encoded results, and the one produced in PHP 4 fails to decode correctly on either PHP 4 or PHP 5. The attached sample illustrates the problem.
So I guess the focus of my question has shifted to: how do I circumvent what looks like a bug in PHP4's mcrypt_encrypt function?
I hadn't thought it worth mentioning before (stupidly) but I'm stuck on PHP 4 (the code I'm writing is an extension to a third party product and to much huge annoyance they still have not upgraded to PHP 5). When your code didn't work on my PHP 4 server (it didn't like the keyword "private") I tried it on a PHP 5 server, and from there discovered the core of the problem:- there's something wrong with PHP 4 that breaks both your code and mine. I tried an identical test file on both servers. They produce completely different encoded results, and the one produced in PHP 4 fails to decode correctly on either PHP 4 or PHP 5. The attached sample illustrates the problem.
So I guess the focus of my question has shifted to: how do I circumvent what looks like a bug in PHP4's mcrypt_encrypt function?
<?php
function encrypt($text) {
$eot = '___EOT';
$key = 'quay';
$ivs = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($ivs, MCRYPT_RAND);
$text .= $eot;
$data = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_ECB, $iv);
$data = base64_encode($data);
return $data;
}
function decrypt($text) {
$eot = '___EOT';
$key = 'quay';
$ivs = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($ivs, MCRYPT_RAND);
$text = base64_decode($text);
$data = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_ECB, $iv);
$data = explode($eot, $data);
return $data[0];
}
echo('Encrypted: '.encrypt('ch1ck!NLi77L£').'<br /><br />');
//Note the completely different output strings produced by PHP4 and PHP5. The one produced by PHP4 is corrupted with a "Â" character when decoded on either PHP4 or PHP5.
echo('PHP5 Output Decrypted: '.decrypt('JlS3HtZ4wmVcgaqRuMbmr8CLrwidlTAtZ8+5KPzMfEk=').'<br /><br />');
echo('PHP4 Output Decrypted: '.decrypt('fkBHqfFbPsgyjjwFXvwBNM8OH6zxWP6vUzE00WCCFkc=').'<br /><br />');
?>
Interesting - PHP4 has been dead so long I do not think about it any more. Let me try to recast the class for PHP4, but please understand that I do not have a test bed for PHP4 (nor for my Model T Ford :-)
Nother question... Are you good at translating PHP into ASP? We might be able to build our own "encryption" scheme. Not too secure, but better than ROT13 and good enough to temporarily confound prying eyes.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Well, I finally managed to uncover the basic nature of the problem - it had to do with inserting the text for decryption directly into the source code. Where I had 'ch1ck!NLi77L£' as a string right in the source code, it failed. When I swapped that out for $_REQUEST['password'] and added "password=ch1ck!NLi77L£" to the query string, it worked. The same did not occur on my PHP5 server, but I suspect that has more to do with the configuration of the servers than the distinction between PHP4 and PHP5.
In the end I looked up how to use Chilkat's ActiveX control in PHP and realised it was incredibly simple, so now I've opted to use that in preference over PHP's functions. I figure using the same control to do the same thing in both languages offers an extra level of assurance that the output will be the same.
Thanks for all your help - you definitely put me on the path that let to working out what the problem was.
In the end I looked up how to use Chilkat's ActiveX control in PHP and realised it was incredibly simple, so now I've opted to use that in preference over PHP's functions. I figure using the same control to do the same thing in both languages offers an extra level of assurance that the output will be the same.
Thanks for all your help - you definitely put me on the path that let to working out what the problem was.
Thanks for the points - I think the Chilkat control sounds like the best answer all around!
Open in new window