Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update IPFS codec registration example #20

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 6 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,16 +105,15 @@ const payloadBlock = await Block.create({ bytes: payloadBytes, cid: payloadCid,

## JWE Encryption Usage

When using DAG-JOSE (for JWE or JWS) with js-IPFS, you will need to convert it from a raw multiformats style codec to a legacy IPLD codec using [blockcodec-to-ipld-format](https://github.com/ipld/js-blockcodec-to-ipld-format).
When using DAG-JOSE (for JWE or JWS) with js-IPFS, you will need to register the codec when creating the IPFS instance. For versions of js-IPFS older than 0.41, it is also necessary to a convert it from a raw multiformats style codec to a legacy IPLD codec using [blockcodec-to-ipld-format](https://github.com/ipld/js-blockcodec-to-ipld-format).

_The following example is available in complete form in [example-ipfs.mjs](./example-ipfs.mjs)._
_The following example is available in complete form in [example-ipfs.mjs](./example-ipfs.mjs). An example of legacy IPLD codec registration at [example-ipfs-legacy.mjs](./example-ipfs-legacy.mjs)._

_A plain IPLD (without IPFS, for cases where you are managing the block store) version is available in [example-ipld.mjs](./example-ipld.mjs)._

```js
// IPLD & IPFS
import { create as createIpfs } from 'ipfs'
import { convert as toLegacyIpld } from 'blockcodec-to-ipld-format'

import * as dagJose from 'dag-jose'
```
Expand Down Expand Up @@ -144,13 +143,11 @@ import { generateKeyPairFromSeed } from '@stablelib/x25519'
Set up js-IPFS:

```js
const dagJoseIpldFormat = toLegacyIpld(dagJose)

// Async setup tasks
async function setup () {
console.log('Starting IPFS ...')
// Instantiate an IPFS node, that knows how to deal with DAG-JOSE blocks
ipfs = await createIpfs({ ipld: { formats: [dagJoseIpldFormat] } })
ipfs = await createIpfs({ ipld: { codecs: [dagJose] } })
}
```

Expand All @@ -166,7 +163,7 @@ const storeEncrypted = async (payload, key) => {
// encrypt into JWE container layout using secret key
const jwe = await createJWE(cleartext, [dirEncrypter])
// let IPFS store the bytes using the DAG-JOSE codec and return a CID
const cid = await ipfs.dag.put(jwe, { format: dagJoseIpldFormat.codec, hashAlg: 'sha2-256' })
const cid = await ipfs.dag.put(jwe, { format: 'dag-jose', hashAlg: 'sha2-256' })
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

best to use use dagJose.name since that's the internal matching that's going to happen in js-ipfs and the user can avoid one magic string

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const cid = await ipfs.dag.put(jwe, { format: 'dag-jose', hashAlg: 'sha2-256' })
const cid = await ipfs.dag.put(jwe, { format: dagJose.name, hashAlg: 'sha2-256' })

console.log(`Encrypted block CID: \u001b[32m${cid}\u001b[39m`)
return cid
}
Expand Down Expand Up @@ -206,7 +203,7 @@ const storeEncrypted = async (payload, pubkey) => {
// encrypt into JWE container layout using public key
const jwe = await createJWE(cleartext, [asymEncrypter])
// let IPFS store the bytes using the DAG-JOSE codec and return a CID
const cid = await ipfs.dag.put(jwe, { format: dagJoseIpldFormat.codec, hashAlg: 'sha2-256' })
const cid = await ipfs.dag.put(jwe, { format: 'dag-jose', hashAlg: 'sha2-256' })
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const cid = await ipfs.dag.put(jwe, { format: 'dag-jose', hashAlg: 'sha2-256' })
const cid = await ipfs.dag.put(jwe, { format: dagJose.name, hashAlg: 'sha2-256' })

console.log(`Encrypted block CID: \u001b[32m${cid}\u001b[39m`)
return cid
}
Expand Down Expand Up @@ -246,7 +243,7 @@ const cleartext = prepareCleartext({ my: 'secret message' })

// encrypt and put into ipfs
const jwe = jose.JWE.encrypt.flattened(cleartext, jwk, { alg: 'dir', enc: 'A128CBC-HS256' })
const cid = await ipfs.dag.put(jwe, { format: format.codec, hashAlg: 'sha2-256' })
const cid = await ipfs.dag.put(jwe, { format: 'dag-jose', hashAlg: 'sha2-256' })
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const cid = await ipfs.dag.put(jwe, { format: 'dag-jose', hashAlg: 'sha2-256' })
const cid = await ipfs.dag.put(jwe, { format: dagJose.name, hashAlg: 'sha2-256' })


// retreive and decrypt object
const retrived = await ipfs.dag.get(cid)
Expand Down
110 changes: 110 additions & 0 deletions example-ipfs-legacy.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { randomBytes } from '@stablelib/random'
import { generateKeyPairFromSeed } from '@stablelib/x25519'

// IPLD & IPFS
import { create as createIpfs } from 'ipfs'
import { convert as toLegacyIpld } from 'blockcodec-to-ipld-format'

// JWT & utilities
import {
xc20pDirEncrypter,
xc20pDirDecrypter,
x25519Encrypter,
x25519Decrypter,
decryptJWE,
createJWE
} from 'did-jwt'
import {
decodeCleartext,
prepareCleartext
} from 'dag-jose-utils'

import * as dagJose from './lib/index.js'

// Translate DAG-JOSE into the IPLD interface js-IPFS understands
const dagJoseIpldFormat = toLegacyIpld(dagJose)
let ipfs

// Async setup tasks
async function setup () {
console.log('Starting IPFS ...')
// Instantiate an IPFS node, that knows how to deal with DAG-JOSE blocks
ipfs = await createIpfs({ ipld: { formats: [dagJoseIpldFormat] } })
}

async function symmetric () {
// Encrypt and store a payload using a secret key
const storeEncrypted = async (payload, key) => {
const dirEncrypter = xc20pDirEncrypter(key)
// prepares a cleartext object to be encrypted in a JWE
const cleartext = await prepareCleartext(payload)
// encrypt into JWE container layout using secret key
const jwe = await createJWE(cleartext, [dirEncrypter])
// let IPFS store the bytes using the DAG-JOSE codec and return a CID
const cid = await ipfs.dag.put(jwe, { format: dagJoseIpldFormat.codec, hashAlg: 'sha2-256' })
console.log(`Encrypted block CID: \u001b[32m${cid}\u001b[39m`)
return cid
}

// Load an encrypted block from a CID and decrypt the payload using a secret key
const loadEncrypted = async (cid, key) => {
const dirDecrypter = xc20pDirDecrypter(key)
const retrieved = await ipfs.dag.get(cid)
const decryptedData = await decryptJWE(retrieved.value, dirDecrypter)
return decodeCleartext(decryptedData)
}

const key = randomBytes(32)
const secretz = { my: 'secret message' }
console.log('Encrypting and storing secret:\u001b[1m', secretz, '\u001b[22m')
const cid = await storeEncrypted(secretz, key)
const decoded = await loadEncrypted(cid, key)
console.log('Loaded and decrypted block content:\u001b[1m', decoded, '\u001b[22m')
}

// Asymmetric encryption using a private and public key
async function asymmetric () {
// Encrypt and store a payload using a public key
const storeEncrypted = async (payload, pubkey) => {
const asymEncrypter = x25519Encrypter(pubkey)
// prepares a cleartext object to be encrypted in a JWE
const cleartext = await prepareCleartext(payload)
// encrypt into JWE container layout using public key
const jwe = await createJWE(cleartext, [asymEncrypter])
// let IPFS store the bytes using the DAG-JOSE codec and return a CID
const cid = await ipfs.dag.put(jwe, { format: dagJoseIpldFormat.codec, hashAlg: 'sha2-256' })
console.log(`Encrypted block CID: \u001b[32m${cid}\u001b[39m`)
return cid
}

// Load an encrypted block from a CID and decrypt the payload using a secret key
const loadEncrypted = async (cid, privkey) => {
const asymDecrypter = x25519Decrypter(privkey)
// decode the DAG-JOSE envelope
const retrieved = await ipfs.dag.get(cid)
const decryptedData = await decryptJWE(retrieved.value, asymDecrypter)
return decodeCleartext(decryptedData)
}

const privkey = randomBytes(32)
// generate a public key from the existing private key
const pubkey = generateKeyPairFromSeed(privkey).publicKey
const secretz = { my: 'secret message' }
console.log('Encrypting and storing secret with public key:\u001b[1m', secretz, '\u001b[22m')
const cid = await storeEncrypted(secretz, pubkey)
const decoded = await loadEncrypted(cid, privkey)
console.log('Loaded and decrypted block content with private key:\u001b[1m', decoded, '\u001b[22m')
}

// Run!
setup().then(() => {
console.log('Running symmetric example...')
symmetric().then(async () => {
console.log('Running asymmetric example...')
await asymmetric()
process.exit(0)
})
}).catch((e) => {
console.error(e.stack)
process.exit(1)
})
9 changes: 3 additions & 6 deletions example-ipfs.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { generateKeyPairFromSeed } from '@stablelib/x25519'

// IPLD & IPFS
import { create as createIpfs } from 'ipfs'
import { convert as toLegacyIpld } from 'blockcodec-to-ipld-format'

// JWT & utilities
import {
Expand All @@ -21,15 +20,13 @@ import {

import * as dagJose from './lib/index.js'

// Translate DAG-JOSE into the IPLD interface js-IPFS understands
const dagJoseIpldFormat = toLegacyIpld(dagJose)
let ipfs

// Async setup tasks
async function setup () {
console.log('Starting IPFS ...')
// Instantiate an IPFS node, that knows how to deal with DAG-JOSE blocks
ipfs = await createIpfs({ ipld: { formats: [dagJoseIpldFormat] } })
ipfs = await createIpfs({ ipld: { codecs: [dagJose] } })
}

async function symmetric () {
Expand All @@ -41,7 +38,7 @@ async function symmetric () {
// encrypt into JWE container layout using secret key
const jwe = await createJWE(cleartext, [dirEncrypter])
// let IPFS store the bytes using the DAG-JOSE codec and return a CID
const cid = await ipfs.dag.put(jwe, { format: dagJoseIpldFormat.codec, hashAlg: 'sha2-256' })
const cid = await ipfs.dag.put(jwe, { format: 'dag-jose', hashAlg: 'sha2-256' })
console.log(`Encrypted block CID: \u001b[32m${cid}\u001b[39m`)
return cid
}
Expand Down Expand Up @@ -72,7 +69,7 @@ async function asymmetric () {
// encrypt into JWE container layout using public key
const jwe = await createJWE(cleartext, [asymEncrypter])
// let IPFS store the bytes using the DAG-JOSE codec and return a CID
const cid = await ipfs.dag.put(jwe, { format: dagJoseIpldFormat.codec, hashAlg: 'sha2-256' })
const cid = await ipfs.dag.put(jwe, { format: 'dag-jose', hashAlg: 'sha2-256' })
console.log(`Encrypted block CID: \u001b[32m${cid}\u001b[39m`)
return cid
}
Expand Down