Openssl.Net Porting a Ruby Example to C# (From Railscasts 143 Paypal-Security)

Railscast 143 (Paypal security) resulting in We were unable to decrypt the certificate id.

I repeated the entire process a few more times, and it started working. Also reviewed each value in a process similar to the next answer. Unfortunately, any time I switch deployment platforms, I seem to run into the same issue. And eventually, it starts working again.

Using Net::HTTP.get for an https url

Original answer:

uri = URI.parse("https://example.com/some/path")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
@data = http.get(uri.request_uri)

As pointed out in the comments, this is more elegant:

require "open-uri"
@data = URI.parse("https://example.com/some/path").read

Porting C# TripleDESCryptoServiceProvider encryption to PHP

Your main problem lies in the handling of the key. One issue is trivial: In PHP, the md5 function by default returns a hexadecimal dump of the hash, while you need the raw binary value to match C#’s MD5CryptoServiceProvider.ComputeHash(). For that, just add one true parameter to the PHP call (md5(key, true)).

The other issue is a tiny bit more complicated: MD5 returns a 128-bit hash, while 3DES uses a 192-bit key (actually, 168-bit of key with the rest being parity bits, but let’s ignore that here). When you supply a too short key to the PHP implementation, it pads the key using zero bytes; however the .NET/CSP implementation of 3DES seems to repeat the key bytes from the beginning (wrapping the key around). Therefore, to match the .NET behavior in PHP, you need to wrap the key manually ($key . $key).

And the final issue is padding: PHP pads the data using zeros, while .NET uses PKCS#7 padding by default. If you need to handle padding correctly, you need to add it when encrypting, and remove it when decrypting.

define('CIPHER', 'tripledes');
define('MODE', 'cbc');

function Encrypt($data)
{
$iv = chr(1) . chr(2) . chr(3) . chr(4) . chr(5) . chr(6) . chr(7) . chr(8);
$key = 'abcdef';

// determine key bytes from the key text, using MD5 and wrapping around
$key = md5($key, true);
$key = $key . $key;
$tripleKey = substr($key, 0, mcrypt_get_key_size(CIPHER, MODE));

// add PKCS#7 padding
$blocksize = mcrypt_get_block_size(CIPHER, MODE);
$paddingSize = $blocksize - (strlen($data) % $blocksize);
$data .= str_repeat(chr($paddingSize), $paddingSize);

$encodedText = mcrypt_encrypt(CIPHER, $tripleKey, $data, MODE, $iv);
return base64_encode($encodedText);
}

function Decrypt($data)
{
$iv = chr(1) . chr(2) . chr(3) . chr(4) . chr(5) . chr(6) . chr(7) . chr(8);

// determine key bytes from the key text, using MD5 and wrapping around
$key = 'abcdef';
$key = md5($key, true);
$key = $key . $key;
$tripleKey = substr($key, 0, mcrypt_get_key_size(CIPHER, MODE));

$decodedText = mcrypt_decrypt(CIPHER, $tripleKey, base64_decode($data), MODE, $iv);

// check and remove PKCS#7 padding
if (!$decodedText) return $decodedText;
$lastByte = ord($decodedText[strlen($decodedText) - 1]);
if ($lastByte == 0 || $lastByte > mcrypt_get_block_size(CIPHER, MODE)) return FALSE;
$paddingText = substr($decodedText, -$lastByte, $lastByte);
$decodedText = substr($decodedText, 0, -$lastByte);
if ($paddingText != str_repeat(chr($lastByte), $lastByte)) return FALSE;

return $decodedText;
}

But, as a commentator above has already said, this is not really a good cryptographic implementation for many reasons. (And my implementation of the tweaks is not really hardened, either.)



Related Topics



Leave a reply



Submit