简体   繁体   中英

Why does my implementation of crypto.sublte.digest result in equivalent hex hashes for equal length strings?

The following code was adapted from these two sources:

http://qnimate.com/hashing-using-web-cryptography-api/

https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest

(function () {
    "use strict";

    var crypto = window.crypto || window.msCrypto;

    if (typeof crypto.subtle === "undefined") {
        return;
    }

    function convertStringToArrayBuffer (str) {
        var strLength = str.length, buffer = new ArrayBuffer(strLength), i = 0;
        while (i < strLength) {
            buffer[i] = str.charCodeAt(i);
            i += 1;
        }
        return buffer;
    }

    function convertBufferToHex (buffer) {
        var data = new DataView(buffer), i = 0, 
            dataLength = data.byteLength, cData = null,
            hexValue = '';

        while (i < dataLength) {
            cData = data.getUint8(i).toString(16);
            if (cData.length < 2) {
                cData = '0' + cData;
            }

            hexValue += cData;
            i += 1;
        }
        return hexValue;
    }

    function digest (str) {
        var buf = convertStringToArrayBuffer(str);

        return crypto.subtle.digest("SHA-256", buf).then(function (hash) {
            return convertBufferToHex(hash);
        });
    }

    window.sha256 = {
        "convertStringToArrayBuffer": convertStringToArrayBuffer,
        "convertBufferToHex": convertBufferToHex,
        "digest": digest
    };
}());

Using sha256.digest("this string").then(function (x) { console.log(x) } ); and sha256.digest("that strong").then(function (x) { console.log(x) } ); produce the same hex string when run in a Chrome or Firefox console.

In fact any two strings with the same length will have the same hex representation.

Everything I've read says that having two equivalent hashes is rare. Which means I'm doing something wrong here. I have no idea what that something is.

Okay, I finally figured this out.

According to MDN https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer , you cannot directly assign values to an ArrayBuffer.

Instead you have to use something like Uint8Array, Uint16Array, DataView, etc. to assign values to an ArrayBuffer.

so I changed

function convertStringToArrayBuffer (str) {
    var strLength = str.length, buffer = new ArrayBuffer(strLength), i = 0;
    while (i < strLength) {
        buffer[i] = str.charCodeAt(i);
        i += 1;
    }
    return buffer;
}

to

function convertStringToArrayBuffer (str) {
    var strLength = str.length, buffer = new Uint8Array(strLength), i = 0;
    while (i < strLength) {
        buffer[i] = str.charCodeAt(i);
        i += 1;
    }
    return buffer;
}

and voila! :D

Equal length strings no longer have matching hashes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM