1

I've a project in vb.net/Jquery. Where I use a encryption function to validate connexion to my 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

Now If I'm offline, I want to check the connexion from indexdb. Then I try to simulated this function bit i failed again and again. I see this but Need node.js. I failed to adapted and I prefer don't put node.js just for that I see this other one here, but it's very long and I failed to put result in variable and worst the result is different from my hash... I see cryptojs from google but don't understand how to use it. When I download it i've 2 folders : components/rollups??

Someone can help me to find a simple way to use a crypto library and how to use it?

YannickIngenierie
  • 602
  • 1
  • 13
  • 37
  • 2
    `Rfc2898DeriveBytes` implements PBKDF2 which is supported by CryptoJS and by the crypto module of NodeJS. You can find examples in the respective documentation, e.g. [here](https://cryptojs.gitbook.io/docs/#pbkdf2) and [here](https://nodejs.org/api/crypto.html#crypto_crypto_pbkdf2sync_password_salt_iterations_keylen_digest). Try an implementation and, if you get stuck, post your most recent code along with a description of the problem. – Topaco Dec 23 '20 at 16:23
  • I already find this page, but failed to implement them, How can I insert in Visual studio, like u can see in my first post. And I never use node.js. That's why cryptojs keep my attention, but how use it – YannickIngenierie Dec 23 '20 at 17:27
  • Or a simple exemple codepen will be very good, just to understand includes and others things around that – YannickIngenierie Dec 23 '20 at 17:48
  • For NodeJS integration in Visual Studio you can find enough infos on the web, e.g. [here](https://learn.microsoft.com/en-us/visualstudio/ide/quickstart-nodejs?view=vs-2019). How to use CryptoJS in a NodeJS environment can also be found, e.g. [here](https://www.npmjs.com/package/crypto-js). – Topaco Dec 23 '20 at 17:58

2 Answers2

1

I used your VB code to get the following (Base64 encoded) sample data for the hash and salt:

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

Since I took the VB code unchanged, the remaining PBKDF2 parameters are:

Password:   Toto
Iterations: 10
Key size:   64 bytes

One possible implementation for password validation in JavaScript using CryptoJS is:

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 uses the WordArray data type (marked as WA in the snippet) and offers various encoders for the conversion, e.g. CryptoJS.enc.Base64 for the conversion from/to Base64, s. here. This makes the _arrayBufferToBase64 and _base64ToArrayBuffer methods obsolete.

Please note that an iteration count of 10 is generally too low. The iteration count is intended to slow down an attacker and should be set as high as possible (e.g. 10,000) while still maintaining acceptable application performance.

Topaco
  • 40,594
  • 4
  • 35
  • 62
0

I create a new post To clearly post the test code using cryptojs. In 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>

In 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

In 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;
}

And like u can imagine... the results are differents between vb.net and javacript In ValidatePassWord, I've in last line :

6lHrQquUwxciBYFdokTmPn0ub+eeZrN0rwgRp2WQqxDplCq9O3Z6WxlR/KjDl24Ziv3GY9q5F9PV6CXprw3M2Q== nUeo17n1s3eJ5wJrFp4PBXFwks8lfS9lCMu8gRLR/fdWIkzRCxQIQ7OVZK0RmzcDsTcQtU2WiLh5OqXtAFyYa4k=

I've a big doubt in salt parameter between base64string and buffer... but I try this 3 solutions... always wrong result in the end

        ret.salt = System.Text.Encoding.UTF8.GetString(hash, 0, hash.Length) 'System.Text.Encoding.Default.GetString(salt) 'Convert.ToBase64String(salt)

Then I try to force the 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

But always same problem no match

YannickIngenierie
  • 602
  • 1
  • 13
  • 37
  • I'd recommend to post a _complete_ set of sample data. I.e. for the VB code, provide an example for `ret.salt` (currently missing) and `ret.hash` (keeping the rest of the PBKDF2 parameters: password (_Toto_), iterations (_10_), keysize (_64 bytes_)). I assume that both data corresponds to `msg.d.salt` and `msg.d.hash` in JavaScript, right? With such sample data, it would be much easier to check `ValidatePassword` or `CryptoJS.PBKDF2` and adjust if necessary. No offense, but it would have been better if you had edited your question and attached this information instead of posting an answer. – Topaco Dec 24 '20 at 17:11
  • I used your VB code to generate the required sample data. You can find a possible JavaScript implementation of the validation using CryptoJS in my answer. – Topaco Dec 24 '20 at 18:18