Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using openssl encryption with Java

I have a legacy C++ module that offers encryption/decryption using the openssl library (DES encryption). I'm trying to translate that code into java, and I don't want to rely on a DLL, JNI, etc... C++ code looks like:

des_string_to_key(reinterpret_cast<const char *>(key1), &initkey);
des_string_to_key(reinterpret_cast<const char *>(key2), &key);
key_sched(&key, ks);
// ...
des_ncbc_encrypt(reinterpret_cast<const unsigned char *>(tmp.c_str()), 
reinterpret_cast< unsigned char *>(encrypted_buffer), tmp.length(), ks, &initkey, 
DES_ENCRYPT);

return base64(reinterpret_cast<const unsigned char *>(encrypted_buffer),    strlen(encrypted_buffer));

Java code looks like:

Cipher ecipher;
try {
    ecipher = Cipher.getInstance("DES");
    SecretKeySpec keySpec = new SecretKeySpec(key, "DES");      
    ecipher.init(Cipher.ENCRYPT_MODE, keySpec);         
    byte[] utf8 = password.getBytes("UTF8");
    byte[] enc = ecipher.doFinal(utf8);
    return new sun.misc.BASE64Encoder().encode(enc);
}
catch {
    // ...
}

So I can do DES encryption in Java pretty easily, but how can I get the same result as with the above code with methods that are completely different? What bothers me in particular is the fact that the C++ version uses 2 keys while the Java version uses only 1 key. The answer about DES in CBC mode is quite satisfying but I can't get it to work yet. Here are more details about the original code: unsigned char key1[10]= {0}; unsigned char key2[50]= {0};

int i;
for (i=0;i<8;i++)
    key1[i] = 31+int((i*sqrt((double)i*5)))%100;
key1[9]=0;

for (i=0;i<48;i++)
    key2[i] = 31+int((i*i*sqrt((double)i*2)))%100;
key2[49]=0;
...
// Initialize encrypted buffer
memset(encrypted_buffer, 0, sizeof(encrypted_buffer));

// Add begin Text and End Text to the encrypted message
std::string input;
const char beginText = 2;
const char endText = 3;
input.append(1,beginText);
input.append(bufferToEncrypt);
input.append(1,endText);    

// Add padding
tmp.assign(desPad(input));

des_ncbc_encrypt(reinterpret_cast<const unsigned char *>(tmp.c_str()),     
reinterpret_cast< unsigned char *>(encrypted_buffer), tmp.length(), ks, &initkey, 
DES_ENCRYPT);
...

From what I've read, the key should be 56 (or 64, it's not clear to me) bits long, but here it's 48 bytes long.

like image 647
jerome Avatar asked Sep 18 '08 13:09

jerome


2 Answers

I'm not an OpenSSL expert, but I'd guess the C++ code is using DES in CBC mode thus needing an IV (that's what the initKey probably is, and that's why you think you need two keys). If I'm right, you need to change your Java code to use DES in CBC mode too, then the Java code too will require an encryption key and an IV.

like image 97
Alexander Avatar answered Oct 13 '22 21:10

Alexander


Also, keep in mind that you really shouldn't use sun.misc.* classes in your code. This could break in other VMs as these are not public APIs. Apache Commons Codecs (among others) have implementations of Base64 that don't bear this problem.

I'm not really sure why single DES would ever use multiple keys. Even if you were using Triple-DES, I believe you would use a single key (with more bytes of data) rather than using separate keys with the Java Cryptography API.

like image 33
jsight Avatar answered Oct 13 '22 23:10

jsight