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?