Node.js加密密钥和iv匹配java SecretKeySpec / IvParameterSpec

时间:2015-05-31 07:53:13

标签: node.js encryption cryptography aes padding

我正在尝试将Java(简单)加密算法移植到Node JS。我需要能够解密/加密从Java端加密/解密的东西。

我一开始就陷入了密码的初始化。

在Java中,我获得了SecretKeySpec的密钥,以及带有IvParameterSpec的初始化向量:

public CryptStuff(String password) throws zillion_exceptions {
    if (password==null) throw new InvalidKeyException("No encryption password is set!");
    key = new SecretKeySpec(password.getBytes("UTF-8"), "AES");
    cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    ivSpec=new IvParameterSpec(new byte[cipher.getBlockSize()]);
    cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
}

NodeJS需要一个密钥缓冲区和一个IV缓冲区,但是,我不知道如何从头开始计算它们:

var mCrypto = require('crypto'),
    key=[0,0,0,0,0,0,.......],
    iv=[0,0,0,0,0,.........];

function init (password) {

    // generate key from password
    // generate IV from blocksize?

    var aesCipher = mCrypto.createCipheriv("aes-????????", (new Buffer(key)), (new Buffer(iv)));
    .
    .
    .
}

另外,AES / CBC / PKCS5Padding的匹配算法字符串是什么?

1 个答案:

答案 0 :(得分:9)

假设您拥有与Java代码相同的密码字符串,您可以在节点中创建这样的密钥缓冲区:

var key = new Buffer(password, "utf8");

由于你在Java中使用零填充IV(坏!),这是节点中的等效代码:

var iv = new Buffer(16); // 16 byte buffer with random data
iv.fill(0); // fill with zeros

由于您在Java中使用CBC模式,因此您必须在节点中执行相同的操作。请注意,在根据您的"密码"选择密码字符串时,您必须选择正确的密钥大小。长度:

var aesCipher = mCrypto.createCipheriv("aes-128-cbc", key, iv);
// or
var aesCipher = mCrypto.createCipheriv("aes-192-cbc", key, iv);
// or
var aesCipher = mCrypto.createCipheriv("aes-256-cbc", key, iv);

Node将自动应用PKCS#7填充,这与AES的PKCS#5填充相同。

密码不是密钥!

密码通常没有适当的长度用作密钥(AES的有效长度为16字节,24字节和32字节),它只包含可打印的字符,这可能使攻击者更容易暴力强迫关键。

从密码创建密钥所需的是密钥派生功能。流行的是PBKDF2,bcrypt和scrypt(成本增加)。

随机IV!

你真的应该为你生成的每个密文生成一个新的随机IV。如果您使用静态IV,则观察您的密文的攻击者可以确定您发送了相同甚至类似的消息。如果你使用随机IV,那么密文差别很大,攻击者无法确定是否有两个不同的密文是从同一个明文创建的。这称为语义安全。

随机IV本身并不是必须保密的,因此您可以轻松地将其添加到密文并在解密之前将其切片。

您甚至可以将其与密钥派生函数(KDF)结合使用。只需为KDF生成随机盐。 KDF通常能够导出可变数量的输出字节,因此只需让它派生密钥|| IV(连接)然后拆分它们。现在,您只需要将盐添加到密文。

验证<!/ H2>

根据您的系统,您可能容易受到padding oracle攻击等攻击。对此的最好防御是验证密文。因此,您可以使用具有强MAC的加密 - 然后MAC方案(如HMAC-SHA256)或经过身份验证的操作模式(如GCM或EAX)。 Java和节点都支持GCM,但还有一些工作要做。