Skip to content

Instantly share code, notes, and snippets.

@AdamJLemmon
Created January 26, 2021 16:33
Show Gist options
  • Save AdamJLemmon/c2cafccd6180e2baf8b4ee16bc4e6df6 to your computer and use it in GitHub Desktop.
Save AdamJLemmon/c2cafccd6180e2baf8b4ee16bc4e6df6 to your computer and use it in GitHub Desktop.
/**
* Standards Referenced:
* JSON Web Encryption (JWE) https://tools.ietf.org/html/rfc7516
* JSON Object Signing and Encryption (JOSE) https://www.iana.org/assignments/jose/jose.xhtml
*/
const crypto = require('crypto')
const base64url = require('base64url')
// The location of the document within some third party service that will host these documents
const DOCUMENT_URL = 'https://example.com/docs/VRdqHY1xwB'
const DOCUMENT_ACCESS_TOKEN = 'd2925f29fcd7'
const JWE_ALG = 'A256KW'
const JWE_ENC = 'A256CBC-HS512'
const ENCRYPTION_ALGORITHM = 'aes-256-cbc'
const IV_LENGTH = 16
const KEY_LENGTH = 32
/**
*
* @param {Object} jwe JWE JSON Serialization https://tools.ietf.org/html/rfc7516#section-3.2
* @param {String} key The shared secret to
* @returns {Object}
* @param {String} plaintext
*/
const decrypt = ({ jwe, key }) => {
const ciphertextBuffer = Buffer.from(jwe.ciphertext, 'base64')
const keyBuffer = Buffer.from(key, 'base64')
const ivBuffer = Buffer.from(jwe.iv, 'base64')
// Note pull alg and enc from JWE header and interpret how to decrypt in practise
const decipher = crypto.createDecipheriv(ENCRYPTION_ALGORITHM, keyBuffer, ivBuffer)
const decrypted = decipher.update(ciphertextBuffer)
const decryptedBuffer = Buffer.concat([decrypted, decipher.final()])
const plaintext = decryptedBuffer.toString()
return { plaintext }
}
/**
*
* @param {String} plaintext
* @returns
* @param {Object} jwe JWE JSON Serialization https://tools.ietf.org/html/rfc7516#section-3.2
* @param {String} key The shared secret to decrypt
*/
const encrypt = ({ plaintext }) => {
const keyBuffer = crypto.randomBytes(KEY_LENGTH)
const ivBuffer = crypto.randomBytes(IV_LENGTH)
let cipher = crypto.createCipheriv(ENCRYPTION_ALGORITHM, keyBuffer, ivBuffer)
let encrypted = cipher.update(plaintext)
const encryptedBuffer = Buffer.concat([encrypted, cipher.final()])
const header = {
alg: JWE_ALG,
enc: JWE_ENC,
}
const protected = base64url(JSON.stringify(header))
const iv = base64url(ivBuffer)
const key = base64url(keyBuffer)
const ciphertext = base64url(encryptedBuffer)
const jwe = { protected, iv, ciphertext }
return { jwe, key }
}
const run = async () => {
const verifiableCredential = {
'@context':[
'https://www.w3.org/2018/credentials/v1',
'https://www.w3.org/2018/credentials/examples/v1'
],
'id':'http://example.gov/credentials/3732',
'type':[
'VerifiableCredential',
'UniversityDegreeCredential'
],
'issuer':'did:key:z6Mkq28Lfc8TwdaujZT8P2vWcs9eDnWKjXyYom6EgDxjCK1j',
'issuanceDate':'2020-03-10T04:24:12.164Z',
'credentialSubject':{
'id':'http://example.com/subject/123',
'degree':{
'type':'BachelorDegree',
'name':'Bachelor of Science and Arts'
}
},
'proof':{
'type':'Ed25519Signature2018',
'created':'2020-03-10T04:24:12.164Z',
'jws':'eyJhbGciOiJFZERTQSIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..gsjCEscxfFpe7Kith8tmwp7U3UBTjK7DIzPjfyfXXfzYmRH8IMEmcyUCt-mTJHB7tC6-fAgWPN7VNY0AvT2kCA',
'proofPurpose':'assertionMethod',
'verificationMethod':'did:key:z6Mkq28Lfc8TwdaujZT8P2vWcs9eDnWKjXyYom6EgDxjCK1j#z6Mkq28Lfc8TwdaujZT8P2vWcs9eDnWKjXyYom6EgDxjCK1j'
}
}
const inputPlaintext = JSON.stringify(verifiableCredential)
const { jwe, key } = encrypt({ plaintext: inputPlaintext })
console.log({ jwe })
const { plaintext } = decrypt({ jwe, key })
const vc = JSON.parse(plaintext)
console.log({ vc })
const urlQuery = new URLSearchParams({ key, access_token: DOCUMENT_ACCESS_TOKEN })
const queryString = urlQuery.toString()
const proposedUrl = `${DOCUMENT_URL}?${queryString}`
console.log({ proposedUrl })
}
run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment