views:

2114

answers:

3

Hi,

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.

A: 

The algorithms should match; if you're getting different results it may have to do with the way you're handling the keys and the text. Also keep in mind that Java characters are 2 bytes long, which C++ chars are 1 byte, so that may have something to do with it.

jodonnell
+1  A: 

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.

Alexander
+1  A: 

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.

jsight