0

Hello Everyone!

I am new in React, and I want to make an application like GalleryVault, LOCKit, WeVault, or any other application that has the function of encrypting files, but I want to build it in React Native, every application as I mentioned earlier has a different way of encrypting files, but for my application here I will describe my own method of encrypting files and some of the problems I encountered when using my own method.

Core Tools

  • In here I run the application on a real device Xiaomi Redmi 1S only 1GB RAM (a potato device)
  • React v16.13.1
  • React Native v0.63.3
  • rn-fetch-blob v0.12.0
  • buffer v6.0.3

Case 1

I don't want to save the base64 code to a new file as plain text for size reasons But, I guess it's fine to read it in base64 code

Case 2

Actually, my encryption method is very simple here:

First, I just read the file I wanted to encrypt in base64 code then changed it into a buffer,

Second, I randomly took the data from the buffer, and I saved the rest of the buffer into a file,

Third, the file will be visible encrypted when in fact I only took the buffer data from the file

Finally, the application file would not be able to be opened by the default gallery if it was an Image or video player if it was a video

The problem in this case, is that I have to change the base64 code into the buffer first and the conversion process is very slow, different when I save it directly in the base64 code without converting it to the buffer first.

Maybe you guys asking

Why should you need converting base64 code into a Buffer when you can save it as base64 code directly

The answer is

Because the base64 code data cannot be changed, it's different from the buffer where I can change, add, even delete it and then save it back into a file without any errors, but it's different from the base64 code when I change it this will cause an error bad-base64 from rn-fetch-blob, and this is my issue which has not found a solution for 2 days.

Code Sample

encryptFile.js

import RNFetchBlob from 'rn-fetch-blob';
import {Buffer} from 'buffer';
import _ from 'lodash';

const fs = RNFetchBlob.fs;

const encryptFile = async (uri = '') => {
  try {
    const fileUri = uri.replace('file://', '');
    const stream = await fs.readStream(fileUri, 'base64', 5120, 5);
    let dataChunk = [];

    stream.open();

    stream.onData(chunk => {
      const bufferChunk = Buffer.from(chunk, 'base64').toJSON().data;
      dataChunk.push(...bufferChunk);
    });

    stream.onError(err => {
      console.log(err);
      console.error('Error while read stream');
    });

    stream.onEnd(async () => {
      try {
        /**
         * My simple encryption algorithm
         * I just take the first and the last binary from the Buffer data
         *
         * It's only worked for small file size but won't work with a big file (out of memory)
         * like 10MB++, but I need it to work with large file size like 100MB, 300MB, 1GB+
         * if this is possible
         */
        const pattern = _.pullAt(dataChunk, [0, dataChunk.length - 1]);
        const encFile = Buffer.from(dataChunk, 'ascii').toString('base64');

        const saveLocation = `${fs.dirs.SDCardDir}/AppFolder/.src/someFileName`;
        await fs.writeFile(saveLocation, encFile, 'base64');

        console.warn('Encrypting is done :)');
      } catch (error) {
        console.log(error);
        console.error('Error while encrypting');
      }
    });
  } catch (error) {
    console.log(error);
    console.error('Error start read stream');
  }
};

export default encryptFile;

decryptFile.js

import RNFetchBlob from 'rn-fetch-blob';
import {Buffer} from 'buffer';

const fs = RNFetchBlob.fs;

const decryptFile = async (uri = '') => {
  try {
    const fileUri = uri.replace('file://', '');
    const stream = await fs.readStream(fileUri, 'base64', 5120, 5);
    let dataChunk = [];

    stream.open();

    stream.onData(chunk => {
      const binaryChunk = Buffer.from(chunk, 'base64').toJSON().data;
      dataChunk.push(...binaryChunk);
    });

    stream.onError(err => {
      console.log(err);
      console.error('Error while read stream');
    });

    stream.onEnd(async () => {
      try {
        /**
        * Example:
        *
        * Combine the binary that I have taken from the buffer
        * so the file can be opened again normally
        * 
        * But, it won't work with big file :( (out of memory)
        */
        const combine = [137, ...dataChunk, 130];
        const decFile = Buffer.from(combine, 'ascii').toString('base64');

        console.warn('Decrypting is done :)');
      } catch (error) {
        console.log(error);
        console.error('Error while decrypting');
      }
    });
  } catch (error) {
    console.log(error);
    console.error('Error start read stream');
  }
};

export default decryptFile;

Expected Results

Can encrypt and decrypt large files faster and avoiding memory leak

Actual Results

Always got out of memory when encrypting or decrypting with 10MB++ file

Goals

Simple encryption but fast when decrypting, not important the encryption is safe or not, the most important thing is that the encrypted files cannot be opened by the gallery application if it's an image or a video player if it's a video. Any idea?

Firmansyah
  • 106
  • 12
  • 27
  • What is the purpose of base64 encoding your files ? – Ebbe M. Pedersen Dec 03 '20 at 00:01
  • @EbbeM.Pedersen Thx for the comment, for reading and write a file of course plus I can display an Image or Video with base64 and as far as I know, there's nothing encoding that can be displaying an image or video except base64 – Firmansyah Dec 03 '20 at 20:11
  • 1
    You are aware that base64 is not encrypting, right ? – Ebbe M. Pedersen Dec 04 '20 at 11:07
  • @EbbeM.Pedersen I do, I mean I don't wanna encrypting the entire file because of performance reasons, it's fake encrypting I just break the file by taking some random binary data and then I swap it back into base64 code, why? Because writing files in binary encoding is very slow – Firmansyah Dec 04 '20 at 20:23

0 Answers0