0

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

node.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;

我错过了什么?

4

1 回答 1

2

问题是什么?

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

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

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

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

crypto模块中的文档node.js说它正在使用EVP_BytesToKeyOpenSSL 的功能来派生密钥和 IV:

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

...

密码用于导出密码密钥和初始化向量 (IV)。该值必须是“二进制”编码字符串或 [Buffer[]。

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

引自Node.js v5.6.0 文档

如何解决问题?

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

一个快速而肮脏(并且非常不安全)的解决方案是找到一个等效的 Delphi 例程,EVP_BytesToKey并使用它来使其工作。

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


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


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

于 2016-02-13T11:40:46.650 回答