Last active
November 22, 2021 16:15
-
-
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)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.