如何在 javascript 中创建像 Rfc2898DeriveBytes 这样的加密函数
How make a crypto function in javascript like Rfc2898DeriveBytes
我在 vb.net/Jquery 有一个项目。我在哪里使用加密功能来验证与我的 Intranet 的连接。
Public Shared Function ValidatePassword(passwordToTest As String, passwordParam As paramPassword) As Boolean
Dim hash() As Byte = passwordParam.hashByteArray
Dim testHash() As Byte = PBKDF2(passwordToTest, passwordParam.saltByteArray, passwordParam.iteration, passwordParam.hashByteArraySize)
Return SlowEquals(hash, testHash)
End Function
Private Shared Function SlowEquals(a() As Byte, b() As Byte) As Boolean
Dim diff As UInteger = CUInt(a.Length) Xor CUInt(b.Length)
For i As Integer = 0 To Math.Min(a.Length, b.Length) - 1
diff = CUInt(a(i) Xor b(i)) Or diff
Next
Return diff = 0
End Function
Private Shared Function PBKDF2(password As String, salt() As Byte, iterations As Integer, outputBytes As Integer) As Byte()
Dim PBKDF2_hasher As Rfc2898DeriveBytes = New Rfc2898DeriveBytes(password, salt)
PBKDF2_hasher.IterationCount = iterations
Return PBKDF2_hasher.GetBytes(outputBytes)
End Function
现在如果我处于离线状态,我想从 indexdb 检查连接。然后我尝试模拟这个功能位,我一次又一次地失败了。
我看到 但需要 node.js。我没有适应,我宁愿不要为此放 node.js
我看到另一个 here,但它很长而且我未能将结果放入变量中,最糟糕的是结果与我的哈希不同......
我从 google 看到了 cryptojs,但不明白如何使用它。当我下载它时,我有 2 个文件夹:components/rollups??
有人可以帮我找到使用加密库的简单方法以及如何使用它吗?
我创建了一个新的 post 为了清楚地 post 使用 cryptojs 的测试代码。
在 aspx
<script src="/Scripts/Crypto/core.js"></script>
<script src="/Scripts/Crypto/hmac.js"></script>
<script src="/Scripts/Crypto/sha1.js"></script>
<script src="/Scripts/Crypto/pbkdf2.js"></script>
<script src="/Scripts/Pages/test.js"></script>
在aspx.vb
Public Class NewPwD
Property hash As String
Property salt As String
End Class
<Services.WebMethod()>
Public Shared Function SetPassWord() As NewPwD
Dim ret As New NewPwD
Dim csprng As RNGCryptoServiceProvider = New RNGCryptoServiceProvider()
Dim salt(63) As Byte
csprng.GetBytes(salt)
Dim hash() As Byte = PBKDF2("Toto", salt, 10, 64)
ret.hash = Convert.ToBase64String(hash)
ret.salt = Convert.ToBase64String(salt)
Return ret
End Function
Private Shared Function PBKDF2(password As String, salt() As Byte, iterations As Integer, outputBytes As Integer) As Byte()
Dim PBKDF2_hasher As Rfc2898DeriveBytes = New Rfc2898DeriveBytes(password, salt)
PBKDF2_hasher.IterationCount = iterations
Return PBKDF2_hasher.GetBytes(outputBytes)
End Function
在test.JS
$(function () {
$.ajax({
type: "POST", url: '/test.aspx/SetPassWord', contentType: 'application/json; charset=utf-8', dataType: "json",
success: function (msg) {
AfficheMsgRetour(ValidatePassWord("Toto", msg.d.hash,msg.d.salt, 64, 10));
}
});
});
function ValidatePassWord(password, hashedPwd, saltString, saltlen, iterations) {
var key = CryptoJS.PBKDF2(password, saltString, { keySize: saltlen, iterations: iterations });
var str = _arrayBufferToBase64(key.words);
return (hashedPwd === str);
}
function _arrayBufferToBase64(buffer) {
var binary = '';
var bytes = new Uint8Array(buffer);
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return window.btoa(binary);
}
function _base64ToArrayBuffer(base64) {
var binary_string = window.atob(base64);
var len = binary_string.length;
var bytes = new Uint8Array(len);
for (var i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
return bytes.buffer;
}
就像你想象的那样...vb.net 和 javacript 之间的结果不同
在 ValidatePassWord 中,我在最后一行:
6lHrQquUwxciBYFdokTmPn0ub+eeZrN0rwgRp2WQqxDplCq9O3Z6WxlR/KjDl24Ziv3GY9q5F9PV6CXprw3M2Q==
nUeo17n1s3eJ5wJrFp4PBXFwks8lfS9lCMu8gRLR/fdWIkzRCxQIQ7OVZK0RmzcDsTcQtU2WiLh5OqXtAFyYa4k=
我对 base64string 和 buffer 之间的 salt 参数有很大的疑问...
但我尝试了这 3 种解决方案...最后总是错误的结果
ret.salt = System.Text.Encoding.UTF8.GetString(hash, 0, hash.Length) 'System.Text.Encoding.Default.GetString(salt) 'Convert.ToBase64String(salt)
那我试试强制放盐
Public Shared Function SetPassWord() As NewPwD
Dim ret As New NewPwD
Dim csprng As RNGCryptoServiceProvider = New RNGCryptoServiceProvider()
Dim originalsalt As String = "azertyuiop"
Dim salt As Byte() = System.Text.Encoding.Default.GetBytes(originalsalt)
Dim hash() As Byte = PBKDF2("Toto", salt, 10, 64)
ret.hash = Convert.ToBase64String(hash)
ret.salt = originalsalt
Return ret
End Function
但总是一样的问题不匹配
我使用您的 VB 代码获取了哈希和盐的以下(Base64 编码)样本数据:
Hash: bAZiQwC3BDvAzUEp/9MJ2HqNPvsB24V5HUnz8YZA1sGP8BOK0H1UhiUSMV4jipPiZiiKXQE8g0jKJt+bzcwj1Q==
Salt: ByMK17y9LCHLtX9+N6c9UlXKwv9r5Q9YPZVwQ1s1a4z9R4vufoFD4ezqfN3iE+mt7cOl9CxGVxYMLXVbdOR83w==
由于我把VB代码不变,剩下的PBKDF2参数是:
Password: Toto
Iterations: 10
Key size: 64 bytes
在 JavaScript 中使用 CryptoJS 进行密码验证的一种可能实现是:
function ValidatePassWord(password, hashedPwd, saltString, keylen, iterations) {
var saltWA = CryptoJS.enc.Base64.parse(saltString);
var hashedPwdToCompareWA = CryptoJS.PBKDF2(password, saltWA, { keySize: keylen / 4, iterations: iterations });
var hashedPwdToCompare = CryptoJS.enc.Base64.stringify(hashedPwdToCompareWA);
//console.log(hashedPwdToCompare);
return (hashedPwd === hashedPwdToCompare);
}
// Data from VB Code
var password = 'Toto';
var keylen = 64;
var iterations = 10;
var hashedPwd = 'bAZiQwC3BDvAzUEp/9MJ2HqNPvsB24V5HUnz8YZA1sGP8BOK0H1UhiUSMV4jipPiZiiKXQE8g0jKJt+bzcwj1Q==';
var saltString = 'ByMK17y9LCHLtX9+N6c9UlXKwv9r5Q9YPZVwQ1s1a4z9R4vufoFD4ezqfN3iE+mt7cOl9CxGVxYMLXVbdOR83w==';
// Successful verification
var verified = ValidatePassWord(password, hashedPwd, saltString, keylen, iterations);
console.log('Test - successful verification:', verified);
// Failed verification
var otherHashedPwd = 'xAZiQwC3BDvAzUEp/9MJ2HqNPvsB24V5HUnz8YZA1sGP8BOK0H1UhiUSMV4jipPiZiiKXQE8g0jKJt+bzcwj1Q==';
var verified = ValidatePassWord(password, otherHashedPwd, saltString, keylen, iterations);
console.log('Test - failed verification: ', verified);
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
CryptoJS 使用 WordArray
数据类型(在代码片段中标记为 WA
)并提供各种编码器用于转换,例如CryptoJS.enc.Base64
用于转换 from/to Base64,s。 here。这使得 _arrayBufferToBase64
和 _base64ToArrayBuffer
方法已过时。
请注意,10 次的迭代次数通常太少了。迭代计数旨在减慢攻击者的速度,应设置得尽可能高(例如 10,000),同时仍保持可接受的应用程序性能。
我在 vb.net/Jquery 有一个项目。我在哪里使用加密功能来验证与我的 Intranet 的连接。
Public Shared Function ValidatePassword(passwordToTest As String, passwordParam As paramPassword) As Boolean
Dim hash() As Byte = passwordParam.hashByteArray
Dim testHash() As Byte = PBKDF2(passwordToTest, passwordParam.saltByteArray, passwordParam.iteration, passwordParam.hashByteArraySize)
Return SlowEquals(hash, testHash)
End Function
Private Shared Function SlowEquals(a() As Byte, b() As Byte) As Boolean
Dim diff As UInteger = CUInt(a.Length) Xor CUInt(b.Length)
For i As Integer = 0 To Math.Min(a.Length, b.Length) - 1
diff = CUInt(a(i) Xor b(i)) Or diff
Next
Return diff = 0
End Function
Private Shared Function PBKDF2(password As String, salt() As Byte, iterations As Integer, outputBytes As Integer) As Byte()
Dim PBKDF2_hasher As Rfc2898DeriveBytes = New Rfc2898DeriveBytes(password, salt)
PBKDF2_hasher.IterationCount = iterations
Return PBKDF2_hasher.GetBytes(outputBytes)
End Function
现在如果我处于离线状态,我想从 indexdb 检查连接。然后我尝试模拟这个功能位,我一次又一次地失败了。
我看到
有人可以帮我找到使用加密库的简单方法以及如何使用它吗?
我创建了一个新的 post 为了清楚地 post 使用 cryptojs 的测试代码。 在 aspx
<script src="/Scripts/Crypto/core.js"></script>
<script src="/Scripts/Crypto/hmac.js"></script>
<script src="/Scripts/Crypto/sha1.js"></script>
<script src="/Scripts/Crypto/pbkdf2.js"></script>
<script src="/Scripts/Pages/test.js"></script>
在aspx.vb
Public Class NewPwD
Property hash As String
Property salt As String
End Class
<Services.WebMethod()>
Public Shared Function SetPassWord() As NewPwD
Dim ret As New NewPwD
Dim csprng As RNGCryptoServiceProvider = New RNGCryptoServiceProvider()
Dim salt(63) As Byte
csprng.GetBytes(salt)
Dim hash() As Byte = PBKDF2("Toto", salt, 10, 64)
ret.hash = Convert.ToBase64String(hash)
ret.salt = Convert.ToBase64String(salt)
Return ret
End Function
Private Shared Function PBKDF2(password As String, salt() As Byte, iterations As Integer, outputBytes As Integer) As Byte()
Dim PBKDF2_hasher As Rfc2898DeriveBytes = New Rfc2898DeriveBytes(password, salt)
PBKDF2_hasher.IterationCount = iterations
Return PBKDF2_hasher.GetBytes(outputBytes)
End Function
在test.JS
$(function () {
$.ajax({
type: "POST", url: '/test.aspx/SetPassWord', contentType: 'application/json; charset=utf-8', dataType: "json",
success: function (msg) {
AfficheMsgRetour(ValidatePassWord("Toto", msg.d.hash,msg.d.salt, 64, 10));
}
});
});
function ValidatePassWord(password, hashedPwd, saltString, saltlen, iterations) {
var key = CryptoJS.PBKDF2(password, saltString, { keySize: saltlen, iterations: iterations });
var str = _arrayBufferToBase64(key.words);
return (hashedPwd === str);
}
function _arrayBufferToBase64(buffer) {
var binary = '';
var bytes = new Uint8Array(buffer);
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return window.btoa(binary);
}
function _base64ToArrayBuffer(base64) {
var binary_string = window.atob(base64);
var len = binary_string.length;
var bytes = new Uint8Array(len);
for (var i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
return bytes.buffer;
}
就像你想象的那样...vb.net 和 javacript 之间的结果不同 在 ValidatePassWord 中,我在最后一行:
6lHrQquUwxciBYFdokTmPn0ub+eeZrN0rwgRp2WQqxDplCq9O3Z6WxlR/KjDl24Ziv3GY9q5F9PV6CXprw3M2Q== nUeo17n1s3eJ5wJrFp4PBXFwks8lfS9lCMu8gRLR/fdWIkzRCxQIQ7OVZK0RmzcDsTcQtU2WiLh5OqXtAFyYa4k=
我对 base64string 和 buffer 之间的 salt 参数有很大的疑问... 但我尝试了这 3 种解决方案...最后总是错误的结果
ret.salt = System.Text.Encoding.UTF8.GetString(hash, 0, hash.Length) 'System.Text.Encoding.Default.GetString(salt) 'Convert.ToBase64String(salt)
那我试试强制放盐
Public Shared Function SetPassWord() As NewPwD
Dim ret As New NewPwD
Dim csprng As RNGCryptoServiceProvider = New RNGCryptoServiceProvider()
Dim originalsalt As String = "azertyuiop"
Dim salt As Byte() = System.Text.Encoding.Default.GetBytes(originalsalt)
Dim hash() As Byte = PBKDF2("Toto", salt, 10, 64)
ret.hash = Convert.ToBase64String(hash)
ret.salt = originalsalt
Return ret
End Function
但总是一样的问题不匹配
我使用您的 VB 代码获取了哈希和盐的以下(Base64 编码)样本数据:
Hash: bAZiQwC3BDvAzUEp/9MJ2HqNPvsB24V5HUnz8YZA1sGP8BOK0H1UhiUSMV4jipPiZiiKXQE8g0jKJt+bzcwj1Q==
Salt: ByMK17y9LCHLtX9+N6c9UlXKwv9r5Q9YPZVwQ1s1a4z9R4vufoFD4ezqfN3iE+mt7cOl9CxGVxYMLXVbdOR83w==
由于我把VB代码不变,剩下的PBKDF2参数是:
Password: Toto
Iterations: 10
Key size: 64 bytes
在 JavaScript 中使用 CryptoJS 进行密码验证的一种可能实现是:
function ValidatePassWord(password, hashedPwd, saltString, keylen, iterations) {
var saltWA = CryptoJS.enc.Base64.parse(saltString);
var hashedPwdToCompareWA = CryptoJS.PBKDF2(password, saltWA, { keySize: keylen / 4, iterations: iterations });
var hashedPwdToCompare = CryptoJS.enc.Base64.stringify(hashedPwdToCompareWA);
//console.log(hashedPwdToCompare);
return (hashedPwd === hashedPwdToCompare);
}
// Data from VB Code
var password = 'Toto';
var keylen = 64;
var iterations = 10;
var hashedPwd = 'bAZiQwC3BDvAzUEp/9MJ2HqNPvsB24V5HUnz8YZA1sGP8BOK0H1UhiUSMV4jipPiZiiKXQE8g0jKJt+bzcwj1Q==';
var saltString = 'ByMK17y9LCHLtX9+N6c9UlXKwv9r5Q9YPZVwQ1s1a4z9R4vufoFD4ezqfN3iE+mt7cOl9CxGVxYMLXVbdOR83w==';
// Successful verification
var verified = ValidatePassWord(password, hashedPwd, saltString, keylen, iterations);
console.log('Test - successful verification:', verified);
// Failed verification
var otherHashedPwd = 'xAZiQwC3BDvAzUEp/9MJ2HqNPvsB24V5HUnz8YZA1sGP8BOK0H1UhiUSMV4jipPiZiiKXQE8g0jKJt+bzcwj1Q==';
var verified = ValidatePassWord(password, otherHashedPwd, saltString, keylen, iterations);
console.log('Test - failed verification: ', verified);
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
CryptoJS 使用 WordArray
数据类型(在代码片段中标记为 WA
)并提供各种编码器用于转换,例如CryptoJS.enc.Base64
用于转换 from/to Base64,s。 here。这使得 _arrayBufferToBase64
和 _base64ToArrayBuffer
方法已过时。
请注意,10 次的迭代次数通常太少了。迭代计数旨在减慢攻击者的速度,应设置得尽可能高(例如 10,000),同时仍保持可接受的应用程序性能。