【问题标题】:How make a crypto function in javascript like Rfc2898DeriveBytes如何在 javascript 中创建加密函数,如 Rfc2898DeriveBytes
【发布时间】:2021-04-02 05:43:50
【问题描述】:

我在 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 检查连接。然后我尝试模拟这个功能位,我一次又一次地失败了。 我看到 this 但需要 node.js。我没有适应,我更喜欢不要仅仅为此而放置 node.js 我看到另一个here,但它很长,我没有将结果放入变量中,最糟糕的是结果与我的哈希不同...... 我从 google 看到了 cryptojs,但不明白如何使用它。当我下载它时,我有 2 个文件夹:组件/汇总??

谁能帮我找到一个简单的方法来使用加密库以及如何使用它?

【问题讨论】:

  • Rfc2898DeriveBytes 实现了由 CryptoJS 和 NodeJS 的加密模块支持的 PBKDF2。您可以在相应的文档中找到示例,例如herehere。尝试实现,如果遇到困难,请发布您最近的代码以及问题描述。
  • 我已经找到这个页面,但未能实现它们,我如何在 Visual Studio 中插入,就像你在我的第一篇文章中看到的那样。而且我从不使用 node.js。这就是为什么 cryptojs 引起了我的注意,但是如何使用它
  • 或者一个简单的例子codepen会很好,只是为了理解包含和其他东西
  • 对于 Visual Studio 中的 NodeJS 集成,您可以在网络上找到足够的信息,例如here。还可以找到如何在 NodeJS 环境中使用 CryptoJS,例如here.

标签: javascript encryption pbkdf2


【解决方案1】:

我创建一个新帖子使用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和缓冲区之间的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

但总是同样的问题不匹配

【讨论】:

  • 我建议发布一组完整示例数据。 IE。对于 VB 代码,提供ret.salt(当前缺失)和ret.hash(保留其余 PBKDF2 参数:密码(Toto)、迭代(10)的示例>),密钥大小(64 字节))。我假设这两个数据都对应于 JavaScript 中的msg.d.saltmsg.d.hash,对吧?有了这样的样本数据,检查ValidatePasswordCryptoJS.PBKDF2 并在必要时进行调整会容易得多。无意冒犯,但如果您编辑了您的问题并附上了此信息而不是发布答案,那就更好了。
  • 我使用您的 VB 代码生成了所需的示例数据。您可以在我的回答中找到使用 CryptoJS 进行验证的可能 JavaScript 实现。
【解决方案2】:

我使用您的 VB 代码为哈希和盐获取了以下(Base64 编码)示例数据:

Hash:       bAZiQwC3BDvAzUEp/9MJ2HqNPvsB24V5HUnz8YZA1sGP8BOK0H1UhiUSMV4jipPiZiiKXQE8g0jKJt+bzcwj1Q==
Salt:       ByMK17y9LCHLtX9+N6c9UlXKwv9r5Q9YPZVwQ1s1a4z9R4vufoFD4ezqfN3iE+mt7cOl9CxGVxYMLXVbdOR83w==

由于我把VB代码不变,剩下的PBKDF2参数是:

Password:   Toto
Iterations: 10
Key size:   64 bytes

使用 CryptoJS 在 JavaScript 中验证密码的一种可能实现是:

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);
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"&gt;&lt;/script&gt;

CryptoJS 使用 WordArray 数据类型(在 sn-p 中标记为 WA)并提供各种编码器用于转换,例如CryptoJS.enc.Base64 用于从/到 Base64 的转换,s。 here。这使得 _arrayBufferToBase64_base64ToArrayBuffer 方法过时了。

请注意,10 次的迭代次数通常太少。迭代计数旨在减缓攻击者的速度,应将其设置得尽可能高(例如 10,000),同时仍保持可接受的应用程序性能。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-06
    • 1970-01-01
    • 2013-11-18
    • 2011-12-05
    相关资源
    最近更新 更多