I have been at this for hours now. I need to get the SHA1 checksum of an image in Expo React Native. I am using the ImagePicker API to get the image and can see that I can get the MD5 hash of the image which I verified but they are not the same thing according to google
Whereas MD5 produces a 128-bit hash, SHA1 generates 160-bit hash (20 bytes).
I specifically need to get this. This is because I am trying to upload to Backblaze B2 through their API.
I was told this is a required field in order to check the file arrived correctly. I tried using the expo-crypto module but it only hashes strings.
Please is there any library or something I could use to do this?
Here's my trial:
Launch the image picker
let result = await ImagePicker.launchImageLibraryAsync({
allowsEditing: true,
aspect: [1.91, 1],
exif:true,
base64:true,
quality: 1,
});
Get the result. returns:
Object {
"cancelled": false,
"exif": Object {
"ImageLength": 1080,
"ImageWidth": 1080,
"LightSource": 0,
"Orientation": 0,
},
"height": 1080,
"type": "image",
"uri": "file:///data/user/0/com.blipmoore.blipmoore_cleaner/cache/ImagePicker/c8ac399d-ae12-40f6-95c6-994ddf99b5ed.jpg",
"width": 1080,
}
Note for the above. I had to remove the base64 because it was too long.
I then try to use buffer to change the format of the base64,
Buffer.from(result.base64, '')
But there is no SHA-1 format. I do not even know if this is the correct thing to do.
On this page in the documentation, they said:
You must always include the X-Bz-Content-Sha1 header with your upload request. The value you provide can be: (1) the 40-character hex checksum of the file, (2) the string hex_digits_at_end, or (3) the string do_not_verify.
I cannot opt for 3 for obvious reasons. Please what do I do? I can get a buffer hex value from my code but I cannot verify it's the right thing because on the docs it says, a 40-character hex checksum
and the hex value I get from the buffer is like a 1000+.
SHA-1 is a way of creating a fixed length 'digest' from variable-length input, such as an image you want to upload. Although SHA-1 is no longer considered secure in a cryptographic sense, it can still be used as a checksum that the data that a service such as Backblaze B2 received is the same as the data that you sent.
Looking at Expo's Crypto.digestStringAsync() function, you are correct - it only works with strings.
Fortunately, there are pure JavaScript implementations of SHA-1 out there - I was able to use Rusha to do the job. Here's my code; you can also try it out in this Snack.
package.json
{
"dependencies": {
"rusha": "~0.8.14",
"expo-image-picker": "~13.1.1",
"buffer": "~6.0.3"
}
}
App.js
import React, { useState, useEffect } from 'react';
import { Button, Image, View, Platform } from 'react-native';
import * as ImagePicker from 'expo-image-picker';
import { Buffer } from "buffer";
import Rusha from 'rusha';
export default function ImagePickerExample() {
const [image, setImage] = useState(null);
const pickImage = async () => {
// Get an image from the user's device
let result = await ImagePicker.launchImageLibraryAsync({
allowsEditing: true,
aspect: [1.91, 1],
exif:true,
base64:true,
quality: 1,
});
// Convert the image data from Base64 to binary
const binaryImage = Buffer.from(result.base64, "base64");
// Get the SHA-1 digest of the binary image data
const digest = Rusha.createHash().update(binaryImage).digest('hex');
console.log("SHA-1:", digest);
if (!result.cancelled) {
setImage(result.uri);
}
};
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button title="Pick an image from camera roll" onPress={pickImage} />
{image && <Image source={{ uri: image }} style={{ width: 200, height: 200 }} />}
</View>
);
}