Invalid Array Length in using Cryptojs - javascript

I am trying to transpose a c# code to a javascript using cryptojs and in the c# code it uses TripleDESCryptoServiceProvider. I can get everything exactly the values of C# in my javascript code except for the encrypting part. I get an error of "Invalid array length" This is the whole error message:
"RangeError: Invalid array length
at WordArray.init.clamp (http://localhost:8100/auth-login-login-module.js:1392:27)
at WordArray.init.concat (http://localhost:8100/auth-login-login-module.js:1357:19)
at Object.pad (http://localhost:8100/auth-login-login-module.js:652:19)
at Object._doFinalize (http://localhost:8100/auth-login-login-module.js:729:26)
at Object.finalize (http://localhost:8100/auth-login-login-module.js:400:44)
at Object.encrypt (http://localhost:8100/auth-login-login-module.js:912:41)
at Object.encrypt (http://localhost:8100/auth-login-login-module.js:438:59)
at AuthService.encryptText (http://localhost:8100/auth-login-login-module.js:6745:83)
at LoginPage.ngOnInit (http://localhost:8100/auth-login-login-module.js:6939:26)
at checkAndUpdateDirectiveInline (http://localhost:8100/vendor.js:65455:19)"
Please see my code on c# and javascript.
C#
public static string EncryptTxt(string key, string msg, CipherMode mode, Int16 KeyOffSet)
{
SHA512CryptoServiceProvider sha = new SHA512CryptoServiceProvider();
byte[] newKey = new byte[23];
using (var tdes = new TripleDESCryptoServiceProvider())
{
byte[] Results;
System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding();
MD5CryptoServiceProvider HashProvider = new MD5CryptoServiceProvider();
byte[] TDESKey = HashProvider.ComputeHash(UTF8.GetBytes(key));
TripleDESCryptoServiceProvider TDESAlgorithm = new TripleDESCryptoServiceProvider();
byte[] keybyte = sha.ComputeHash(Encoding.UTF8.GetBytes(key));
byte[] newKeyx = new byte[24];
Array.Copy(keybyte, KeyOffSet, newKeyx, 0, newKeyx.Length);
TDESAlgorithm.Key = newKeyx;
TDESAlgorithm.Mode = mode;
TDESAlgorithm.Padding = PaddingMode.PKCS7;
byte[] DataToEncrypt = UTF8.GetBytes(msg);
try
{
ICryptoTransform Encryptor = TDESAlgorithm.CreateEncryptor();
Results = Encryptor.TransformFinalBlock(DataToEncrypt, 0, DataToEncrypt.Length);
}
finally
{
TDESAlgorithm.Clear();
HashProvider.Clear();
}
return Convert.ToBase64String(Results);
}
javascript
encryptText = () => {
debugger;
const msg = 'xxx:juan:201910181809:12345678';
let key = crypto.enc.Utf8.parse('xxx');
key = crypto.MD5(key);
key.words.push(key.words[0], key.words[1]);
const iv = crypto.enc.Utf8.parse('xxx');
// MD5CryptoServiceProvider
const hashProvider = crypto.MD5(iv);
const TDESKey = this.wordArrayToByteArray(hashProvider, 8);
const keybyte = this.wordArrayToByteArray(crypto.SHA512(iv), 16);
const newKeyx = new Uint8Array(24);
const newkeybyte = keybyte.slice(10, 34);
Object.assign(newKeyx, newkeybyte);
const TDESAlgorithmKey = newkeybyte;
const DataToEncrypt = this.wordArrayToByteArray(crypto.enc.Utf8.parse(msg), 40);
const dteLength = DataToEncrypt.length;
const encrypted = crypto.TripleDES.encrypt(DataToEncrypt, key, {
keySize: dteLength,
mode: crypto.mode.ECB,
padding: crypto.pad.Pkcs7,
algo: TDESAlgorithmKey
});
const result = this.wordArrayToByteArray(encrypted.ciphertext, dteLength);
console.log(encrypted);
return encrypted;
}
wordToByteArray(word: any, length: any) {
const ba = [], xFF = 0xFF;
if (length > 0) {
// tslint:disable-next-line:no-bitwise
ba.push(word >>> 24);
}
if (length > 1) {
// tslint:disable-next-line:no-bitwise
ba.push((word >>> 16) & xFF);
}
if (length > 2) {
// tslint:disable-next-line:no-bitwise
ba.push((word >>> 8) & xFF);
}
if (length > 3) {
// tslint:disable-next-line:no-bitwise
ba.push(word & xFF);
}
return ba;
}
Can you please show me how to do this right. I really appreciate it!

This error is triggered when you pass an object (other data type rather than a string).
Convert your parameter to string before passing it ahead.

Try using JSON.stringify(), let me know if it works ..

Related

AES-GCM Secret/Symmetric Key Validation with Encrypted Buffer Comparison of SubtleCrypto and SJCL

Our application has a group chat feature which involves end-to-end encryption of group chat messages.
The group is hosted at server.
All the encryption and decryption is handled on the clientside.
It also utilizes the same mechanism of encryption for the real-time messages.
The group chat works by foremost someone creating this group at serverside, when a client is instating its creation they generate a new key [clientside], and validate it on their end [successful encryption and decryption of a same static text from SubtleCrypto], and then successfully hosts it by sending the encrypted buffer to server where groups are managed, storing it, and then others can join if they know the secret key. We use the same AES-GCM Symmetric Key / Secret Key that is generated for this purpose. The server-side doesn't have the key stored anywhere.
Now, to validate whether the key a client trying to join this group is valid or not before joining is, with the key that was shared to them [by other means, such as email etc], at client-side, encrypt the SAME static text, and send its buffer. Then the buffer value stored at the server-side on creation time is compared to this new client joining with the buffer of the newly encrypted static text they performed on client-side, and if the buffer is equal on server-side, they are authorized into this group.
Now with reference to my previous question(s), I'm attempting to replace Web API SubtleCrypto to SJCL, and the newly generated SJCL encrypted buffer is never the same compared to the SubtleCrypto. While encrypting and decrypting between each other is already established, the problem at hand is that their buffers don't match, even though they're both using the same key, IV, and AES-GCM mode. And they both have to simultaneously work for backwards compatibility of different client versions.
Here is an example:
const buf2hex = (buffer) =>
{
return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
}
const string2hex = (input) =>
{
let hex;
let result = "";
let i = 0;
for (i = 0; i < input.length; i++)
{
hex = input.charCodeAt(i).toString(16);
result += ("000" + hex).slice(-4);
}
return result
}
const hex2bytes = (string) =>
{
const normal = string.length % 2 ? "0" + string : string; // Make even length
const bytes = new Uint8Array(normal.length / 2);
for (let index = 0; index < bytes.length; ++index)
{
const c1 = normal.charCodeAt(index * 2);
const c2 = normal.charCodeAt(index * 2 + 1);
const n1 = c1 - (c1 < 58 ? 48 : 87);
const n2 = c2 - (c2 < 58 ? 48 : 87);
bytes[index] = n1 * 16 + n2;
}
return bytes;
}
//JWK K Value
const generateKey = async () =>
{
const key = await window.crypto.subtle.generateKey(
{
name: "AES-GCM",
length: 128
}, true, ["encrypt", "decrypt"]);
const key_exported = await window.crypto.subtle.exportKey("jwk", key);
return key_exported.k;
}
//CryptoKey generated from SubtleCrypto:
const generateSubtleCryptoKey = async (kvalue) =>
{
return window.crypto.subtle.importKey(
"jwk",
{
k: kvalue,
alg: "A128GCM",
ext: true,
key_ops: ["encrypt", "decrypt"],
kty: "oct",
},
{
name: "AES-GCM",
length: 128
},
false,
["encrypt", "decrypt"]
);
}
//Cipher generated from SJCL:
const generateCipherSJCL = (kkey) =>
{
const ekkeyB64 = kkey.replace(/-/g, '+').replace(/_/g, '/'); // Base64url -> Base64 (ignore optional padding)
const ebkey = sjcl.codec.base64.toBits(ekkeyB64); // conert to bitArray
const ecipher = new sjcl.cipher.aes(ebkey);
return ecipher;
}
const encryptText = "STATIC TEXT";
const compareBuffers = async () =>
{
const kkey = await generateKey();
const cryptokey = await generateSubtleCryptoKey(kkey)
const ecipher = generateCipherSJCL(kkey);
const subtleCrypto = await window.crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: new Uint8Array(12)
}, cryptokey, new TextEncoder().encode(JSON.stringify(encryptText)));
const encryptionIv = sjcl.codec.hex.toBits(buf2hex(new Uint8Array(12).buffer));
const encryptedMessageFormat = sjcl.codec.hex.toBits(string2hex(JSON.stringify(encryptText)));
const sjclEncrypted = sjcl.mode.gcm.encrypt(ecipher, encryptedMessageFormat, encryptionIv);
const originalEncryptedSJCL = Buffer.from(sjclEncrypted);
console.log({subtleCrypto});
console.log({originalEncryptedSJCL});
const e1 = Buffer.from(new Uint8Array(sjclEncrypted));
const e2 = Buffer.from(new Uint8Array(subtleCrypto));
console.log({e1, e2}); //{e1: Uint8Array(11), e2: Uint8Array(29)}
console.log(Buffer.compare(e1, e2)); //should be 0, equal buffer.
}
compareBuffers();
I suppose I should preface this by stating that I have very limited cryptography knowledge, but why would the buffers differ when they're both encrypted and decrypted across both libraries when the mechanism is same?

How to encrypt AES in C# with CryptoJS [duplicate]

I'm triying to Encrypt string with C# and decrypt it using Angular crypto-js library but it's giving me different output.
I tried different c# aes encryption implementations but crypto-js library can't decrypt the encrypted data in c#. Thank you for any help.
Here is my code
Program.cs
static void Main()
{
var r = EncryptString("exampleString", "examplePassword");
Console.Write(r);
}
public static string EncryptString(string plainText, string passPhrase)
{
if (string.IsNullOrEmpty(plainText))
{
return "";
}
// generate salt
byte[] key, iv;
var salt = new byte[8];
var rng = new RNGCryptoServiceProvider();
rng.GetNonZeroBytes(salt);
DeriveKeyAndIv(passPhrase, salt, out key, out iv);
// encrypt bytes
var encryptedBytes = EncryptStringToBytesAes(plainText, key, iv);
// add salt as first 8 bytes
var encryptedBytesWithSalt = new byte[salt.Length + encryptedBytes.Length + 8];
Buffer.BlockCopy(Encoding.ASCII.GetBytes("Salted__"), 0, encryptedBytesWithSalt, 0, 8);
Buffer.BlockCopy(salt, 0, encryptedBytesWithSalt, 8, salt.Length);
Buffer.BlockCopy(encryptedBytes, 0, encryptedBytesWithSalt, salt.Length + 8, encryptedBytes.Length);
// base64 encode
return Convert.ToBase64String(encryptedBytesWithSalt);
}
private static void DeriveKeyAndIv(string passPhrase, byte[] salt, out byte[] key, out byte[] iv)
{
// generate key and iv
var concatenatedHashes = new List<byte>(48);
var password = Encoding.UTF8.GetBytes(passPhrase);
var currentHash = new byte[0];
var md5 = MD5.Create();
bool enoughBytesForKey = false;
// See http://www.openssl.org/docs/crypto/EVP_BytesToKey.html#KEY_DERIVATION_ALGORITHM
while (!enoughBytesForKey)
{
var preHashLength = currentHash.Length + password.Length + salt.Length;
var preHash = new byte[preHashLength];
Buffer.BlockCopy(currentHash, 0, preHash, 0, currentHash.Length);
Buffer.BlockCopy(password, 0, preHash, currentHash.Length, password.Length);
Buffer.BlockCopy(salt, 0, preHash, currentHash.Length + password.Length, salt.Length);
currentHash = md5.ComputeHash(preHash);
concatenatedHashes.AddRange(currentHash);
if (concatenatedHashes.Count >= 48)
enoughBytesForKey = true;
}
key = new byte[32];
iv = new byte[16];
concatenatedHashes.CopyTo(0, key, 0, 32);
concatenatedHashes.CopyTo(32, iv, 0, 16);
md5.Clear();
}
static byte[] EncryptStringToBytesAes(string plainText, byte[] key, byte[] iv)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (key == null || key.Length <= 0)
throw new ArgumentNullException("key");
if (iv == null || iv.Length <= 0)
throw new ArgumentNullException("iv");
// Declare the stream used to encrypt to an in memory
// array of bytes.
MemoryStream msEncrypt;
// Declare the RijndaelManaged object
// used to encrypt the data.
RijndaelManaged aesAlg = null;
try
{
// Create a RijndaelManaged object
// with the specified key and IV.
aesAlg = new RijndaelManaged { Mode = CipherMode.CBC, KeySize = 256, BlockSize = 128, Key = key, IV = iv };
// Create an encryptor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption.
msEncrypt = new MemoryStream();
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (var swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
swEncrypt.Flush();
swEncrypt.Close();
}
}
}
finally
{
// Clear the RijndaelManaged object.
aesAlg?.Clear();
}
// Return the encrypted bytes from the memory stream.
return msEncrypt.ToArray();
}
Simply decrypting it using crypto-js
let CryptoJS = require('crypto-js');
let r = CryptoJS.AES.decrypt('exampleString', 'examplePassword').toString();
The example code is attempting to decrypt the original unencrypted string, which looks to be a mistake perhaps created when trying to simplify the example code for posting the question? Either way the steps required are not too difficult, but the toString() call needs to be replaced.
var data = "U2FsdGVkX1/Zvh/5BnLfUgfbg5ROSD7Aohumr9asPM8="; // Output from C#
let r2 = CryptoJS.enc.Utf8.stringify(CryptoJS.AES.decrypt(data, 'examplePassword'));
console.log(r2);

Replication of HMACSHA256 in c# as that of jsSHA

so i am trying to get this hash 69F6617707D9442940C39BEBFA0B4459CEBF6CD5E610EA1FF44B341E291654A9 which can me made on https://caligatio.github.io/jsSHA/.
The key is K = E74A540FA07C4DB1B46421126DF7AD36 , Message is T= 537707AD486F07AD75CCF7B1F7FEA6F75871FCF6DC755923C8EE7C375C21EAC51BD97C51C69F395B and the generated hash via my code is SHA256 (T) = 6a2783d8eb0237e015f7dcd27fb2d2a85dd637220433dffcdc31198670f6ecac
This is incorrect Hash.
This is my code can someone explain what is wrong here thanks.
static void Main(string[] args)
{
var key = "E74A540FA07C4DB1B46421126DF7AD36";
string message = "537707AD486F07AD75CCF7B1F7FEA6F75871FCF6DC755923C8EE7C375C21EAC51BD97C51C69F395B";
var encodingCred = new System.Text.ASCIIEncoding();
var encodingKey = new System.Text.ASCIIEncoding();
byte[] keyByte = StringToByteArray(key);
byte[] credentialsBytes = encodingCred.GetBytes(message);
using (var hmacsha256 = new HMACSHA256(keyByte))
{
byte[] hashmessage = hmacsha256.ComputeHash(credentialsBytes);
string hash = BitConverter.ToString(hashmessage).Replace("-", string.Empty).ToLower();
Console.WriteLine("HASH: " + hash);
}
Console.ReadKey();
}
public static byte[] StringToByteArray(String hex)
{
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
return bytes;
}
In C this is valid
void test_keyed_hmac()
{
hmac_sha256 hmac;
sha256 sha;
uint8_t sha_digest[32] = { 0 };
unsigned char key[] = "\xE7\x4A\x54\x0F\xA0\x7C\x4D\xB1\xB4\x64\x21\x12\x6D\xF7\xAD\x36";
//unsigned char key[] = "E74A540FA07C4DB1B46421126DF7AD36";
unsigned char data[] = "\x53\x77\x07\xAD\x48\x6F\x07\xAD\x75\xCC\xF7\xB1\xF7\xFE\xA6\xF7\x58\x71\xFC\xF6\xDC\x75\x59\x23\xC8\xEE\x7C\x37\x5C\x21\xEA\xC5\x1B\xD9\x7C\x51\xC6\x9F\x39\x5B";
//unsigned char data[] = "537707AD486F07AD75CCF7B1F7FEA6F75871FCF6DC755923C8EE7C375C21EAC51BD97C51C69F395B";
printf("Data length %d \n", strlen(data));
hmac_sha256_initialize(&hmac, key, strlen(key));
// Finalize the HMAC-SHA256 digest and output its value.
hmac_sha256_finalize(&hmac, data, strlen(data));
for (int i = 0; i < 32; ++i) {
// Cast added by RKW to get format specifier to work as expected
printf("%x", (unsigned long)hmac.digest[i]);
}
putchar('\n');
}
I need something like this in c# that gives the valid hash mentioned above in second line

Equivalent version of SHA256 ComputeHash (from C#) for React Native/JS

I'm trying to build an equivalent version of SHA256 ComputeHash (from C#, the EXACT same output from the below sample), to React Native/JavaScript.
This is the following C#:
public static string Hash(string input)
{
if (string.IsNullOrWhiteSpace(input)) return "";
using (SHA256 hasher = SHA256.Create())
{
// Convert the input string to a byte array and compute the hash.
byte[] data = hasher.ComputeHash(Encoding.Unicode.GetBytes(input));
// Create a new Stringbuilder to collect the bytes
// and create a string.
StringBuilder sBuilder = new StringBuilder();
// Loop through each byte of the hashed data
// and format each one as a hexadecimal string.
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("X2"));
}
// Return the hexadecimal string.
return $"0x{sBuilder.ToString().ToLower()}";
}
}
I tried the following, but it doesn't generate the same Hash:
import * as Crypto from 'expo-crypto';
const hash = await Crypto.digestStringAsync(
Crypto.CryptoDigestAlgorithm.SHA256,
"StringIWantToHash"
);
Would anyone know, either what's wrong with the JavaScript, or if there is an exact equivalent version of the C# one?
Expo React Native:
Solution 1:
install sha256 by
yarn add sha256
import React, { Component } from "react";
import { Text, StyleSheet, View } from "react-native";
const sha256 = require("sha256");
const isNullOrWhitespace = (input) => {
if (typeof input === "undefined" || input == null) return true;
return input.replace(/\s/g, "").length < 1;
};
const getByteArray = (input) => {
let bytes = [];
for (var i = 0, k = 0; i < input.length; i++, k += 2) {
bytes[k] = input.charCodeAt(i);
bytes[k + 1] = 0;
}
return bytes;
};
const hash = async (input) => {
if (isNullOrWhitespace(input)) {
return "";
}
var bytes = getByteArray(input);
const hashString = "0x" + sha256(bytes, { asBytes: false });
return hashString;
};
export default class App extends Component {
state = {
encodedString: "",
};
async UNSAFE_componentWillMount() {
const encodedString = await hash("test2"); //0x39a2272982dc7e6e5d109ab36ec280f6cd3b4b7440af5c739ed808d4ec02aae4
this.setState({ encodedString: encodedString });
}
render() {
const { encodedString } = this.state;
return (
<View style={styles.container}>
<Text>{encodedString}</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
});
Solution 2:
you are using ToString("X2") in c# which means you have to convert hash to HEX (base 16)
here id demo: https://snack.expo.io/#nomi9995/expo-crypto
you need to convert hash to HEX (base 16) like this
await hash.toString(16);
try this it will give the same result as c#
Code :
import React, { Component } from "react";
import { Text, StyleSheet, View } from "react-native";
import * as Crypto from "expo-crypto";
const isNullOrWhitespace = (input) => {
if (typeof input === "undefined" || input == null) return true;
return input.replace(/\s/g, "").length < 1;
};
const hash = async (input) => {
if (isNullOrWhitespace(input)) {
return "";
}
let hash = await Crypto.digestStringAsync(
Crypto.CryptoDigestAlgorithm.SHA256,
input
);
const sBuilder = await hash.toString(16);
return `0x${sBuilder.toLowerCase()}`;
};
export default class App extends Component {
state = {
encodedString: "",
};
async UNSAFE_componentWillMount() {
const result = await hash("StringIWantToHash"); //here you can pass your string
this.setState({ encodedString: result });
}
render() {
const { encodedString } = this.state;
return (
<View style={styles.container}>
<Text>{encodedString}</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
});
Node js:
install crypto-js by
yarn add crypto-js
try this it will give the same result as c#
var CryptoJS = require("crypto-js");
const isNullOrWhitespace = (input) => {
if (typeof input === "undefined" || input == null) return true;
return input.replace(/\s/g, "").length < 1;
};
const hash = (input) => {
if (isNullOrWhitespace(input)) {
return "";
}
let hash = CryptoJS.SHA256(input);
const sBuilder=hash.toString(CryptoJS.enc.Hex);
return `0x${sBuilder.toLowerCase()}`;
};
const result=hash("StringIWantToHash");
console.log(result,"result"); // it will give the same result as C#
Solution 1: Use UTF8 instead of Unicode
Well, this is an Encoding problem.
Encoding.Unicode is Microsoft's misleading name for UTF-16 (a double-wide encoding, used in the Windows world for historical reasons but not used by anyone else). http://msdn.microsoft.com/en-us/library/system.text.encoding.unicode.aspx (see this answer)
You should be using Encoding.UTF8.GetBytes instead.
Using js-sha256 library like this:
const jssha = require('js-sha256')
function hash(input)
{
const hashString = "0x" + jssha.sha256(input)
return hashString;
}
const hashResult = hash("StringIWantToHash")
// Output: 0x29c506d0d69a16e413d63921b7de79525c43715931d8d93127dbeb46eacda2f9
We can achieve pretty similar in C# just using UTF8 encoding:
public static string Hash(string input)
{
if (string.IsNullOrWhiteSpace(input)) return "";
using (SHA256 hasher = SHA256.Create())
{
// Convert the input string to a byte array and compute the hash.
byte[] data = hasher.ComputeHash(Encoding.UTF8.GetBytes(input)); // Note that UTF8 here
// Create a new Stringbuilder to collect the bytes
// and create a string.
StringBuilder sBuilder = new StringBuilder();
// Loop through each byte of the hashed data
// and format each one as a hexadecimal string.
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("X2"));
}
// Return the hexadecimal string.
return $"0x{sBuilder.ToString().ToLower()}";
}
}
static void Main()
{
var hashResult = Hash("StringIWantToHash");
// Output: 0x29c506d0d69a16e413d63921b7de79525c43715931d8d93127dbeb46eacda2f9
}
Also, I believe that other JS/React Native libraries that help to compute SHA256 hash use UTF8 encoding too, so I think you can use any other crypto libraries for that.
Solution 2: What if you need to use Unicode?
In that case, you need to manually represent C# encoding in JS code.
While you are using Unicode encoding, after every single byte in the string goes '0' byte if it is a plain Latin character. For other symbols (with more than 255 number) Unicode required 2 bytes for that.
var input = "StringIWantToHash";
var encodedInput = Encoding.Unicode.GetBytes(input);
// Output: [83, 0, 116, 0, 114, 0, 105, 0, 110, 0, ...]
So we need to represent that in our JS code:
const jssha = require('js-sha256')
function hash(input)
{
var bytes = [];
for (var i = 0; i < input.length; i++)
{
const code = input.charCodeAt(i);
bytes = bytes.concat([code & 0xff, code / 256 >>> 0]);
}
const hashString = "0x" + jssha.sha256(bytes)
return hashString;
}
const hashResult = hash("StringIWantToHash")
// Output: 0x029dbc4b54b39bed6d684175b2d76cc5622c60fe91f0bde9865b977d0d9a531d
after two days of research it works perfectly! Two different codes give the same result.
js
const sha1 = require('sha1');
const getHash = str =>{
const hashingBytes = Buffer.from(sha1(str), "hex");
const base64Value = Buffer.from(hashingBytes).toString('base64');
return base64Value;
}
c#
System.Security.Cryptography.SHA1 sha = new System.Security.Cryptography.SHA1CryptoServiceProvider();
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(str);
byte[] hashingbytes = sha.ComputeHash(bytes);
var hash = Convert.ToBase64String(hashingbytes);

Try to convert HashPassword c# (Microsoft example) to javascript

I would like to convert byte.Parse in c# to javascript .. but i am not sure how.
byte[] binarySaltValue = new byte[SaltValueSize];
binarySaltValue[0] = byte.Parse(saltValue.Substring(0, 2), System.Globalization.NumberStyles.HexNumber, CultureInfo.InvariantCulture.NumberFormat);
I need to get the ascII code of the substring(0,2) ... did i am right ?
EDIT QUESTION
The real think i try to do is to convert into Javascript the HashPassword method from Microsoft.
private static string HashPassword(string clearData, string saltValue, HashAlgorithm hash)
{
UnicodeEncoding encoding = new UnicodeEncoding();
if (clearData != null && hash != null && encoding != null)
{
// If the salt string is null or the length is invalid then
// create a new valid salt value.
// Convert the salt string and the password string to a single
// array of bytes. Note that the password string is Unicode and
// therefore may or may not have a zero in every other byte.
byte[] binarySaltValue = new byte[SaltValueSize];
binarySaltValue[0] = byte.Parse(saltValue.Substring(0, 2), System.Globalization.NumberStyles.HexNumber, CultureInfo.InvariantCulture.NumberFormat);
binarySaltValue[1] = byte.Parse(saltValue.Substring(2, 2), System.Globalization.NumberStyles.HexNumber, CultureInfo.InvariantCulture.NumberFormat);
binarySaltValue[2] = byte.Parse(saltValue.Substring(4, 2), System.Globalization.NumberStyles.HexNumber, CultureInfo.InvariantCulture.NumberFormat);
binarySaltValue[3] = byte.Parse(saltValue.Substring(6, 2), System.Globalization.NumberStyles.HexNumber, CultureInfo.InvariantCulture.NumberFormat);
byte[] valueToHash = new byte[SaltValueSize + encoding.GetByteCount(clearData)];
byte[] binaryPassword = encoding.GetBytes(clearData);
// Copy the salt value and the password to the hash buffer.
binarySaltValue.CopyTo(valueToHash, 0);
binaryPassword.CopyTo(valueToHash, SaltValueSize);
byte[] hashValue = hash.ComputeHash(valueToHash);
// The hashed password is the salt plus the hash value (as a string).
string hashedPassword = saltValue;
foreach (byte hexdigit in hashValue)
{
hashedPassword += hexdigit.ToString("X2", CultureInfo.InvariantCulture.NumberFormat);
}
// Return the hashed password as a string.
return hashedPassword;
}
return null;
}
Ok so there is my solution, maybe it's not optimized but working fine!
function Salt(plainText, salt) {
if (plainText != undefined && plainText != "" && salt != null) {
// If the salt string is null or the length is invalid then
// create a new valid salt value.
// Convert the salt string and the password string to a single
// array of bytes. Note that the password string is Unicode and
// therefore may or may not have a zero in every other byte.
var binarySaltValue = new Array();
binarySaltValue[0] = parseInt(salt.substring(0, 2), 16);
binarySaltValue[1] = parseInt(salt.substring(2, 4), 16);
binarySaltValue[2] = parseInt(salt.substring(4, 6), 16);
binarySaltValue[3] = parseInt(salt.substring(6, 8), 16);
var binaryPassword = cryptoHelper.stringToBytes(plainText);
var valueToHash = new Array();
// Copy the salt value and the password to the hash buffer.
// binarySaltValue.concat(valueToHash);
// binarySaltValue.CopyTo(valueToHash, 0);
// binaryPassword.CopyTo(valueToHash, SaltValueSize);
valueToHash = valueToHash.concat(binarySaltValue);
// Détermine la longeur utilisé par le array - 2048
var newLengthArray = 2048 - valueToHash.length;
var tampon = new Array(newLengthArray);
for (var i = 0; i < tampon.length; i++) {
tampon[i] = 0;
}
valueToHash = valueToHash.concat(tampon);
valueToHash = valueToHash.concat(binaryPassword);
var hashValue = CryptoJS.MD5(CryptoJS.lib.Base.ByteArray(valueToHash));
var arr = wordArrayToByteArray(hashValue);
var hashedPassword = salt;
for (var i = 0; i < arr.length; i++) {
hexdigit = arr[i];
var hexValue = hexdigit.toString(16);
if (hexValue.length < 2) hexValue = "0" + hexValue;
hashedPassword += hexValue;
}
return hashedPassword;
}
return null;
}

Categories