I want to encrypt file before storing into IPFS network so that only person who is uploading a file should be able to decrypt.
1 Answer
You can use the public key to encrypt it so that only the private key can decrypt it.
I wrote this based on npmjs/eth-crypto, it takes the user's ethereum keypair. It's not super optimal but it will work. Ideally you'd want people to have a second key pair derived from the same seed but ECDH.
https://crypto.stackexchange.com/questions/12823/ecdsa-vs-ecies-vs-ecdh
- ECDSA is a digital signature algorithm
- ECIES is an Integrated Encryption scheme
- ECDH is a key secure key exchange algorithm
You could also have the user encrypt it on the client through AES.
import {publicKeyConvert} from 'secp256k1'
import {encrypt, decrypt} from 'eccrypto'
/**
* @method encryptMessage - Encrypted a signed message
* @param {Object} payload - Stringified JSON object containing the message and optional signature
* @param {Object} wallet - Wallet (public Key) to encrypt message with
* @returns {Object} - Object with encrypted values as hex
**/
const encryptMessage = async (payload, wallet) => {
return await encryptWithPublicKey(wallet.publicKey, payload)
}
/**
* @method decryptMessage - Decrypt an encrypted credential/message
* @param {Object} encryptedPayload - Object with the encrypted credentials
* @param {wallet} wallet - Wallet containing the privatekey associated with the publickey the message was encrypted with
* @returns {Object} - Object containing the decrypted values
**/
const decryptMessage = async (encryptedPayload, wallet) => await decryptWithPrivateKey(wallet.privateKey, encryptedPayload)
/**
* @method encryptWithPublicKey
* @param {String} pubKey - Compressed 33byte public key starting with 03 or 02
* @param {Object} message - message object to encrypt
* @returns {String} - Stringified cipher
*/
function encryptWithPublicKey(pubKey, message) {
pubKey = pubKey.substring(2)
pubKey = publicKeyConvert(new Buffer(pubKey, 'hex'), false).toString('hex')
pubKey = new Buffer(pubKey, 'hex')
return encrypt(
pubKey,
Buffer(message)
).then(encryptedBuffers => {
const cipher = {
iv: encryptedBuffers.iv.toString('hex'),
ephemPublicKey: encryptedBuffers.ephemPublicKey.toString('hex'),
ciphertext: encryptedBuffers.ciphertext.toString('hex'),
mac: encryptedBuffers.mac.toString('hex')
};
// use compressed key because it's smaller
const compressedKey = publicKeyConvert(new Buffer(cipher.ephemPublicKey, 'hex'), true).toString('hex')
const ret = Buffer.concat([
new Buffer(cipher.iv, 'hex'), // 16bit
new Buffer(compressedKey, 'hex'), // 33bit
new Buffer(cipher.mac, 'hex'), // 32bit
new Buffer(cipher.ciphertext, 'hex') // var bit
]).toString('hex')
return ret
});
}
/**
* @method decryptWithPrivateKey decript an EC publicKey encrypted message with the associated private key
* @param {String} privateKey - the privatekey to decrypt with, including '0x' prefix
* @param {String} encrypted - the stringified cipher to decrypt
* @returns {Object} - the decrypted message
*/
function decryptWithPrivateKey(privateKey, encrypted) {
const buf = new Buffer(encrypted, 'hex');
encrypted = {
iv: buf.toString('hex', 0, 16),
ephemPublicKey: buf.toString('hex', 16, 49),
mac: buf.toString('hex', 49, 81),
ciphertext: buf.toString('hex', 81, buf.length)
};
// decompress publicKey
encrypted.ephemPublicKey = publicKeyConvert(new Buffer(encrypted.ephemPublicKey, 'hex'), false).toString('hex')
const twoStripped = privateKey.substring(2)
const encryptedBuffer = {
iv: new Buffer(encrypted.iv, 'hex'),
ephemPublicKey: new Buffer(encrypted.ephemPublicKey, 'hex'),
ciphertext: new Buffer(encrypted.ciphertext, 'hex'),
mac: new Buffer(encrypted.mac, 'hex')
};
return decrypt(
new Buffer(twoStripped, 'hex'),
encryptedBuffer
).then(decryptedBuffer => decryptedBuffer.toString());
}