javascriptecmascript-6cryptographywebcrypto-api

How to create a hash using Web Crypto API?


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 comparing the output to what various online tools give me, the result is completely 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 completely different hash of different length (should be 40). Could I have some advise on the problem? Thanks.


Solution

  • 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.com/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