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 ***/
@marcocastignoli
Copy link

marcocastignoli commented Nov 5, 2019

I'm trying to make it work encrypting with the private. Not working... Is it supposed to work?

@npfoss
Copy link
Author

npfoss commented Nov 9, 2019

I haven't tried, but I'm not sure when you'd ever want to encrypt with the private key, a signature is the standard way to prove you sent a message (given the public key)

@marcocastignoli
Copy link

marcocastignoli commented Nov 9, 2019 via email

@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