简体   繁体   中英

why encrypt result is different using same AES algorithm and same key between CryptoJS and node built-in crypto module

I was developing server with Node.js and client with Ionic framework

I made API for login request from client

when client request login, sends encrypted id and password string

and server decrypt received id and password string and check validation

I used crypto-js( https://code.google.com/archive/p/crypto-js/ ) library for client encryption

client encryption code below

var secret = 'abcdefghijklmnopqrstuvwxyz123456';
var id = "someId";
var encrypted = CryptoJS.AES.encrypt(id, password);
console.log(encrypted.toString());  // U2FsdGVkX19EfjjBwydSZL509wKl5TEX+4f3vakEejU=

For server-side decryption I used node built-in crypto module

const crypto = require('crypto');
var method = 'aes256';
var secret = 'abcdefghijklmnopqrstuvwxyz123456';
var id = "U2FsdGVkX19EfjjBwydSZL509wKl5TEX+4f3vakEejU=" // suppose we received with no loss
var decipher = crypto.createDecipher(method, secret);
decipher.update(id,'base64','utf8');
var deciphered = decipher.final('utf8');
console.log(deciphered);

server-side decrypt code crash with error message below

crypto.js:153
  var ret = this._handle.final();
                         ^

Error: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
    at Error (native)
    at Decipher.Cipher.final (crypto.js:153:26)
    at Object.<anonymous> (...\routes\index.js:33:27)
    at Module._compile (module.js:409:26)
    at Object.Module._extensions..js (module.js:416:10)
    at Module.load (module.js:343:32)
    at Function.Module._load (module.js:300:12)
    at Module.require (module.js:353:17)
    at require (internal/module.js:12:17)
    at Object.<anonymous> (...\app.js:18:14)
    at Module._compile (module.js:409:26)
    at Object.Module._extensions..js (module.js:416:10)
    at Module.load (module.js:343:32)
    at Function.Module._load (module.js:300:12)
    at Module.require (module.js:353:17)
    at require (internal/module.js:12:17)

As error message was 'bad decrypt' so I tried to encrypt same text with each library

[crypto-js]

var secret = 'abcdefghijklmnopqrstuvwxyz123456';
var id = "someId";
var encrypted = CryptoJS.AES.encrypt(id, password);
console.log(encrypted.toString());  // U2FsdGVkX19EfjjBwydSZL509wKl5TEX+4f3vakEejU=

[crypto module]

const crypto = require('crypto');
var method = 'aes256';
var secret = 'abcdefghijklmnopqrstuvwxyz123456';
var id = "someId" 
var cipher= crypto.createCipher(method, secret);
cipher.update(id,'base64','utf8');
var ciphered = decipher.final('utf8');
console.log(ciphered.toString()); // WAsd61C2bfG7UbO5STo13A==

I found out result of library is different

plain text : 'someId'
crpyto-js  : 'U2FsdGVkX19EfjjBwydSZL509wKl5TEX+4f3vakEejU='
crpyto module : 'WAsd61C2bfG7UbO5STo13A=='

I tried to understand the source code of each library

but it was too complicate so, I couldn't understand

I want to know how each library's encrytion works and what cause the different result

You are using two different systems which may have different defaults. Do not rely on defaults, but explicitly specify everything to be the same on both sides. Crypto is designed to fail if even the smallest thing does not match. You will need to specify the character to byte mapping used, the crypto mode, the IV (if needed), the key and the padding method.

Your different outputs are different lengths, so initially I suspect that padding is the first thing to look at. Set both sides to PKCS#7 padding and see if that helps.

For further diagnosis, check that the key and IV are byte-for-byte the same on each side.

All parameters must be specified and correct. Do not rely on defaults, they are implementation dependent and will very between implementations.

In general you should use:

  1. CBC mode with a random iv, on encryption create a random iv, prepend it to the encrypted data for use on decryption. For AES the iv should be 16-bytes, the block size. Do not use ECB mode, it is insecure, see ECB mode , scroll down to the Penguin.

  2. PKCS#7 padding (sometimes called PKCS#5). This is needed because AES is a block cipher and input and output must be an exact multiple of the block size. This padding will be automatically added during encryption and removed during decryption.

  3. Ensure the iv and key are exactly the correct size.

  4. For debugging display all inputs and outputs in hexadecimal. It can be helpful during debugging to dump all inputs and outputs just prior to and after encryption and decryption. Hexadecimal allows one to see each byte, Base64 combines 3 bytes into 4 bytes and makes it harder to understand.

When all this is exactly the same the outputs will also be exactly the same.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM