Difference in blowfish encryption between perl and ruby
Asked Answered
T

2

7

Why is there a difference in blowfish encryption between Crypt::CBC (perl) and OpenSSL (ruby)?

Perl

use Crypt::CBC;

my $cipher = Crypt::CBC->new( -key => 'length32length32length32length32', -cipher => 'Blowfish' );
my $ciphertext = $cipher->encrypt_hex('test');

# ciphertext is 53616c7465645f5f409c8b8eb353823c06d9b50537c92e19

Ruby

require "rubygems"
require "openssl"

cipher = OpenSSL::Cipher::Cipher.new("bf-cbc")
cipher.encrypt
cipher.key = "length32length32length32length32"

result = cipher.update("test") << cipher.final
ciphertext = result.unpack("H*").first

# ciphertext is 16f99115a09e0464

Crypt::CBC seems to be prepending Salted__ to the output by default. Can you explain what is going on that is so different between these? Is there a way to make OpenSSL behave in a similar way to Crypt::CBC?

Toul answered 9/11, 2011 at 23:53 Comment(2)
The Perl script generates different output each time it is run. The 8 bytes in the output after "Salted__" are the salt that the module used to encrypt the text (I don't know if that info is helpful).Cease
@mob: That actually explains it. It's the initialization vector. Otherwise, a given input always encrypts to the same thing, which discloses information. Joepestro, this probably falls under "why are you inventing your own crypto protocol"Screens
N
8

Crypt::CBC (perl) uses its own method to randomize the salt and initialization vector. Plus in the case of Blowfish it uses a key length of 56 as mentioned above.

Using the perl code from your example:

Perl

use Crypt::CBC;

my $cipher = Crypt::CBC->new( -key => 'length32length32length32length32', -cipher =>  'Blowfish' );
my $ciphertext = $cipher->encrypt_hex('test');
# 53616c7465645f5f409c8b8eb353823c06d9b50537c92e19

To decode this using ruby (OpenSSL) requires a little tweaking to extract the key and initialization vector:

Ruby

require 'openssl'

# Hex string to decode(from above)
string = '53616c7465645f5f409c8b8eb353823c06d9b50537c92e19'

# Pack Hex
string = [string].pack('H*')

# Some Config
pass = 'length32length32length32length32'
key_len = 56;
iv_len  = 8;
desired_len = key_len + iv_len;
salt_re = /^Salted__(.{8})/

#Extract salt
salt = salt_re.match(string)
salt = salt.captures[0]
data  = '';
d = '';
while (data.length < desired_len)
  d = Digest::MD5::digest("#{d}#{pass}#{salt}");
  data << d;
end

#Now you have extracted your key and initialization vector
key = data.slice(0..key_len-1)
iv = data.slice(key_len .. -1)

# Trim string of salt
string = string[16..-1]

cipher = OpenSSL::Cipher::Cipher.new "bf-cbc"
cipher.decrypt
cipher.key_len = key_len
cipher.key = key
cipher.iv = iv

puts cipher.update(string) << cipher.final
# test   
Nidorf answered 14/11, 2012 at 2:47 Comment(0)
T
1

Turns out the blowfish key size defaults are different between these two. OpenSSL defaults to 16, Crypt::Blowfish defaults to 56.

You can override key size in Crypt::CBC by specifying -keysize => n, but unfortunately there does not appear to be a way to override the key size in OpenSSL.

The Openssl library defaults to 16 byte Blowfish key sizes, so for compatibility with Openssl you may wish to set -keysize=>16

http://metacpan.org/pod/Crypt::CBC

Perl (specify keysize)

my $cipher = Crypt::CBC->new( 
    -key => 'length32length32length32length32',
    -keysize => 16,
    -cipher => 'Blowfish' 
);
Toul answered 11/11, 2011 at 22:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.