Skip to content

Instantly share code, notes, and snippets.

@SuaYoo
Last active November 22, 2021 16:15
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SuaYoo/07638d095852f0ce7777cb74ccee9c7b to your computer and use it in GitHub Desktop.
Save SuaYoo/07638d095852f0ce7777cb74ccee9c7b to your computer and use it in GitHub Desktop.
Encrypt and decrypt JSON files for Web3 Storage (requires Node.js >=15.7)
// node >=15.7.0 required for Blob usage
const { Blob } = require('buffer');
const crypto = require('crypto');
const { Web3Storage } = require('web3.storage');
// Secret env variables
//
// Grab token from https://web3.storage/tokens/
const WEB3_STORAGE_API_KEY = 'my_api_key';
// Encryption secret must have exact length of 32
// You'll want to save the output of
// `crypto.randomBytes(16).toString('hex')`
// somewhere instead of re-generating it each time
// so that you can decrypt your files later.
const ENCRYPTION_SECRET = crypto.randomBytes(16).toString('hex');
// Make storage client
const storageClient = new Web3Storage({
token: WEB3_STORAGE_API_KEY,
});
// Encryption options
// Encrypt/decrypt functions based on
// https://attacomsian.com/blog/nodejs-encrypt-decrypt-data
const algorithm = 'aes-256-ctr';
// Encrypt some data
// Example:
// encrypt(JSON.stringify({ a: 'b' }))
function encrypt(text/*: string*/) {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv(algorithm, ENCRYPTION_SECRET, iv);
const encrypted = Buffer.concat([cipher.update(text), cipher.final()]);
return {
iv: iv.toString('hex'),
content: encrypted.toString('hex'),
};
}
// Decrypt file blob (NOTE only works with node >=15.7.0)
// Example:
// decrypt(await web3Response.files()[0])
async function decrypt(file/*: Blob*/) {
const hash = JSON.parse(await file.text());
const decipher = crypto.createDecipheriv(
algorithm,
ENCRYPTION_SECRET,
Buffer.from(hash.iv, 'hex')
);
const decrypted = Buffer.concat([
decipher.update(Buffer.from(hash.content, 'hex')),
decipher.final(),
]);
return decrypted.toString();
}
// Store object in Web3 Storage as an encrypted JSON file
async function storeEncryptedData(data, fileName) {
const encrypted = encrypt(JSON.stringify(data));
const file = new Blob([JSON.stringify(encrypted)], {
type: 'application/json',
});
file.name = `${fileName}.json.enc`;
const cid = await storageClient.put([file]);
console.log('stored files with cid:', cid);
return cid;
}
// Retrieve encrypted JSON file from Web3 Storage and decrypt
async function retrieveDecryptedData(cid) {
const res = await storageClient.get(cid);
console.log(`Got a response! [${res.status}] ${res.statusText}`);
if (!res.ok) {
throw new Error(`failed to get ${cid} - [${res.status}] ${res.statusText}`);
}
// unpack File objects from the response
const files = await res.files();
return Promise.all(files.map(decrypt));
}
async function demo() {
// Store some data
const cid = await storeEncryptedData({ text: 'secret text' }, 'test_file');
// Retrieve same data
const jsonArr = await retrieveDecryptedData(cid);
console.log('decrypted results:', jsonArr);
}
// Demo:
demo();
@coding-island-js
Copy link

Awesome. thanks for the code! I did something similar to what you wrote above, but instead did a new File instead of Blob and it works. Again thanks for taking the time to reply back and provide a solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment