How do I calculate an AWS S3 compatible SHA-256 hash from a Blob in Angular?

I am trying to upload an image from the client side (Angular app) using a presigned upload URL that is generated in the backend. When doing a PUT request to an Amazon S3 bucket using this presigned URL, a x-amz-content-sha256 signed header must be included with a valid SHA-256 value that is calculated from the image blob that will be uploaded using the presigned URL.

Currently I am calculating this SHA-256 hash using the following TypeScript code:

  private getSHA256ChecksumFromBlobAndCacheBoth(imageBlob: Blob): Promise<string> {
    return imageBlob.arrayBuffer()
      .then(arrayBuffer => crypto.subtle.digest("SHA-256", arrayBuffer))
      .then(arrayBuffer => { 
        let SHA256Checksum: string = this.convertSHA256ChecksumToHexString(arrayBuffer);
        return SHA256Checksum;
      });
  }
  
  private convertSHA256ChecksumToHexString(buffer: ArrayBuffer): string {
    return Array.from(new Uint8Array(buffer))
      .map((byte) => byte.toString(16).padStart(2, "0"))
      .join("");
  }

This produces a valid SHA-256 hash. Here’s an example of one: ce48c8f1eebbfdfd811d2e8fbb07d7a4fa9e0ab382934d2010b336e2a2b41730

Despite it being valid, it is still rejected by S3; it causes a signature mismatch error. When I remove the actual hash value and replace it with UNSIGNED-PAYLOAD the upload request is accepted.

So Amazon calculates the SHA-256 of the same blob differently than how it’s normally done.

How do I create an Amazon S3 compatible SHA-256 hash of an image blob in TypeScript/JavaScript?