2012-08-22 49 views
1

由于某些奇怪的原因,Node内置的CipherDecipher类未按预期工作。该documentation指出cipher.updateNode.js Crypto AES密码

“返回的加密内容,并且在其流可以被称为新的数据很多次了。”

docs还指出cipher.final

“返回任何剩余的加密内容。”

然而,在我的测试中,你必须电话cipher.final获取所有数据,从而使密码对象毫无价值,并且处理您必须创建一个新的Cipher对象的下一个块。

var secret = crypto.randomBytes(16) 
    , source = crypto.randomBytes(8) 
    , cipher = crypto.createCipher("aes128", secret) 
    , decipher = crypto.createDecipher("aes128", secret); 

var step = cipher.update(source); 
var end = decipher.update(step); 

assert.strictEqual(source.toString('binary'), end); // should not fail, but does 

注意,这个使用crypto.createCiphercrypto.createCipheriv时,与秘密的初始化向量发生。解决方法是,以取代线6和7用下列:

var step = cipher.update(source) + cipher.final(); 
var end = decipher.update(step) + decipher.final(); 

但对此,如前所述,使两者cipherdecipher毫无价值。

这就是我期望Node内置的加密技术能够工作的原理,但它显然不适用。这是我如何使用它或Node中的错误的问题?或者我期待错误的事情?我可以直接执行AES,但这会很耗时和烦人。每次我需要加密或解密时,是否应该创建一个新的CipherDecipher对象?这看起来很昂贵,如果我这样做是一个流的一部分。

回答

3

我遇到了两个问题:第一个是我错误地认为块的大小是64位或8字节,这是我用来创建“明文”的原因。实际上,AES的内部将128位明文分成两个64位块,然后从那里开始。

第二个问题是,尽管在应用上述更改后使用了正确的块大小,crypto模块正在应用自动填充,禁用自动填充解决了第二个问题。因此,工作示例如下:

var secret = crypto.randomBytes(16) 
    , source = crypto.randomBytes(16) 
    , cipher = crypto.createCipheriv("aes128", secret, secret); // or createCipher 
    , decipher = crypto.createDecipheriv("aes128", secret, secret); 

cipher.setAutoPadding(false); 
decipher.setAutoPadding(false); 

var step = cipher.update(source); 
var end = decipher.update(step); 

assert.strictEqual(source.toString('binary'), end); // does not fail 
+0

禁用填充是不安全的 –

+0

感谢您的提示。在上下文中,这并不重要,因为我试图在安全性不重要的环境中模拟安全系统的协议。 – skeggse

+0

is atuo padding salt –

2

AES使用16字节的块大小(不是您建议的8倍)。而且,如果启用了填充,它应该始终填充。其原因在于,否则,未压缩算法无法区分填充和明文的最后一个字节。

大多数情况下,您不应该指望密文与纯文本的大小相同。确保始终呼叫doFinal()。如果您正在实施自己的加密方案,则只应使用更新此方法进行加密/解密。

0

a node.js issue连续多次调用更新。我想这个问题已经解决,并在下一个版本中反映出来。