sha256 hash of a base64 string in Javascript

This one took a surprising amount of time to figure out. We want a function that takes a string input that contains base64 encoded data, calculates the SHA-256 hash of that data, then returns that hash as a base64 encoded string.

Our existing implement relied on node's Buffer, which gets polyfilled by browserify. Buffer provides easy helper functions for jumping to and from base64 encoding:

const buffer = Buffer.from(base64String, 'base64')
const convertedString = buffer.toString('base64')
// convertedString === base64String

If we want to do this same conversion in the browser, without polyfilling Buffer, the code is a bit less pretty. These Stack Overflow answers point out how to convert to Arraybuffer and back.

Putting this together, the final code, which works both in the browser, and in node:

async function checksum(data) {
    // Convert base64 string into a Uint8Array
    const binaryString = atob(data)
    const buffer = new Uint8Array(binaryString.length)
    for (let i = 0; i < binaryString.length; i++) {
        buffer[i] = binaryString.charCodeAt(i)
    }
    // Calculate SHA-256 of the buffer
    const sha256Buffer = new Uint8Array(await crypto.subtle.digest('SHA-256', buffer))
    // Convert the buffer back into base64
    let binary = ''
    for (let i = 0; i < sha256Buffer.byteLength; i++) {
        binary += String.fromCharCode(sha256Buffer[i])
    }
    return btoa(binary)
}