密码箱/节点加密兼容性



我正在尝试(但失败(在Delphi usung LockBox 3中破译使用Node.js加密库加密的消息。

节点.js代码:

var crypto = require('crypto');
var cipher = crypto.createCipher('aes-256-ctr', 'my password');
var crypted = cipher.update('hello world', 'utf8', 'base64');
crypted += cipher.final(output_encoding);
console.log(crypted);

其结果是

oyC1KRVx3JZBLlI=

德尔福密码:

var
  Codec: TCodec;
  CipherText: AnsiString;
begin
  Codec := TCodec.Create(nil);
  try
    Codec.CryptoLibrary := TCryptographicLibrary.Create(Codec);
    //
    Codec.StreamCipherId = 'native.StreamToBlock';
    Codec.BlockCipherId  = 'native.AES-256';
    Codec.ChainModeId    = 'native.CTR';
    //
    Codec.Password := 'my password';
    Codec.DecryptAnsiString(CipherText, 'oyC1KRVx3JZBLlI=');
    //
    Result := string(CipherText);
  finally
    Codec.Free;
  end;
end;

我错过了什么?

问题出在哪里?

问题是两个库在内部使用不同的密钥和初始化向量 (IV(。

请记住,AES 密码不适用于密码,而是密钥和 IV。

当您向加密库提供密码时,它使用某种内部机制来自动派生密钥和 IV。

这种机制并不明显,但通常在加密库的文档中描述。

node.jscrypto模块的文档说它正在使用OpenSSL的EVP_BytesToKey函数来派生密钥和IV:

crypto.createCipher(algorithm, password( - 创建并返回密码 使用给定算法和密码的对象。

密码

用于派生密码密钥和初始化 载体(四(。该值必须是"二进制"编码字符串或 [缓冲区[]。

crypto.createCipher(( 的实现使用 OpenSSL 函数EVP_BytesToKey摘要算法设置为 MD5, 一次迭代,没有盐。缺盐允许字典攻击 因为相同的密码始终创建相同的密钥。低迭代 计数和非加密安全哈希算法允许密码 要非常迅速地进行测试

引用自 Node.js v5.6.0 文档。

如何解决问题?

正确的解决方案是使用加密安全的哈希算法从密码派生密钥,然后手动将密钥和 IV 提供给加密库,无论它是什么。

一个快速而肮脏(且高度不安全(的解决方案是找到一个相当于EVP_BytesToKey的德尔菲例程,并用它来使其工作。

请记住还要检查是否使用相同的填充方案。 TCodec应该允许您选择padPKCS PaddingScheme,它应该与加密模块在node.js中使用的一个兼容。如果它不起作用,也请尝试其他选项。


另一种选择是在Delphi中使用OpenSSL,它应该已经与node.js中使用的内容兼容。


另外,请参阅此问题,该问题与您的问题类似:

  • TPLB 3 OpenSSL 解密 AES-256-CBC 使用 Ruby 2.0.0 加密 OpenSSL::Cipher