java <--> openssl interop
Hello.
I have a problem when trying to decrypt data in java, which was encrypted using openssl.
I keep getting a BadPaddingException("Given final block not properly padded").
After trying to come up with a simple test case, i found the following strange fact;
when encrypting a string in openssl using blowfish in ECB mode (I know, not secure, but bare with me) using a simple key, the encrypted text is different than when I use the same key in java and a "Blowfish/CBC/PKCS5Padding" cipher.
I have no clue as to what the problem might be, and an ready to give up.....
Can someone please please help? I can post relevant code if necessary.
Cheers ;)
[701 byte] By [
tzachara] at [2007-11-27 4:49:34]

# 3
But there will be an equivalent to the -K mode for the C library. The important point is that one does not use a passphrase as key as this is processed by openssl to form the real key bytes. Start with the real key bytes.
My standard AES test example using the command line is
import javax.crypto.spec.*;
import javax.crypto.*;
import me.sabre150.research.howto.runtime.*;
import java.io.*;
public class EncryptOpenSSLDecryptJava
{
private static String toHex(byte[] bites)
{
char[] hexChars = new char[bites.length*2];
for (int charIndex = 0, startIndex = 0; charIndex < hexChars.length;)
{
int bite = bites[startIndex++] & 0xff;
hexChars[charIndex++] = HEX_CHARS[bite >> 4];
hexChars[charIndex++] = HEX_CHARS[bite & 0xf];
}
return new String(hexChars);
}
private static final char[] HEX_CHARS =
{'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
public static void encryptOrDecryptFile(File ifile, Cipher cipher, File ofile) throws Exception
{
InputStream istrm = new FileInputStream(ifile);
istrm = new javax.crypto.CipherInputStream(istrm, cipher);
OutputStream ostrm = new FileOutputStream(ofile);
byte[] buffer = new byte[65536];
for (int len = 0; (len = istrm.read(buffer)) >= 0;)
{
ostrm.write(buffer, 0, len);
}
ostrm.close();
istrm.close();
}
public static void main(String[] args1) throws Exception
{
final String iFile = System.getProperty("user.home") + "/user.sql";
final String eFile = iFile + ".enc";
final String oFile = iFile + ".x";
final String provider = "SunJCE";
final String algorithm = "AES";
final byte[] iv = {1,2,3,4,5,6,7,8,8,7,6,5,4,3,2,1};
final byte[] keyBytes =
{
0,1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf,
10,11,12,13,14,15,16,17,18,19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
};
{
final String[] command = {"sh","-c","openssl enc -e -aes-256-cbc -K " + toHex(keyBytes) + " -iv " + toHex(iv) + " -in " + iFile + " -out " + eFile};
final Process process = Runtime.getRuntime().exec(command);
new Thread(new SyncPipe(process.getErrorStream(), System.err)).start();
new Thread(new SyncPipe(process.getInputStream(), System.out)).start();
final int returnCode = process.waitFor();
System.out.println("'openssl' return code = " + returnCode);
}
{
final Cipher cipher = Cipher.getInstance(algorithm + "/CBC/PKCS5Padding",provider);
final SecretKey key = new SecretKeySpec(keyBytes, algorithm);
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
encryptOrDecryptFile(new File(eFile), cipher, new File(oFile));
}
{
String[] command = {"sh","-c","diff " + iFile + " " + oFile};
final Process process = Runtime.getRuntime().exec(command);
new Thread(new SyncPipe(process.getErrorStream(), System.err)).start();
new Thread(new SyncPipe(process.getInputStream(), System.out)).start();
final int returnCode = process.waitFor();
System.out.println("'diff' return code = " + returnCode);
}
}
}
# 5
>> I just noticed that you say you encrypt using ECB mode but decrypt using CBC mode!
This is just a typo.
here is the code i use in java:
public static byte[] encryptBF(byte[] text, byte[] key)
{
KeyGenerator kgen = KeyGenerator.getInstance("Blowfish");
kgen.init(key.length * 8);
SecretKey skey = kgen.generateKey();
Cipher cipher = Cipher.getInstance("Blowfish/ECB/PKCS5Padding");
byte [] biv= new byte[8];
Arrays.fill(biv, (byte)0);
IvParameterSpec iv = new IvParameterSpec(biv);
cipher.init(Cipher.ENCRYPT_MODE, skey, iv);
return cipher.doFinal(text, 0, text.length);
}
and in C:
void my_enc_init(EVP_CIPHER_CTX *ctx,
unsigned char *key,
int key_len)
{
static unsigned char iv[] = {0,0,0,0,0,0,0,0};
if (ctx == NULL){
TRACE(1, "ctx is null \n");
return;
}
EVP_CIPHER_CTX_init(ctx);
EVP_EncryptInit_ex(ctx, EVP_bf_ecb(), NULL, NULL, NULL);
EVP_CIPHER_CTX_set_key_length(ctx, key_len);
EVP_EncryptInit_ex(ctx, NULL, NULL, key, NULL);
EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv);
return ;
}
int enc(
unsigned char *key,
int key_len,
const unsigned char *data,
int data_len,
unsigned char *out)
{
EVP_CIPHER_CTX ctx;
int outlen = 0;
int tmp = 0;
my_enc_init(&ctx, key, key_len);
if (EVP_EncryptUpdate(&ctx, out, &outlen, data, data_len) != 1){
TRACE(1, "cannot encrypt \n");
ERR_print_errors_fp(stderr);
return -1;
}
if (EVP_EncryptFinal_ex(&ctx, out+outlen, &tmp) != 1){
TRACE(1, "enc not finished correctly. \n");
ERR_print_errors_fp(stderr);
return -1;
}
EVP_CIPHER_CTX_cleanup(&ctx);
return tmp+outlen;
}
using the same key, data and iv results in different cipher text.
they are also different when using CBC.