I am trying to learn various encryption methods and came across a problem when trying to generate ciphertext with Perl vs PHP.
If I encrypt a secret with PHP, I can decrypt the resulting ciphertext in both PHP and Perl, but if I encrypt in Perl the ciphertext is 'wrong' and the secret gets garbled by both PHP and Perl...
encrypt.php:
#!/usr/bin/env php
<?php
# Set up vars
$iv = 'length16length16';
$key = 'length32length32length32length32';
$cleartext = 'password';
if( count( $argv ) > 1 )
{
$cleartext = $argv[1];
}
# --- ENCRYPTION ---
# Set up cipher
$cipher = mcrypt_module_open( MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
mcrypt_generic_init( $cipher, $key, $iv );
# Do the encryption
$ciphertext = mcrypt_generic( $cipher, $cleartext );
# Convert to HEX for print/storage
$cipher_block = implode( unpack( 'H*', $iv . $ciphertext ) );
print( "IV " . implode( unpack( 'H*', $iv ) ) );
print( "CIPH " . implode( unpack( 'H*', $ciphertext ) ) );
print( $cipher_block );
# Clean up
mcrypt_generic_deinit( $cipher );
mcrypt_module_close( $cipher );
?>
decrypt.php:
#!/usr/bin/env php
<?php
# Set up vars
$key = 'length32length32length32length32';
if( count( $argv ) > 1 )
{
# --- DECRYPTION ---
# Grab the hex-encoded cipherblock & convert it to binary
$cipher_block = unpack( 'a16iv/a*ciphertext', pack( 'H*', $argv[1] ) );
# Set up cipher
$cipher = mcrypt_module_open( MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
mcrypt_generic_init( $cipher, $key, $cipher_block['iv'] );
# Do the decryption
$cleartext = mdecrypt_generic( $cipher, $cipher_block['ciphertext'] );
print( $cleartext );
# Clean up
mcrypt_generic_deinit( $cipher );
mcrypt_module_close( $cipher );
}
?>
encrypt.pl:
#!/usr/bin/env perl
use strict;
use warnings;
use Crypt::CBC;
# Set up vars
my $iv = 'length16length16';
my $key = 'length32length32length32length32';
my $cleartext = shift;
# --- ENCRYPTION ---
# Set up cipher
my $cipher = Crypt::CBC->new(
-literal_key => 1,
-key => $key,
-header => 'none',
-iv => $iv,
-cipher => 'Crypt::OpenSSL::AES');
# Do the encryption
my $ciphertext = $cipher->encrypt( $cleartext );
# Convert to HEX for print/storage
my $cipher_block = unpack( 'H*', $iv . $ciphertext );
print( "IV " . unpack( 'H*', $iv ) . "\n" );
print( "CIPH " . unpack( 'H*', $ciphertext ) . "\n" );
print( $cipher_block );
decrypt.pl:
#!/usr/bin/env perl
use strict;
use warnings;
use Crypt::CBC;
# Set up vars
my $key = 'length32length32length32length32';
my $cipher_block = shift;
if( $cipher_block )
{
# --- DECRYPTION ---
# Grab the hex-encoded cipherblock & convert it to binary
my ($iv, $ciphertext) = unpack( 'a16a*', pack( 'H*', $cipher_block ) );
# Set up cipher
my $cipher = Crypt::CBC->new(
-literal_key => 1,
-key => $key,
-header => 'none',
-iv => $iv,
-cipher => 'Crypt::OpenSSL::AES');
my $cleartext = $cipher->decrypt( $ciphertext );
print( $cleartext );
}
And this is the output I get:
$ ./encrypt.php "Secret Text"
IV 6c656e67746831366c656e6774683136
CIPH 32a47901313f47ed2ca657d3bd0c2e80
6c656e67746831366c656e677468313632a47901313f47ed2ca657d3bd0c2e80
$ ./decrypt.php 6c656e67746831366c656e677468313632a47901313f47ed2ca657d3bd0c2e80
Secret Text
$ ./decrypt.pl 6c656e67746831366c656e677468313632a47901313f47ed2ca657d3bd0c2e80
Secret Text
$ ./encrypt.pl "Secret Text"
IV 6c656e67746831366c656e6774683136
CIPH f3ae0d5f236cea77fa9ac5540d733aef
6c656e67746831366c656e677468313632a47901313f47ed2ca657d3bd0c2e80
$ ./decrypt.php 6c656e67746831366c656e677468313632a47901313f47ed2ca657d3bd0c2e80
sesswrtext
$ ./decrypt.pl 6c656e67746831366c656e677468313632a47901313f47ed2ca657d3bd0c2e80
sesswrtext
As you can see, even with an identical secret, key & IV, the Perl script generates a distinct ciphertext, that the PHP & Perl scripts both decrypt to be the same, but not the original secret...
Thanks in advance.