Blowfish decryption in python of string encoded by javax.crypto

4.3k views Asked by At

Using the code found at https://raw.github.com/usefulfor/usefulfor/master/security/JBoss.java, I did thefollowing:

bash-3.2$ java -cp . JBoss -e testpython
-27038292d345798947e2852756afcf0a
bash-3.2$ java -cp . JBoss -d -27038292d345798947e2852756afcf0a
testpython

However, I can't for the life of me, figure out how to decrypt the string '27038292d345798947e2852756afcf0a' using pycrypto in python. My understanding is that the Java code is using Blowfish, and the phrase 'jaas is the way' as the key for the cipher. But I can't make any sense of how to do this in python. The following results in mostly unprintable garbage:

import Crypto
from Crypto.Cipher import Blowfish
from base64 import b64encode, b64decode

bs        = Blowfish.block_size
key       = 'jaas is the way'
plaintext = b'27038292d345798947e2852756afcf0a'
iv        = '\0' * 8

c1 = Blowfish.new(key, Blowfish.MODE_ECB)
c2 = Blowfish.new(key, Blowfish.MODE_CBC, iv)
c3 = Blowfish.new(key, Blowfish.MODE_CFB, iv)
c4 = Blowfish.new(key, Blowfish.MODE_OFB, iv)

msg1 = c1.decrypt(plaintext)
msg2 = c2.decrypt(plaintext)
msg3 = c3.decrypt(plaintext)
msg4 = c4.decrypt(plaintext)

print "msg1 = %s\n" % msg1
print "msg2 = %s\n" % msg2 
print "msg3 = %s\n" % msg3 
print "msg4 = %s\n" % msg4 

What am I missing ?

thanks.

2

There are 2 answers

2
SquareRootOfTwentyThree On

First of all, that Java example code is very bad. It outputs the ciphertext as an integer, whereas ciphertext should remain a binary string. The reason is that an integer can be represented in an infinite number of binary encodings. For instance, the number one can be '0x01' (1 byte), '0x0001' (2 bytes), and so forth. When you are dealing with cryptographic functions, you must be extremely precise with the representation.

Additionally, the example uses the default values of the javax.crypto API, which are not described anywhere. So it is really trial and error.

For the solution, you must know how to convert negative integers to hex strings in Python. In this case, you don't need a hex string, but its byte representation. The concept is the same though. I use PyCrypto's long_to_bytes to convert a positive integer (of arbitrary length) to a byte string.

from Crypto.Cipher import Blowfish
from Crypto.Util.number import long_to_bytes

def tobytestring(val, nbits):
    """Convert an integer (val, even negative) to its byte string representation.
    Parameter nbits is the length of the desired byte string (in bits).
    """
    return long_to_bytes((val + (1 << nbits)) % (1 << nbits), nbits/8)

key = b'jaas is the way'
c1  = Blowfish.new(key, Blowfish.MODE_ECB)

fromjava = b"-27038292d345798947e2852756afcf0a"
# We don't know the real length of the ciphertext, assume it is 16 bytes
ciphertext = tobytestring(int(fromjava, 16), 16*8)
print c1.decrypt(ciphertext)

The output is:

'testpython\x06\x06\x06\x06\x06\x06'

From that you see that javax.crypto also adds PKCS#5 padding, which you need to remove by yourself. That is trivial to do though.

However, the real solution to your problem is to do Java encryption in a better way. The Python code will be greatly simplified.

0
dexxtr On

This helps me

private byte[] encrypt(String key, String plainText) throws GeneralSecurityException {

    SecretKey secret_key = new SecretKeySpec(key.getBytes(), ALGORITM);

    Cipher cipher = Cipher.getInstance(ALGORITM);
    cipher.init(Cipher.ENCRYPT_MODE, secret_key);

    return cipher.doFinal(plainText.getBytes());
}

hope this will be useful for you, more http://dexxtr.com/post/57145943236/blowfish-encrypt-and-decrypt-in-java-android