7

I'm trying to encrypt a string in java, send it to my node.js server, and decrypt it. However, when I try to do this I get keep getting errors when trying to decrypt.

Java encrypt:

String privateKey = "someprivatekey";
String data = "dataToEncrypt";

DESKeySpec keySpec = new DESKeySpec(privateKey.getBytes("UTF-8"));
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey key = keyFactory.generateSecret(keySpec);

byte[] dataToBytes = data.getBytes("UTF-8");      

Cipher cipher = Cipher.getInstance("DES"); 
cipher.init(Cipher.ENCRYPT_MODE, key);

// send this string to server 
String encryptedStr = Base64.encodeToString(cipher.doFinal(dataToBytes), 0);

node.js decrypt:

var privateKey = 'someprivatekey';
var decipher = crypto.createDecipher('des', privateKey);
var dec = decipher.update(textToDecipher, 'base64', 'utf8'); 
dec += decipher.final('utf8'); 
console.log('deciphered: ' + dec);

However, I get this error on the node.js side on the decipher.final() line:

TypeError: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt

I've tried decoding the string and using a buffer on the node side, but it didn't seem to work either, I get the same bad decrypt error.

var buffer = new Buffer(textToDecipher, 'base64');
var decipher = crypto.createDecipher('des', privateKey);
var dec = Buffer.concat([decipher.update(buffer), decipher.final()]);

Any ideas what I could be doing wrong?

4
  • "someprivatekey" is not a valid DES key. Is your actual key shorter? Commented Aug 17, 2015 at 16:14
  • I think node.js/java uses different padding by default. Try to specify padding explicitly. Commented Aug 17, 2015 at 16:31
  • @ArtjomB. Yes, it is shorter, does the string length matter when creating a DES key? Commented Aug 17, 2015 at 17:14
  • Yes. DES is only specified for 8 byte keys (with parity). Please don't use DES nowadays. It's rather easy to brute-force with some EC2 time. If you really want to use DES, you should at least use Triple DES (3DES) or otherwise AES. Also, don't ever use ECB mode. It's not semantically secure. Use at least CBC mode with a random IV. Commented Aug 17, 2015 at 17:36

2 Answers 2

5

When you create the decipher object on the node server, you are passing a password rather than an actual key. In order to specify the actual key, you need to use crypto.createDecipheriv(), but this requires an actual IV (this example uses 8 null bytes, but that's not recommended for real encryption; Initialization Vector on wikipedia)

I was able to get your example working by explicitly specifying padding, block mode, and IV:

String privateKey = "someprivatekey";
String data = "dataToEncrypt";

DESKeySpec keySpec = new DESKeySpec(privateKey.getBytes("UTF-8"));
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey key = keyFactory.generateSecret(keySpec);

byte[] dataToBytes = data.getBytes("UTF-8");      

Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); 
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(new byte[8]));

// send this string to server 
String encryptedStr = Base64.encodeToString(cipher.doFinal(dataToBytes), 0);

The decryption version also explicitly specifies the block mode (des-cbc), and correctly truncates the key text to the first 8 bytes:

var privateKey = 'someprivatekey';
var textToDecipher = '9Y8GTNxhQkKSIm5pmH91VA=='; // Text "dataToEncrypt" encrypted using DES using CBC and PKCS5 padding with the key "someprivatekey"

var iv = new Buffer(8);
iv.fill(0);

var decipher = crypto.createDecipheriv('des-cbc', privateKey.substr(0,8), iv);
var dec = decipher.update(textToDecipher, 'base64', 'utf8');
dec += decipher.final('utf8');
console.log('deciphered: ' + dec);
Sign up to request clarification or add additional context in comments.

Comments

1

Java crypto's default mode for DES is ECB, which you need to specify in nodejs:

var decipher = crypto.createDecipheriv('des-ecb', key, new Buffer(0))
var txt = decipher.update(encrypt_text, 'hex', 'utf8');
txt += decipher.final('utf8')
return txt

1 Comment

Although changing to CBC on both sides as in tombrown52's answer is even better.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.