the output of "crypto.createCipheriv with chinese character" is not correct

Viewed 81

when there is no chinese character, php and node output the same result.

but when this is chinese character, the output of php is correct, the output of node is not correct

const crypto = require('crypto');
function encodeDesECB(textToEncode, keyString) {
  var key = new Buffer(keyString.substring(0, 8), 'utf8');
  var cipher = crypto.createCipheriv('des-ecb', key, '');
  cipher.setAutoPadding(true);
  var c = cipher.update(textToEncode, 'utf8', 'base64');
  c += cipher.final('base64');
  return c;
}

console.log(encodeDesECB(`{"key":"test"}`, 'MIGfMA0G'))
console.log(encodeDesECB(`{"key":"测试"}`, 'MIGfMA0G'))

node output

6RQdIBxccCUFE+cXPODJzg==
6RQdIBxccCWXTmivfit9AOfoJRziuDf4

php output

6RQdIBxccCUFE+cXPODJzg==
6RQdIBxccCXFCRVbubGaolfSr4q5iUgw
1 Answers

The problem is not the encryption, but a different JSON serialization of the plaintext.

In the PHP code, json_encode() converts the characters as a Unicode escape sequence, i.e. the encoding returns {"key":"\u6d4b\u8bd5"}. In the NodeJS code, however, {"key": "测试"} is applied.

This means that different plaintexts are encrypted in the end. Therefore, for the same ciphertext, a byte-level identical plaintext must be used.


If Unicode escape sequences are to be applied in the NodeJS code (as in the PHP code), an appropriate conversion is necessary. For this the jsesc package can be used:

const jsesc = require('jsesc');
...
console.log(encodeDesECB(jsesc(`{\"key\":\"测试\"}`, {'lowercaseHex': true}), 'MIGfMA0G')); // 6RQdIBxccCXFCRVbubGaolfSr4q5iUgw

now returns the result of the posted PHP code.


If the Unicode characters are to be used unmasked in the PHP code (as in the NodeJS code), an appropriate conversion is necessary. For this the flag JSON_UNESCAPED_UNICODE can be set in json_encode():

$data = json_encode($data, JSON_UNESCAPED_UNICODE); // 6RQdIBxccCWXTmivfit9AOfoJRziuDf4

now returns the result of the posted NodeJS code.

Related