Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Node.js 使用加密模块将java编写的DESede/ECB/NoPadding算法转换为Nodejs_Node.js_Des_Cryptojs - Fatal编程技术网

Node.js 使用加密模块将java编写的DESede/ECB/NoPadding算法转换为Nodejs

Node.js 使用加密模块将java编写的DESede/ECB/NoPadding算法转换为Nodejs,node.js,des,cryptojs,Node.js,Des,Cryptojs,我正在将代码从java迁移到Nodejs。我需要使用“DESede/ECB/NoPadding”算法用私钥加密文本。目前代码是用Java编写的,现在我需要迁移到Nodejs。由于加密密钥被发送到其他应用程序,因此我不能在这里更改算法或密钥。以下是java中使用的方法 1. Stored the private key in hex string. I.e. 48 chars hex string as below which is equivalent to 24 bytes reuquired

我正在将代码从java迁移到Nodejs。我需要使用“DESede/ECB/NoPadding”算法用私钥加密文本。目前代码是用Java编写的,现在我需要迁移到Nodejs。由于加密密钥被发送到其他应用程序,因此我不能在这里更改算法或密钥。以下是java中使用的方法

1. Stored the private key in hex string. I.e. 48 chars hex string as below which is equivalent to 24 bytes reuquired for 3des
73AD9CEC99816AA6A4D82FB273AD9CEC99816AA6A4D82FB2
2. Following is code written in java 
https://github.com/dilipkumar2k6/3des/blob/master/TripleDes.java
import java.security.GeneralSecurityException;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;


public class TripleDes {
    // Crypto library related keys
    private static final String ALGO_NAME = "DESede/ECB/NoPadding";
    private static final int PADDING_BLOCK = 8;

    // Test Data
    private static final String PLAIN_TEXT = "Hello World";
    private static final String SHARED_KEY = "73AD9CEC99816AA6A4D82FB273AD9CEC99816AA6A4D82FB2";

    public static void main(String[] arg) {

        try {
            // Get Algorithm name
            String desAlgoName = getDESAlgorithmName(ALGO_NAME);
            // Create Cipher object
            Cipher cipher = Cipher.getInstance(ALGO_NAME);
            //Actual DES algo needs 56 bits key, which is equivalent to 1byte (0 at 0th position)  Get 8*3 byets key
            byte [] key = hexFromString(SHARED_KEY);
            System.out.println("DES Algorithm  shared key size in bytes >> "+key.length);
            // Create SecretKeySpec
            SecretKeySpec secretKeySpec = new SecretKeySpec(key, desAlgoName);
            //Encrypt bytes
            byte [] encryptedBytes = encryptIntoBytes(cipher, secretKeySpec, PLAIN_TEXT.getBytes(), 0, PLAIN_TEXT.getBytes().length);
            String encryptedString=  hexToString(encryptedBytes);
            System.out.println(encryptedString);

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public static byte[] encryptIntoBytes(Cipher cipher, SecretKeySpec secretKeySpec, byte[] dct, int offset, int len) throws GeneralSecurityException {
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
        byte[] ect = cipher.doFinal(addPadding(dct, offset, len));
        return ect;
    }

    public static String getDESAlgorithmName(String algoName) {
        System.out.println("getDESAlgorithmName algoName >> "+algoName);
        String desAlgoName = null;
        int i = algoName.indexOf("/");
        if (i != -1)
            desAlgoName = algoName.substring(0, i);
        else
            desAlgoName = algoName;
        return desAlgoName;
    }

    /**
     * Adds padding characters to the data to be encrypted. Also adds random
     * Initial Value to the beginning of the encrypted data when using Triple
     * DES in CBC mode (DES-EDE3/CBC).
     * 
     * @param inData
     *            Array of bytes to be padded
     * @param offset
     *            Offset to starting point within array
     * @param len
     *            Number of bytes to be encrypted
     * @return Padded array of bytes
     */
    public static byte[] addPadding(byte[] inData, int offset, int len) {
        System.out.println("addPadding offset >> "+offset+", len >> "+len);
        byte[] bp = null;
        int padChars = PADDING_BLOCK; // start with max padding value
        int partial = (len + 1) % padChars; // calculate how many extra bytes
                                            // exist
        if (partial == 0) {
            padChars = 1; // if none, set to only pad with length byte
        } else {
            padChars = padChars - partial + 1; // calculate padding size to
                                                // include length
        }
        System.out.println("addPadding >> Add padding of "+padChars);
        /*
         * Create a byte array large enough to hold data plus padding bytes The
         * count of padding bytes is placed in the first byte of the data to be
         * encrypted. That byte is included in the count.
         */
        bp = new byte[len + padChars];
        bp[0] = Byte.parseByte(Integer.toString(padChars));
        System.arraycopy(inData, offset, bp, 1, len);
        return bp;
    }

    public static byte[] hexFromString(String hex) {
        int len = hex.length();
        byte[] buf = new byte[((len + 1) / 2)];

        int i = 0, j = 0;
        if ((len % 2) == 1)
            buf[j++] = (byte) fromDigit(hex.charAt(i++));

        while (i < len) {
            buf[j++] = (byte) ((fromDigit(hex.charAt(i++)) << 4) | fromDigit(hex
                    .charAt(i++)));
        }
        return buf;
    }

    public static int fromDigit(char ch) {
        if (ch >= '0' && ch <= '9')
            return ch - '0';
        if (ch >= 'A' && ch <= 'F')
            return ch - 'A' + 10;
        if (ch >= 'a' && ch <= 'f')
            return ch - 'a' + 10;

        throw new IllegalArgumentException("invalid hex digit '" + ch + "'");
    }

    public static String hexToString(byte[] ba) {
        return hexToString(ba, 0, ba.length);
    }

    public static final char[] hexDigits = { '0', '1', '2', '3', '4', '5',
            '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

    public static String hexToString(byte[] ba, int offset, int length) {
        char[] buf = new char[length * 2];
        int j = 0;
        int k;

        for (int i = offset; i < offset + length; i++) {
            k = ba[i];
            buf[j++] = hexDigits[(k >>> 4) & 0x0F];
            buf[j++] = hexDigits[k & 0x0F];
        }
        return new String(buf);
    }

}
下面是我的问题

1. How can i convert my existing hex code into string? I used "hexToString" method (please check the java code)to convert hex into string. However getting weired character (this is also expected but problem is how i can use this transformed key in nodejs.
2. Can I pass byte array as key to Nodejs? It will make problem easy as I can easily convert my hex key into bytes array and I store my bytes array key in nodejs code.
3. In my javacode, I have custom padding logic, how can i write same logic in nodejs?
4. Most importantly, can I achieve same encryption logic in nodejs (similar to java)?
Artjom B.帮助我了解了nodejs和des3算法。我已经编辑了我的帖子,以澄清我的确切要求

我想我的主要问题是,如何将byte[]作为密钥提供给DES3的nodejs加密


我有点卡住了。请提供帮助。

运行
crypto.getCiphers()
将显示可用的密码。ECB模式下带有两个键(16字节键)的三重DES(EDE)可用作
DES EDE
。如果您有三部分键(24字节键),则应使用
des-ede3
ecb
可能不会出现在密码描述中,因为它是最基本的形式

三重DES-EDE使用密钥的方式不同。EDE意味着使用三种不同的密钥进行加密解密。例如,如果您只有一个8字节的键,这表明您在EDE的每个阶段都使用相同的键。从Java代码中可以清楚地看到,您有一个24字节的密钥(48个十六进制编码的字符)。您必须使用相同的键

默认情况下,加密模块使用PKCS7填充,因此您需要设置并自己进行填充。我把那项任务交给你去做

module.exports = {
    encrypt: function (plainText) {
        return encrypt({
            alg: 'des-ede3', //3des-ecb  
            autoPad: false,
            key: '73AD9CEC99816AA6A4D82FB273AD9CEC99816AA6A4D82FB2',
            plaintext: 'Hello World',
            iv: null
        });
    }
};

function mypad(buf){
    // TODO: do the padding
    // replicate padding as in Java
    return buf;
}

function myunpad(buf){
    // TODO: do the unpadding
    // read the first *byte* and remove as many trailing *bytes*
    return buf;
}

function encrypt(param) {
    var key = new Buffer(param.key);
    var iv = new Buffer(param.iv ? param.iv : 0);
    var plaintext = mypad(new Buffer(param.plaintext));
    var alg = param.alg;
    var autoPad = param.autoPad;

    //encrypt  
    var cipher = crypto.createCipheriv(alg, key, iv);
    cipher.setAutoPadding(autoPad);  //default true  
    var ciph = cipher.update(plaintext, 'utf8', 'hex');
    ciph += cipher.final('hex');
    console.log(alg, ciph);
    return ciph;
}

function decrypt(param) {
    var key = new Buffer(param.key);
    var iv = new Buffer(param.iv ? param.iv : 0)
    var alg = param.alg;
    var autoPad = param.autoPad;

    //decrypt  
    var decipher = crypto.createDecipheriv(alg, key, iv);
    cipher.setAutoPadding(autoPad);
    var txt = decipher.update(ciph, 'hex', 'utf8');
    txt += decipher.final('utf8');
    console.log(alg, txt);
    return myunpad(new Buffer(txt, 'hex'));
}

警告:


不要使用(3)DES,尤其是只有一个8字节的密钥!不要使用ECB模式!不要在块模式中使用NoPadding!在GCM模式下使用AES-256(因为它是流模式,所以没有填充)。-

这是我基于Artjom答案的解密函数。如果您有24字节的密钥,请使用“des-ede3”

internals.decrypt = function (message, key) {
    var message = Buffer.from(message, 'base64');
    var decipher = crypto.createDecipher('des-ede', key);

    var decryptedMessage = decipher.update(message, 'hex', 'utf8');
    decryptedMessage += decipher.final('utf8');
    return decryptedMessage.toString();
}

谢谢我尝试使用des ede,但不知道iv的值是什么。它将错误作为无效iv抛出。错误:错误:0607A082:数字信封例程:EVP_CIPHER_CTX_set_key_length:对象的新Cipheriv(crypto.js:346:17)的无效密钥长度。Cipheriv(crypto.js:344:12)ECB模式不需要iv。使用null,或者传递一个零长度的缓冲区。我正在使用null和IV,仍然会出错,我已经更新了我的示例代码。请看一下。第一行是错误消息,表示密钥大小无效。此模式的3DES键只能是16字节而不是48字节。即使使用16字节长的键,它也不起作用。然而,当我改为des-ede3和16字节的组合键,然后它的工作。但主要问题是我使用了现有密钥,java中使用的现有密钥长3465Werate56345tgewrGW412432654765UEFGSDF4545435也添加了代码段。
internals.decrypt = function (message, key) {
    var message = Buffer.from(message, 'base64');
    var decipher = crypto.createDecipher('des-ede', key);

    var decryptedMessage = decipher.update(message, 'hex', 'utf8');
    decryptedMessage += decipher.final('utf8');
    return decryptedMessage.toString();
}