Skip to content

Instantly share code, notes, and snippets.

@npfoss
Last active April 6, 2020 09:27
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save npfoss/663689d74a2318c13cb8754cef295e6a to your computer and use it in GitHub Desktop.
Save npfoss/663689d74a2318c13cb8754cef295e6a to your computer and use it in GitHub Desktop.
Example code for extracting JS-IPFS node keys for external encryption/decryption.

I spent a very long time trying to figure out how to encrypt something with an IPFS peer's ID so that only they can decrypt it (in JavaScript). This gist is to save anyone else from that same time-sink.

Encryption

Say you have an IPFS node as your peer, and their public key is this protobuf-encoded gibberish spit out by IPFS:

// for example from the command: node.id()
let publicKey = 'CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDC7gCqYWtRFmfQ8XZHnFnqB2sdPjprZgDOvz3Hl6NLGPpz95JVqguxQ9XDLnmPPFVOXEdMWohXOmWkQ4AF/6MDLz68q9/+xlvGRrwXE6gbhF15rBV+2A6LtCsbTNnzd7G+YmHMgBNk8UF4zB6Cg/6o2770fqp8khrTG1rwRXX2Cl0z/hEcIMFCAHEQpnmigP1gibtJi6cEjfjHQkqRF8ndCSNyUucgBkWPuJKEFWwAh5AJBVeEbWZngFGQ4jhp14RQ57cHv7COOQk8X3rSkJKMnyURm1iHK635TaJXpjaW8gD13imKUZHFCxS1JLIa3QTh8bk33+kK1jzkPN/XAC2BAgMBAAE='

You'll need the following imports:

let p2pcrypto = require("libp2p-crypto")
let NodeRSA = require("node-rsa")

First reformat:

let buf = Buffer.from(publicKey, 'base64')
publicKey = p2pcrypto.keys.unmarshalPublicKey(buf)

publicKey = {
	n: Buffer.from(publicKey._key.n, 'base64'),
	e: Buffer.from(publicKey._key.e, 'base64'),
}
let usefulPubKey = new NodeRSA()
usefulPubKey.importKey(publicKey, 'components-public')

Then encrypt:

let message = 'this is a test message'
let cipher = key.encrypt(message)

And what you end up with is the ciphertext as a Buffer.

Decryption

Getting an IPFS node's private key is not well documented. The only way I know is like so:

// Note: `node` is an ipfs node set up like so:
// const node = new IPFS();
let privateKey = node._peerInfo.id._privKey;

Make it useful (note: not a protobuf this time):

let usefulPrivKey = new NodeRSA();
usefulPrivKey.importKey({
    n: Buffer.from(privateKey._key.n, 'base64'),
    e: Buffer.from(privateKey._key.e, 'base64'),
    d: Buffer.from(privateKey._key.d, 'base64'),
    p: Buffer.from(privateKey._key.p, 'base64'),
    q: Buffer.from(privateKey._key.q, 'base64'),
    dmp1: Buffer.from(privateKey._key.dp, 'base64'),
    dmq1: Buffer.from(privateKey._key.dq, 'base64'),
    coeff: Buffer.from(privateKey._key.qi, 'base64'),
}, 'components');

Decrypt:

let messageBytes = usefulPrivKey.decrypt(cipher)
let m = messageBytes.toString()
console.log(m)

Profit:

/*** your code here ***/
@npfoss
Copy link
Author

npfoss commented Nov 11, 2019

I've been using js-ipns for that so I don't have an example for you, but I'm petty sure the keys used by IPFS have a sign function you can use. I think it's on the PeerId's key object but I don't remember exactly.

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