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?