问题描述
我有一个有趣的任务要为我的一位客户做... 我想在为他构建的应用程序上使用该应用程序之一的帐户。 先前的应用程序是用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,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
我不是节点密码专家,但是经过一番研究,我得出了这个结论:
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,"binary");
const derivedBytes = crypto.pbkdf2Sync(passphrase,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');
}
为帮助我,客户端给了我一个字符串,该字符串使用VB加密中的代码进行编码。 使用VB:“ Password” =>“ IMY4Jo6BkjDPYXR6DK + rhw ==”
如果我尝试使用javascript函数: “密码” =>“ dkofR4Us7O8 + rdeirsg78w ==”
我显然缺少与VB函数获得相同结果的东西。但是经过几天的研究,我对此一无所知。你有什么主意吗?
解决方法
此问题是由不同的密钥派生功能引起的。在VB代码PasswordDeriveBytes
中使用,该代码基于PBKDF1。 PBKDF1在RFC 2898,section 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);
在新代码中,应使用PBKDF2代替PBKDF1(或PasswordDeriveBytes
)。 PBKDF2也已在RFC 2898,section 5.2中定义。 MS在此提供了符合标准的Rfc2898DeriveBytes
的实现。在发布的NodeJS代码中,使用了PBKDF2,这是更安全的实现,但与(可能是旧版)VB代码中使用的PBKDF1不兼容。在2004年4月4日发布的MS Blog中,可以找到有关这两种算法的详细而有启发性的讨论。