http://www.perlmonks.org?node_id=551481

jacques has asked for the wisdom of the Perl Monks concerning the following question:

I need to encrypt a string in Java and decrypt it with Perl. I must use Crypt::CBC and the Blowfish algorithm (Crypt::Blowfish). I am using version 2.08 of C::CBC and 2.09 of C::Blowfish. For Java, I am using the default SUN JDK 1.4.2 crypto libraries (part of the standard VM).

I am having a very difficult time decrypting the string in Perl. I am not sure if the problem is with the Java, the Perl, or both. So I am presenting both programs below.

For the Java encryption, the IV is set to all 64-bit zero and the padding is PKCS5Padding. Of course, I tried to match this on the Perl side. C::CBC defaults to PKCS5Padding and I set the IV to "\0\0\0\0\0\0\0\0".

The key is 64 random hexadecimal characters (0-9 and A-F). I think the handling of the key in the Java code could be the cause of the problem, but I am not sure. The Java program prints the encrypted string to the screen, I then copy and paste it to the Perl script, so I can try to decrypt it. (That is how I am testing it.) Here is my Perl code:

my $key = "8326554161EB30EFBC6BF34CC3C832E7CF8135C1999603D4022C031FAEE +D5C40"; my $vector = "\0\0\0\0\0\0\0\0"; my $cipher = Crypt::CBC->new({ 'key' => $key, 'iv' => $vector, 'prepend_iv' => 0, 'cipher' => 'Blowfish', }); my $plaintext = $cipher->decrypt($encrypted);
Here is the Java code:
import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.IvParameterSpec; import java.security.Key; public class CryptoMain { public static void main(String[] args) throws Exception { String mode = "Blowfish/CBC/PKCS5Padding"; String algorithm = "Blowfish"; String secretStr = "8326554161EB30EFBC6BF34CC3C832E7CF8135C1999603 +D4022C031FAEED5C40"; byte secret[] = fromString(secretStr); Cipher encCipher = null; Cipher decCipher = null; byte[] encoded = null; byte[] decoded = null; encCipher = Cipher.getInstance(mode); decCipher = Cipher.getInstance(mode); Key key = new SecretKeySpec(secret, algorithm); byte[] ivBytes = new byte[] { 00, 00, 00, 00, 00, 00, 00, 00 }; IvParameterSpec iv = new IvParameterSpec(ivBytes); encCipher.init(Cipher.ENCRYPT_MODE, key, iv); decCipher.init(Cipher.DECRYPT_MODE, key, iv); encoded = encCipher.doFinal(new byte[] {1, 2, 3, 4, 5}); // THIS IS THE ENCODED STRING I USE IN THE PERL SCRIPT System.out.println("encoded: " + toString(encoded)); decoded = decCipher.doFinal(encoded); System.out.println("decoded: " + toString(decoded)); encoded = encCipher.doFinal(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}); System.out.println("encoded: " + toString(encoded)); decoded = decCipher.doFinal(encoded); System.out.println("decoded: " + toString(decoded)); } ///////// some hex utilities below.... private static final char[] hexDigits = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' }; /** * Returns a string of hexadecimal digits from a byte array. Each * byte is converted to 2 hex symbols. * <p> * If offset and length are omitted, the complete array is used. */ public static String toString(byte[] ba, int offset, int length) { char[] buf = new char[length * 2]; int j = 0; int k; for (int i = offset; i < offset + length; i++) { k = ba[i]; buf[j++] = hexDigits[(k >>> 4) & 0x0F]; buf[j++] = hexDigits[ k & 0x0F]; } return new String(buf); } public static String toString(byte[] ba) { return toString(ba, 0, ba.length); } /** * Returns the number from 0 to 15 corresponding to the hex digit <i +>ch</i>. */ private static int fromDigit(char ch) { if (ch >= '0' && ch <= '9') return ch - '0'; if (ch >= 'A' && ch <= 'F') return ch - 'A' + 10; if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10; throw new IllegalArgumentException("invalid hex digit '" + ch + "' +"); }