aes-128-cbc encrytion/decryption using crypto in node.js not giving same result as similar to java code

匆匆过客 提交于 2019-12-24 20:32:58

问题


I am working with third party API in which I have to send data in aes-128 encrypted form. For help in encryption/decryption they have given me java code. I have tried to replicate it in Node.js but i am unable to apply same encrytion as pergive java code hence I am facing error.

The working code in java is -

public class AesCryptUtil {
    Cipher ecipher;
    /**
     * Input a string that will be md5 hashed to create the key.
     * 
     * @return void, cipher initialized
     */
    public AesCryptUtil() {
        try {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");
            kgen.init(128);
            this.setupCrypto(kgen.generateKey());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public AesCryptUtil(String key) {
        SecretKeySpec skey = new SecretKeySpec(getMD5(key), "AES");
        this.setupCrypto(skey);
    }

    private void setupCrypto(SecretKey key) {
        // Create an 8-byte initialization vector
        byte[] iv = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };

        AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);
        try {
            ecipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

            // CBC requires an initialization vector
            ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // Buffer used to transport the bytes from one stream to another
    byte[] buf = new byte[1024];

    public void encrypt(InputStream in, OutputStream out) {
        try {
            // Bytes written to out will be encrypted
            out = new CipherOutputStream(out, ecipher);

            // Read in the cleartext bytes and write to out to encrypt
            int numRead = 0;
            while ((numRead = in.read(buf)) >= 0) {
                out.write(buf, 0, numRead);
            }
            out.close();
        } catch (java.io.IOException e) {
            e.printStackTrace();
        }
    }
/**
     * Input is a string to encrypt.
     * 
     * @return a Hex string of the byte array
     */
    public String encrypt(String plaintext) {
        try {
            byte[] ciphertext = ecipher.doFinal(plaintext.getBytes("UTF-8"));
            return this.byteToHex(ciphertext);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }


    /**
     * Input encrypted String represented in HEX
     **/

    private static byte[] getMD5(String input) {
        try {
            byte[] bytesOfMessage = input.getBytes("UTF-8");
            MessageDigest md = MessageDigest.getInstance("MD5");
            return md.digest(bytesOfMessage);
        } catch (Exception e) {
            return null;
        }
    }

    static final String HEXES = "0123456789ABCDEF";

    public static String byteToHex(byte[] raw) {
        if (raw == null) {
            return null;
        }
        String result = "";
        for (int i = 0; i < raw.length; i++) {
            result += Integer.toString((raw[i] & 0xff) + 0x100, 16).substring(1);
        return result;
    }

    public static byte[] hexToByte(String hexString) {
        int len = hexString.length();
        byte[] ba = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            ba[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
                    + Character.digit(hexString.charAt(i + 1), 16));
        }
        return ba;
    }

    public static void main(String args[]) {
        String result = null;
        String err = null;
        String key = "DEEA29E294D8B2241FB41EF254AAB86F";
        String data = "<?xml version=" + "1.0" + " encoding=" + "UTF-8" + "?><xmltagopen></xmltagclose>";
        String action = "enc";

        if (key == null)
            err = "error: no key";
        else if (key.length() < 32)
            err = "error: key length less than 32 bytes";
        else if (data == null || action == null)
            err = "error: no data";
        else if (action == null)
            err = "error: no action";
        else if (!action.equals("enc") && !action.equals("dec"))
            err = "error: invalid action";

        if (err == null) {
            try {
                AesCryptUtil encrypter = new AesCryptUtil(key);

                if (action.equals("enc"))
                    result = encrypter.encrypt(data);
                else
                    result = encrypter.decrypt(data);
            } catch (Exception e) {
                err = "error : Exception in performing the requested operation : " + e;
            }
        }
        if (result != null)
            System.out.println(result);
        else
            System.out.println(err);
    }

}

I have tried to do similar in node.js but it's not working and I am getting error message from api that encryption is not correct-

const xml = '<?xml version="1.0" encoding="UTF-8"?><xmltagopen</xmltagclose>';
    let key = 'DEEA29E294D8B2241FB41EF254AAB86F';
    let encodeKey = crypto.createHash('md5').update(key, 'utf8').digest("hex");
    console.log(encodeKey);
    let ivBuffer = new Buffer.from([0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f]);
    let iv = ivBuffer.toString('hex');

    let cipher = crypto.createCipher('aes-128-cbc', encodeKey, iv);
    let encText = cipher.update(xml, 'utf8', 'hex');
    encText += cipher.final('hex');
    console.log(encText);

回答1:


The deprecated crypto.createCipher function, as described in API documentation, derives the encryption key from the provided password:

The implementation of crypto.createCipher() derives keys using the OpenSSL function EVP_BytesToKey with the digest algorithm set to MD5, one iteration, and no salt. The lack of salt allows dictionary attacks as the same password always creates the same key. The low iteration count and non-cryptographically secure hash algorithm allow passwords to be tested very rapidly.

Use crypto.createCipheriv instead.

For example like this:

var crypto  = require( 'crypto' );
var encryptionKey = Buffer.from('DEEA29E294D8B2241FB41EF254AAB86F', 'hex');
var iv = Buffer.from([0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f]);
// better: var iv = crypto.randomBytes(16);
var cipher  = crypto.createCipheriv( 'aes-128-cbc', encryptionKey, iv );
var buf1 = cipher.update( Buffer.from(data) );
var buf2 = cipher.final();
var encrypted = Buffer.concat([buf1, buf2]);


来源:https://stackoverflow.com/questions/57123473/aes-128-cbc-encrytion-decryption-using-crypto-in-node-js-not-giving-same-result

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!