Skip to content
This repository has been archived by the owner on Feb 25, 2019. It is now read-only.

API Documentation #3

Merged
merged 17 commits into from
Aug 24, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
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
20 changes: 4 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ available natively in browsers and [via npm][node-webcrypto] in Node.js.
[jwkset]: https://tools.ietf.org/html/rfc7517#section-5
[w3c-webcrypto]: https://www.w3.org/TR/WebCryptoAPI/
[node-webcrypto]: https://www.npmjs.com/package/@trust/webcrypto
[api-docs]: https://anvilresearch.github.io/jwk


## Table of Contents
Expand Down Expand Up @@ -71,24 +72,11 @@ $ npm run karma // Karma (browser)

## API

### JWK
Full documentation available [here][api-docs].

#### new JWK()
#### (static) importKey()
#### sign()
#### verify()
#### encrypt()
#### decrypt()
### Examples

### JWKSet

#### new JWKSet()
#### (static) generateKeys()
#### (static) importKeys()
#### generateKeys()
#### importKeys()
#### filter()
#### find()
TBD

## Contribute

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"sinon-chai": "^2.12.0"
},
"dependencies": {
"@trust/jwa": "^0.4.3",
"@trust/jwa": "^0.4.5",
"@trust/webcrypto": "^0.4.0",
"node-fetch": "^1.7.2",
"sift": "^5.0.0"
Expand Down
179 changes: 127 additions & 52 deletions src/JWK.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,13 @@ class JWK {
/**
* constructor
*
* @class
* JSON Web Key
* @class JWK
*
* @description
* JSON Web Key ([IETF RFC7517](https://tools.ietf.org/html/rfc7517))
*
* @param {Object} data
* @param {Object} [options={}] - Additional JWK metadata.
*/
constructor (data, options = {}) {
if (!data) {
Expand All @@ -38,75 +43,110 @@ class JWK {
}
}

// Handle object input
if (data.alg && options.alg && data.alg !== options.alg) {
throw new DataError('Conflicting algorithm option')
// Handle options input
let metadata = Object.keys(options)
.filter(key => {
let dataValue = data[key]
let optionsValue = options[key]

} else if (!data.alg && options.alg) {
data.alg = options.alg

} else if (!data.alg && !options.alg) {
throw new DataError('Valid JWA algorithm required for JWK')
}
if (dataValue && optionsValue && dataValue !== optionsValue) {
throw new DataError(`Conflicting '${key}' option`)
}

// Handle kid transferral
if (data.kid && options.kid && data.kid !== options.kid) {
throw new DataError('Conflicting key identifier option')
return !dataValue && optionsValue
})
.reduce((state, key) => {
state[key] = options[key]
return state
}, {})

} else if (!data.kid && options.kid) {
data.kid = options.kid
// Assign input
Object.assign(this, data, metadata)

} else if (!data.kid && !options.kid) {
throw new DataError('Valid JWA key identifier required for JWK')
// Enforce required properties
if (!this.alg) {
throw new DataError('Valid \'alg\' required for JWK')
}

Object.assign(this, data)
if (!this.kid) {
throw new DataError('Valid \'kid\' required for JWK')
}
}

/**
* importKey
*
* @description
* Import a JWK from JSON String or a JS Object.
*
* @param {(String|Object)} data
* @return {Promise}
* @param {Object} [options] - Additional JWK metadata.
* @return {Promise.<JWK>} A promise that resolves the JWK instance.
*/
static importKey (data, options = {}) {
static importKey (data, options) {
return Promise.resolve()
// Create instance
.then(() => new JWK(data, options))
.then(jwk => {
return JWA.importKey(jwk)
.then(({ cryptoKey }) => {
Object.defineProperty(jwk, 'cryptoKey', {
value: cryptoKey,
enumerable: false,
configurable: false
})

return jwk
})
})

// Import CryptoKey and assign to JWK
.then(jwk => JWA.importKey(jwk).then(({ cryptoKey }) => {
Object.defineProperty(jwk, 'cryptoKey', {
value: cryptoKey,
enumerable: false,
configurable: false
})

return jwk
}))
}

/**
* fromCryptoKey
*
* @param {CryptoKey} key
* @param {Object} [options]
* @return {Promise}
* @description
* Import a JWK from a [WebCrypto CryptoKey](https://github.com/anvilresearch/webcrypto).
*
* @param {CryptoKey} key - [WebCrypto CryptoKey]{@link https://github.com/anvilresearch/webcrypto}.
* @param {Object} [options] - Additional JWK metadata.
* @return {Promise.<JWK>} A promise that resolves the JWK instance.
*/
static fromCryptoKey (key, options) {
// Export JWK
return JWA.exportKey('jwk', key)

// Create JWK instance and assign CryptoKey
.then(data => {
let jwk = new JWK(data, options)
Object.defineProperty(jwk, 'cryptoKey', { value: key, enumerable: false, configurable: false })

Object.defineProperty(jwk, 'cryptoKey', {
value: key,
enumerable: false,
configurable: false
})

return jwk
})
}

/**
* sign
*
* @param {(String|Buffer)} data
* @return {Promise}
* @description
* Sign arbitrary data using the JWK.
*
* @example <caption>Signing the string "test"</caption>
* privateJwk.sign('test')
* .then(console.log)
* //
* // (line breaks for display only)
* //
* // => "MEUCIQCHwnGM8IsOJgfQsoPgs3hMd8
* // ahfWHM9ZNvj1K6i2yhKQIgWGOuXX43
* // lSTo-U8Pa8sURR53lv6Osjw-dtoLse
* // lftqQ"
*
* @param {(String|Buffer)} data - The data to sign.
* @return {Promise.<String>} A promise that resolves the base64url encoded signature string.
*/
sign (data) {
let { alg, cryptoKey } = this
Expand All @@ -116,9 +156,21 @@ class JWK {
/**
* verify
*
* @param {(String|Buffer)} data
* @param {String} signature
* @return {Promise}
* @description
* Verify a signature using the JWK.
*
* @example <caption>Verify a signature of the string "test"</caption>
* // base64url encoded signature string
* let signature = `MEUCIQCHwnGM8IsOJgfQsoPgs3hMd8ahfWHM9ZN
* vj1K6i2yhKQIgWGOuXX43lSTo-U8Pa8sURR53lv6Osjw-dtoLselftqQ`
*
* publicJwk.verify('test', signature)
* .then(console.log)
* // => true
*
* @param {(String|Buffer)} data - The data to verify.
* @param {String} signature - A base64url signature string.
* @return {Promise.<Boolean>} A promise that resolves the boolean result of the signature verification.
*/
verify (data, signature) {
let { alg, cryptoKey } = this
Expand All @@ -128,9 +180,19 @@ class JWK {
/**
* encrypt
*
* @param {(String|Object)} data
* @param {(String|Buffer)} aad - integrity protected data
* @return {Promise}
* @description
* Encrypt arbitrary data using the JWK.
*
* @example <caption>Encrypt the string "data"</caption>
* secretJwk.encrypt('data')
* .then(console.log)
* // => { iv: 'u0l3ttqUFDQ8mcRboHv5Vw',
* // ciphertext: 'yq3K4w',
* // tag: 'fHlZ__uuUnHn0ac-Lnrr-A' }
*
* @param {(String|Object)} data - The data to encrypt.
* @param {(String|Buffer)} [aad] - Additional non-encrypted integrity protected data (AES-GCM).
* @return {Promise.<Object>} A promise that resolves an object containing the base64url encoded `iv`, `ciphertext` and `tag` (AES-GCM).
*/
encrypt (data, aad) {
let { alg, cryptoKey } = this
Expand All @@ -140,15 +202,28 @@ class JWK {
/**
* decrypt
*
* @param {(String|Object)} data
* @param {(String|Buffer)} iv
* @param {(String|Buffer)} tag
* @param {(String|Buffer)} aad
* @return {Promise}
* @description
* Decrypt data using the JWK.
*
* @example <caption>Decrypt encrypted string "test"</caption>
* // base64url encoded data
* let ciphertext = 'yq3K4w'
* let iv = 'u0l3ttqUFDQ8mcRboHv5Vw'
* let tag = 'fHlZ__uuUnHn0ac-Lnrr-A'
*
* secretJwk.decrypt(ciphertext, iv, tag)
* .then(console.log)
* // => "data"
*
* @param {(String|Buffer)} ciphertext - The encrypted data to decrypt.
* @param {(String|Buffer)} iv - The initialization vector.
* @param {(String|Buffer)} [tag] - The authorization tag (AES-GCM).
* @param {(String|Buffer)} [aad] - Additional non-encrypted integrity protected data (AES-GCM).
* @return {Promise.<String>} A promise that resolves the plaintext data.
*/
decrypt (data, iv, tag, aad) {
decrypt (ciphertext, iv, tag, aad) {
let { alg, cryptoKey } = this
return JWA.decrypt(alg, cryptoKey, data, iv, tag, aad)
return JWA.decrypt(alg, cryptoKey, ciphertext, iv, tag, aad)
}
}

Expand Down
Loading