Reputation: 918
I am trying to generate some encrypted JBoss data source passwords from Puppet (Ruby). JBoss uses this library (see line 149) to encrypt / decrypt the passwords (using Blowfish with a predefined key compiled in the Java code).
Now, researching a bit I found that, as default, javax.crypto uses for blowfish the following parameters: Blowfish/ECB/PKCS5Padding.
By default, Ruby's OpenSSL library does not make any padding at all (simply refuses the key if it is not a multiple of 8). I tried to do the padding manually and here is my complete code:
#!/usr/bin/ruby
require 'openssl'
key = 'jaas is the way'
ciph = OpenSSL::Cipher.new('bf-ecb').encrypt
ciph.key = key + (8 - key.length % 8).chr * (8 - key.length % 8)
b = ciph.update(ARGV[0]) + ciph.final()
puts b.unpack('H*')
I tried to implement the PKCS5 padding the same way as I saw it implemented in Python in a similar (Python vs. Java Blowfish) question here on SO by adding chr(number of bytes until the length is multiple of 8) until the length of the string is multiple of 8. For this specific key, it is supposed to add exactly one chr(1) and when trying to debug, it seems to do it just fine.
The thing is that my Ruby code is giving different results to the ones obtained by the code in the Picketbox library in Java.
EDIT: Here are some conclusions I got after running more tests:
If both the key and the plain text to be encrypted are 16 bytes long, the results are fine
We tried with a 16 bytes long plain text string to be encrypted and a 15 bytes key. Then we padded (both pre and post) the key in Ruby with all characters with ASCII code from 0 to 255 and none of the results were matching the encrypted text we got in Java. This makes no sense at all because, if Java would simply pad the key with whatever, it would add a character to the beginning or the end of the original key. The only logical explanation could be if Java does manipulate the key string by other means, other than appending a character.
Upvotes: 0
Views: 1345
Reputation: 918
Worakarn Isaratham's answer is 100% correct, however, I'd like to provide an implementation for this problem using the standard OpenSSL library:
#!/usr/bin/ruby
require 'openssl'
def JBossPasswordEncrypt(s)
ciph = OpenSSL::Cipher.new('bf-ecb').encrypt
# https://source.jboss.org/browse/PicketBox/trunk/security-jboss-sx/jbosssx/src/main/java/org/picketbox/datasource/security/SecureIdentityLoginModule.java?r=332 Line 153
ciph.key_len = 15
ciph.key = 'jaas is the way'
# PKCS5 Padding
s = s + (8 - s.length % 8).chr * (8 - s.length % 8)
# Split the secret in chunks of 8 and encrypt it
e = s.scan(/.{8}/).map { |block| ciph.update(block).unpack('H*') }
# Convert the bytes array into a signed number
en = e.join.to_i(16)
en = en - (2 ** (en.size * 8)) if en >= (2 ** (en.size * 8 - 1))
# Return the result in hex (as string)
return en.to_s(16)
end
puts JBossPasswordEncrypt(ARGV[0])
Thank you very much for the help to everyone!
EDIT: I added conversion to a signed number, just like Java does. Not so nice but it works.
EDIT: I wrote it as a method with easier to understand syntax and comments.
Upvotes: 1
Reputation: 1034
Look like the Java Blowfish does no padding to the key at all; it just starts over from the first byte once it reaches the end of the key. (Try using keys "abc, then "abcabc" and see what happens.)
I suggest looking into this Crypt19 gem - their Blowfish implementation accepts key that is not a multiple of 8. But they only offer CBC mode, so you need to implement ECB yourself. Should be pretty easy - just:
encrypt_block
for each blockEDIT: okay, here's the code. This produces identical output to Java version, at least for this "Hello, world!" input.
require 'crypt/blowfish'
secret = "Hello, world!"
blowfish = Crypt::Blowfish.new("jaas is the way")
padded_secret = secret + (8 - secret.length % 8).chr * (8 - secret.length % 8)
encrypted = padded_secret.scan(/.{8}/).map{|block| blowfish.encrypt_block(block).unpack('H*')}.join
puts encrypted #print "17a0aef80205dd34d08dbf27a0101c9c"
Upvotes: 1