Rijndael 加密 VB 到 Javascript

Lat*_*suj 1 javascript vb.net encryption rijndael node.js

我有一项有趣的任务要为我的一位客户做...我应该在我为他构建的应用程序上使用此应用程序之一的帐户。之前的应用程序是用VB编写的,并使用以下函数对密码数据进行加密:

Public Function Encrypt(ByVal plainText As String) As String
   Dim passPhrase As String = "minePassPhrase"
   Dim saltValue As String = "mySaltValue"
   Dim hashAlgorithm As String = "SHA1"
   Dim passwordIterations As Integer = 2
   Dim initVector As String = "@1B2c3D4e5F6g7H8"
   Dim keySize As Integer = 256
   Dim initVectorBytes As Byte() = Encoding.ASCII.GetBytes(initVector)
   Dim saltValueBytes As Byte() = Encoding.ASCII.GetBytes(saltValue)
   Dim plainTextBytes As Byte() = Encoding.UTF8.GetBytes(plainText)
   Dim password As New PasswordDeriveBytes(passPhrase, saltValueBytes, hashAlgorithm, passwordIterations)
   Dim keyBytes As Byte() = password.GetBytes(keySize \ 8)
   Dim symmetricKey As New RijndaelManaged()
   symmetricKey.Mode = CipherMode.CBC
   Dim encryptor As ICryptoTransform = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes)
   Dim memoryStream As New MemoryStream()
   Dim cryptoStream As New CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)
   cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length)
   cryptoStream.FlushFinalBlock()
   Dim cipherTextBytes As Byte() = memoryStream.ToArray()
   memoryStream.Close()
   cryptoStream.Close()
   Dim cipherText As String = Convert.ToBase64String(cipherTextBytes)
   Return cipherText
End Function
Run Code Online (Sandbox Code Playgroud)

我不是节点密码的专业人士,但经过一些研究,我得出以下结论:

const crypto = require('crypto');

const encrypt = function (data) {

    const passPhrase = "minePassPhrase";
    const hashAlgorithm = "SHA1";
    const passwordIterations = 2;
    const keySize = 256;

    const initVector = "@1B2c3D4e5F6g7H8";
    const saltValue = "mySaltValue";

    const initVectorBytes = Buffer.from(initVector.substring(0, 32),"binary");
    const saltValueBytes = Buffer.from(saltValue.substring(0, 32),"binary");

    const derivedBytes = crypto.pbkdf2Sync(passPhrase, saltValueBytes, passwordIterations, keySize, hashAlgorithm);
    const key = derivedBytes.slice(0, Math.floor( keySize / 8 ));

    const cipher = crypto.createCipheriv('aes-256-cbc', key, initVectorBytes);
    const output = Buffer.concat([cipher.update(data, 'utf8'), cipher.final()]);

    return output.toString('base64');
}
Run Code Online (Sandbox Code Playgroud)

为了帮助我,客户给了我一个字符串编码,其中包含 VB 加密的代码。使用VB:“密码”=>“IMY4Jo6BkjDPYXR6DK+rhw==”

如果我尝试使用我的javascript函数:“Password”=>“dkofR4Us7O8+rdeIRsg78w==”

我显然错过了一些东西来获得与 VB 函数相同的结果。但经过几天的研究,我独自一人失去了理智。你有什么主意吗 ?

Top*_*aco 5

该问题是由不同的密钥派生函数引起的。在VB代码中PasswordDeriveBytes使用的是基于PBKDF1的。PBKDF1 在RFC 2898 第 5.1 节中定义。生成的密钥的长度对应于所使用的摘要的长度,即 SHA1 为 20 个字节。MS 扩展了该算法,以便还可以生成更长的密钥,例如发布代码中的 32 字节。然而,这意味着 MS 实现不再符合标准,因此跨平台并不总是能找到对应的。幸运的是,NodeJS 的情况有所不同,这里有一个实现,请参见jheys /derive-password-bytes

以下节点实现重现了 VB 代码的结果:

const derp = require('derive-password-bytes');
const crypto = require('crypto');

const encrypt = function (data) {

    const passPhrase = "minePassPhrase";
    const hashAlgorithm = "SHA1";
    const passwordIterations = 2;
    const keySize = 256;
    const saltValue = "mySaltValue";
    const key = derp(passPhrase, saltValue, passwordIterations, hashAlgorithm, 32);

    const initVector = "@1B2c3D4e5F6g7H8";
    const initVectorBytes = Buffer.from(initVector, "binary");
    
    const cipher = crypto.createCipheriv('aes-256-cbc', key, initVectorBytes);
    const output = Buffer.concat([cipher.update(data, 'utf8'), cipher.final()]);

    return output.toString('base64');
}

const plaintext = "Password"
var encrypted = encrypt(plaintext);

console.log(encrypted);
Run Code Online (Sandbox Code Playgroud)

在新代码中,应使用 PBKDF2 代替 PBKDF1(或PasswordDeriveBytes)。PBKDF2 也在RFC 2898 第 5.2 节中定义。Rfc2898DeriveBytes这里MS提供了符合标准的实现。在发布的 NodeJS 代码中使用了 PBKDF2,这是更安全的实现,但与(可能是遗留的)VB 代码中使用的 PBKDF1 不兼容。关于这两种算法的详细且富有启发性的讨论可以在 04/2004 的MS 博客中找到。