I'm trying to create SHA-1 hash on the client-side. I'm trying to do this with Web Crypto API but when I'm paring the output to what various online tools give me, the result is pletely different. I think the problem is in ArrayBuffer to Hex conversion. Here is my code:
function generateHash() {
var value = "mypassword";
var crypto = window.crypto;
var buffer = new ArrayBuffer(value);
var hash_bytes = crypto.subtle.digest("SHA-1", buffer);
hash_bytes.then(value => document.write([...new Uint8Array(value)].map(x => x.toString(16).padStart(2, '0')).join('')));
}
Output of document.write
should be:
91dfd9ddb4198affc5c194cd8ce6d338fde470e2
But it's not, I get a pletely different hash of different length (should be 40). Could I have some advise on the problem? Thanks.
I'm trying to create SHA-1 hash on the client-side. I'm trying to do this with Web Crypto API but when I'm paring the output to what various online tools give me, the result is pletely different. I think the problem is in ArrayBuffer to Hex conversion. Here is my code:
function generateHash() {
var value = "mypassword";
var crypto = window.crypto;
var buffer = new ArrayBuffer(value);
var hash_bytes = crypto.subtle.digest("SHA-1", buffer);
hash_bytes.then(value => document.write([...new Uint8Array(value)].map(x => x.toString(16).padStart(2, '0')).join('')));
}
Output of document.write
should be:
91dfd9ddb4198affc5c194cd8ce6d338fde470e2
But it's not, I get a pletely different hash of different length (should be 40). Could I have some advise on the problem? Thanks.
Share Improve this question asked Jun 26, 2021 at 10:41 Mr. EngineerMr. Engineer 3752 gold badges11 silver badges34 bronze badges 1- Any advise guys? – Mr. Engineer Commented Jun 26, 2021 at 11:11
3 Answers
Reset to default 6This is a basic function to generate a SHA-1 hex string digest for any input string:
async function digest(message, algo = 'SHA-1') {
return Array.from(
new Uint8Array(
await crypto.subtle.digest(algo, new TextEncoder().encode(message))
),
(byte) => byte.toString(16).padStart(2, '0')
).join('');
}
The problem seems to be more the input conversion from a string to an ArrayBuffer
. E.g. with str2ab()
the code works:
generateHash();
function generateHash() {
var value = "mypassword";
var crypto = window.crypto;
var buffer = str2ab(value); // Fix
var hash_bytes = crypto.subtle.digest("SHA-1", buffer);
hash_bytes.then(value => document.write([...new Uint8Array(value)].map(x => x.toString(16).padStart(2, '0')).join('')));
}
// https://stackoverflow./a/11058858
function str2ab(str) {
const buf = new ArrayBuffer(str.length);
const bufView = new Uint8Array(buf);
for (let i = 0, strLen = str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
with the expected output:
91dfd9ddb4198affc5c194cd8ce6d338fde470e2
Using the debugger, it looks like var buffer = new ArrayBuffer(value);
results in buffer
being an empty ArrayBuffer. The text string stored in value
must be utf-8 encoded in order to be correctly converted to bytes, which can then by passed as an input to the crypto.subtle.digest()
function.
Try changing:
var buffer = new ArrayBuffer(value);
to:
var buffer = new TextEncoder("utf-8").encode(value);
This creates a Uint8Array (as expected by crypto.subtle.digest()
) consisting of the bytes resulting from utf-8 encoding the text string in 'value'. This should solve the problem and produce the result that you are expecting.