react-nativeexpochecksumimagepickerbackblaze

How do I get the SHA1 checksum of an image react native


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+.


Solution

  • 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>
      );
    }