Skip to content

Commit

Permalink
refactor: encrypt APIs unprotectedHeader and aad arguments swapped
Browse files Browse the repository at this point in the history
BREAKING CHANGE: jose.JWE.Encrypt constructor aad and unprotectedHeader
arguments swapped places
BREAKING CHANGE: jose.JWE.encrypt.flattened header (unprotectedHeader)
and aad arguments swapped places
BREAKING CHANGE: jose.JWE.encrypt.general header (unprotectedHeader)
and aad arguments swapped places
  • Loading branch information
panva committed Sep 8, 2020
1 parent ba5c897 commit 70bd4ae
Show file tree
Hide file tree
Showing 11 changed files with 36 additions and 38 deletions.
12 changes: 6 additions & 6 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1350,11 +1350,11 @@ JWS.verify(general, keystore, { complete: true })

<!-- TOC JWE START -->
- [Class: &lt;JWE.Encrypt&gt;](#class-jweencrypt)
- [new JWE.Encrypt(cleartext[, protected[, unprotected[, aad]]])](#new-jweencryptcleartext-protected-unprotected-aad)
- [new JWE.Encrypt(cleartext[, protected[, aad[, unprotected]]])](#new-jweencryptcleartext-protected-aad-unprotected)
- [encrypt.recipient(key[, header])](#encryptrecipientkey-header)
- [encrypt.encrypt(serialization)](#encryptencryptserialization)
- [JWE.encrypt(cleartext, key[, protected])](#jweencryptcleartext-key-protected)
- [JWE.encrypt.flattened(cleartext, key[, protected[, unprotected[, aad]]])](#jweencryptflattenedcleartext-key-protected-unprotected-aad)
- [JWE.encrypt.flattened(cleartext, key[, protected[, aad[, unprotected]]])](#jweencryptflattenedcleartext-key-protected-aad-unprotected)
- [JWE.decrypt(jwe, keyOrStore[, options])](#jwedecryptjwe-keyorstore-options)
<!-- TOC JWE END -->

Expand All @@ -1377,15 +1377,15 @@ General JWE JSON Serialization Syntax.

---

#### `new JWE.Encrypt(cleartext[, protected[, unprotected[, aad]]])`
#### `new JWE.Encrypt(cleartext[, protected[, aad[, unprotected]]])`

Creates a new Encrypt object for the provided cleartext with optional Protected and Unprotected
Headers and Additional Authenticated Data.

- `cleartext`: `<string>` &vert; `<Buffer>` The cleartext that will be encrypted.
- `protected`: `<Object>` JWE Protected Header
- `unprotected`: `<Object>` JWE Shared Unprotected Header
- `aad`: `<string>` &vert; `<Buffer>` JWE Additional Authenticated Data
- `unprotected`: `<Object>` JWE Shared Unprotected Header
- Returns: `<JWE.Encrypt>`

---
Expand Down Expand Up @@ -1432,7 +1432,7 @@ Protected Header or inferred from the provided `<JWK.Key>` instance.

---

#### `JWE.encrypt.flattened(cleartext, key[, protected[, unprotected[, aad]]])`
#### `JWE.encrypt.flattened(cleartext, key[, protected[, aad[, unprotected]]])`

Performs the encryption operation and 'flattened' JWE serialization of the result. The Algorithm
that will be used to wrap or derive the Content Encryption Key (CEK) is either provided as part of
Expand All @@ -1443,8 +1443,8 @@ the combined JWE Header or inferred from the provided `<JWK.Key>` instance.
compatible input also works. `<JWK.Key>` instances are recommended for performance purposes when
re-using the same key for every operation.
- `protected`: `<Object>` JWE Protected Header
- `unprotected`: `<Object>` JWE Shared Unprotected Header
- `aad`: `<string>` &vert; `<Buffer>` JWE Additional Authenticated Data
- `unprotected`: `<Object>` JWE Shared Unprotected Header
- Returns: `<Object>`

---
Expand Down
3 changes: 1 addition & 2 deletions lib/jwe/encrypt.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ const validateHeaders = require('./validate_headers')
const PROCESS_RECIPIENT = Symbol('PROCESS_RECIPIENT')

class Encrypt {
// TODO: in v2.x swap unprotectedHeader and aad
constructor (cleartext, protectedHeader, unprotectedHeader, aad) {
constructor (cleartext, protectedHeader, aad, unprotectedHeader) {
if (!Buffer.isBuffer(cleartext) && typeof cleartext !== 'string') {
throw new TypeError('cleartext argument must be a Buffer or a string')
}
Expand Down
5 changes: 2 additions & 3 deletions lib/jwe/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
const Encrypt = require('./encrypt')
const decrypt = require('./decrypt')

// TODO: in v2.x swap unprotectedHeader and aad
const single = (serialization, cleartext, key, protectedHeader, unprotectedHeader, aad) => {
return new Encrypt(cleartext, protectedHeader, unprotectedHeader, aad)
const single = (serialization, cleartext, key, protectedHeader, aad, unprotectedHeader) => {
return new Encrypt(cleartext, protectedHeader, aad, unprotectedHeader)
.recipient(key)
.encrypt(serialization)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg:
const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty))

test(`${recipe.title} - flattened encrypt`, t => {
const res = JWE.encrypt.flattened(plaintext, key, prot, undefined, aad)
const res = JWE.encrypt.flattened(plaintext, key, prot, aad)
verifiers.flattened(t, res, recipe.output.json_flat)
t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext))
})

test(`${recipe.title} - general encrypt`, t => {
const res = JWE.encrypt.general(plaintext, key, prot, undefined, aad)
const res = JWE.encrypt.general(plaintext, key, prot, aad)
verifiers.general(t, res, recipe.output.json)
t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext))
})
Expand Down
4 changes: 2 additions & 2 deletions test/cookbook/5_11.protecting_specific_header_fields.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg:
const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty))

test(`${recipe.title} - flattened encrypt`, t => {
const res = JWE.encrypt.flattened(plaintext, key, prot, unprotected)
const res = JWE.encrypt.flattened(plaintext, key, prot, undefined, unprotected)
verifiers.flattened(t, res, recipe.output.json_flat)
t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext))
})

test(`${recipe.title} - general encrypt`, t => {
const res = JWE.encrypt.general(plaintext, key, prot, unprotected)
const res = JWE.encrypt.general(plaintext, key, prot, undefined, unprotected)
verifiers.general(t, res, recipe.output.json)
t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext))
})
Expand Down
4 changes: 2 additions & 2 deletions test/cookbook/5_12.protecting_content_only.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg:
const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty))

test(`${recipe.title} - flattened encrypt`, t => {
const res = JWE.encrypt.flattened(plaintext, key, undefined, unprotected)
const res = JWE.encrypt.flattened(plaintext, key, undefined, undefined, unprotected)
verifiers.flattened(t, res, recipe.output.json_flat)
t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext))
})

test(`${recipe.title} - general encrypt`, t => {
const res = JWE.encrypt.general(plaintext, key, undefined, unprotected)
const res = JWE.encrypt.general(plaintext, key, undefined, undefined, unprotected)
verifiers.general(t, res, recipe.output.json)
t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext))
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ keys.forEach(({ kty }) => {
})

test(`${recipe.title} - general encrypt`, t => {
const jwe = new JWE.Encrypt(plaintext, prot, unprotected)
const jwe = new JWE.Encrypt(plaintext, prot, undefined, unprotected)
keys.forEach((key, i) => {
jwe.recipient(key, recipients[i].header)
})
Expand Down
16 changes: 8 additions & 8 deletions test/jwe/complete.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,16 @@ const complete = (t, jwe, k, ...keys) => {

test('compact', complete, () => JWE.encrypt('foo', key), 'cleartext', 'protected', 'key', 'cek')
test('flattened', complete, () => JWE.encrypt.flattened('foo', key), 'cleartext', 'protected', 'key', 'cek')
test('flattened w/ aad', complete, () => JWE.encrypt.flattened('foo', key, undefined, undefined, 'bar'), 'cleartext', 'protected', 'aad', 'key', 'cek')
test('flattened w/ unprotected', complete, () => JWE.encrypt.flattened('foo', key, undefined, { foo: 'bar' }), 'cleartext', 'protected', 'unprotected', 'key', 'cek')
test('flattened w/ aad', complete, () => JWE.encrypt.flattened('foo', key, undefined, 'bar'), 'cleartext', 'protected', 'aad', 'key', 'cek')
test('flattened w/ unprotected', complete, () => JWE.encrypt.flattened('foo', key, undefined, undefined, { foo: 'bar' }), 'cleartext', 'protected', 'unprotected', 'key', 'cek')
test('flattened w/ header', complete, () => {
const enc = new JWE.Encrypt('foo')
enc.recipient(key, { foo: 'bar' })
return enc.encrypt('flattened')
}, 'cleartext', 'protected', 'header', 'key', 'cek')
test('general', complete, () => JWE.encrypt.general('foo', key), 'cleartext', 'protected', 'key', 'cek')
test('general w/ aad', complete, () => JWE.encrypt.general('foo', key, undefined, undefined, 'bar'), 'cleartext', 'protected', 'aad', 'key', 'cek')
test('general w/ unprotected', complete, () => JWE.encrypt.general('foo', key, undefined, { foo: 'bar' }), 'cleartext', 'protected', 'unprotected', 'key', 'cek')
test('general w/ aad', complete, () => JWE.encrypt.general('foo', key, undefined, 'bar'), 'cleartext', 'protected', 'aad', 'key', 'cek')
test('general w/ unprotected', complete, () => JWE.encrypt.general('foo', key, undefined, undefined, { foo: 'bar' }), 'cleartext', 'protected', 'unprotected', 'key', 'cek')
test('general w/ header', complete, () => {
const enc = new JWE.Encrypt('foo')
enc.recipient(key, { foo: 'bar' })
Expand All @@ -54,16 +54,16 @@ test('general w/ header', complete, () => {

test('with keystore > compact', complete, () => JWE.encrypt('foo', key), ks, 'cleartext', 'protected', 'key', 'cek')
test('with keystore > flattened', complete, () => JWE.encrypt.flattened('foo', key), ks, 'cleartext', 'protected', 'key', 'cek')
test('with keystore > flattened w/ aad', complete, () => JWE.encrypt.flattened('foo', key, undefined, undefined, 'bar'), ks, 'cleartext', 'protected', 'aad', 'key', 'cek')
test('with keystore > flattened w/ unprotected', complete, () => JWE.encrypt.flattened('foo', key, undefined, { foo: 'bar' }), ks, 'cleartext', 'protected', 'unprotected', 'key', 'cek')
test('with keystore > flattened w/ aad', complete, () => JWE.encrypt.flattened('foo', key, undefined, 'bar'), ks, 'cleartext', 'protected', 'aad', 'key', 'cek')
test('with keystore > flattened w/ unprotected', complete, () => JWE.encrypt.flattened('foo', key, undefined, undefined, { foo: 'bar' }), ks, 'cleartext', 'protected', 'unprotected', 'key', 'cek')
test('with keystore > flattened w/ header', complete, () => {
const enc = new JWE.Encrypt('foo')
enc.recipient(key, { foo: 'bar' })
return enc.encrypt('flattened')
}, ks, 'cleartext', 'protected', 'header', 'key', 'cek')
test('with keystore > general', complete, () => JWE.encrypt.general('foo', key), ks, 'cleartext', 'protected', 'key', 'cek')
test('with keystore > general w/ aad', complete, () => JWE.encrypt.general('foo', key, undefined, undefined, 'bar'), ks, 'cleartext', 'protected', 'aad', 'key', 'cek')
test('with keystore > general w/ unprotected', complete, () => JWE.encrypt.general('foo', key, undefined, { foo: 'bar' }), ks, 'cleartext', 'protected', 'unprotected', 'key', 'cek')
test('with keystore > general w/ aad', complete, () => JWE.encrypt.general('foo', key, undefined, 'bar'), ks, 'cleartext', 'protected', 'aad', 'key', 'cek')
test('with keystore > general w/ unprotected', complete, () => JWE.encrypt.general('foo', key, undefined, undefined, { foo: 'bar' }), ks, 'cleartext', 'protected', 'unprotected', 'key', 'cek')
test('with keystore > general w/ header', complete, () => {
const enc = new JWE.Encrypt('foo')
enc.recipient(key, { foo: 'bar' })
Expand Down
2 changes: 1 addition & 1 deletion test/jwe/crit.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ test('crit must be present', t => {
test('crit must be integrity protected', t => {
const k = generateSync('oct')
t.throws(() => {
JWE.encrypt.flattened('foo', k, undefined, { crit: [UNDEFINED] })
JWE.encrypt.flattened('foo', k, undefined, undefined, { crit: [UNDEFINED] })
}, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: '"crit" Header Parameter MUST be integrity protected when present' })
const jws = JWE.encrypt.flattened('foo', k)
jws.header = { crit: [UNDEFINED] }
Expand Down
16 changes: 8 additions & 8 deletions test/jwe/sanity.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ test('JWE no alg specified (single rsa), with protected header', t => {

test('JWE no alg specified (single rsa), with unprotected header', t => {
const k = generateSync('RSA')
const encrypt = new JWE.Encrypt('foo', undefined, { enc: 'A256CBC-HS512' })
const encrypt = new JWE.Encrypt('foo', undefined, undefined, { enc: 'A256CBC-HS512' })
encrypt.recipient(k)

const jwe = encrypt.encrypt('flattened')
Expand Down Expand Up @@ -279,7 +279,7 @@ test('JWE encrypt protectedHeader rejects non objects if provided', t => {
test('JWE encrypt unprotectedHeader rejects non objects if provided', t => {
;[[], false, true, null, Infinity, 0, Buffer.from('foo')].forEach((val) => {
t.throws(() => {
new JWE.Encrypt('foo', undefined, val) // eslint-disable-line no-new
new JWE.Encrypt('foo', undefined, undefined, val) // eslint-disable-line no-new
}, { instanceOf: TypeError, message: 'unprotectedHeader argument must be a plain object when provided' })
})
})
Expand All @@ -297,7 +297,7 @@ test('JWE encrypt per-recipient header rejects non objects if provided', t => {
test('JWE encrypt aad rejects non buffers and non strings', t => {
;[[], false, true, null, Infinity, 0].forEach((val) => {
t.throws(() => {
new JWE.Encrypt('foo', undefined, undefined, val) // eslint-disable-line no-new
new JWE.Encrypt('foo', undefined, val) // eslint-disable-line no-new
}, { instanceOf: TypeError, message: 'aad argument must be a Buffer or a string when provided' })
})
})
Expand Down Expand Up @@ -332,14 +332,14 @@ test('JWE compact does not support multiple recipients', t => {
test('JWE compact does not support unprotected header', t => {
const k = generateSync('oct')
t.throws(() => {
JWE.encrypt('foo', k, undefined, { foo: 1 })
JWE.encrypt('foo', k, undefined, undefined, { foo: 1 })
}, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'JWE Compact Serialization doesn\'t support multiple recipients, JWE unprotected headers or AAD' })
})

test('JWE compact does not support aad', t => {
const k = generateSync('oct')
t.throws(() => {
JWE.encrypt('foo', k, undefined, undefined, 'aad')
JWE.encrypt('foo', k, undefined, 'aad')
}, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'JWE Compact Serialization doesn\'t support multiple recipients, JWE unprotected headers or AAD' })
})

Expand Down Expand Up @@ -417,7 +417,7 @@ test('JWE EC ECDH-ES is only usable with a single recipient', t => {
test('JWE prot, unprot and per-recipient headers must be disjoint', t => {
const k = generateSync('oct')
t.throws(() => {
const encrypt = new JWE.Encrypt('foo', { foo: 1 }, { foo: 2 })
const encrypt = new JWE.Encrypt('foo', { foo: 1 }, undefined, { foo: 2 })
encrypt.recipient(k)
encrypt.encrypt('flattened')
}, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'JWE Shared Protected, JWE Shared Unprotected and JWE Per-Recipient Header Parameter names must be disjoint' })
Expand All @@ -427,7 +427,7 @@ test('JWE prot, unprot and per-recipient headers must be disjoint', t => {
encrypt.encrypt('flattened')
}, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'JWE Shared Protected, JWE Shared Unprotected and JWE Per-Recipient Header Parameter names must be disjoint' })
t.throws(() => {
const encrypt = new JWE.Encrypt('foo', undefined, { foo: 1 })
const encrypt = new JWE.Encrypt('foo', undefined, undefined, { foo: 1 })
encrypt.recipient(k, { foo: 2 })
encrypt.encrypt('flattened')
}, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'JWE Shared Protected, JWE Shared Unprotected and JWE Per-Recipient Header Parameter names must be disjoint' })
Expand Down Expand Up @@ -508,7 +508,7 @@ test('JWE "zip" must be integrity protected', t => {
const k = generateSync('oct')

t.throws(() => {
JWE.encrypt.flattened('foo', k, undefined, { zip: 'DEF' })
JWE.encrypt.flattened('foo', k, undefined, undefined, { zip: 'DEF' })
}, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: '"zip" Header Parameter MUST be integrity protected' })
})

Expand Down
6 changes: 3 additions & 3 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ export namespace JWE {
}

class Encrypt {
constructor(cleartext: string | Buffer, protected?: object, unprotected?: object, aad?: string);
constructor(cleartext: string | Buffer, protected?: object, aad?: string, unprotected?: object);

recipient(key: ProduceKeyInput, header?: object): void;

Expand All @@ -393,8 +393,8 @@ export namespace JWE {

function encrypt(payload: string | Buffer, key: ProduceKeyInput, protected?: object): string;
namespace encrypt {
function flattened(payload: string | Buffer, key: ProduceKeyInput, protected?: object, header?: object, aad?: string): FlattenedJWE;
function general(payload: string | Buffer, key: ProduceKeyInput, protected?: object, header?: object, aad?: string): GeneralJWE;
function flattened(payload: string | Buffer, key: ProduceKeyInput, protected?: object, aad?: string, header?: object): FlattenedJWE;
function general(payload: string | Buffer, key: ProduceKeyInput, protected?: object, aad?: string, header?: object): GeneralJWE;
}

interface DecryptOptions {
Expand Down

0 comments on commit 70bd4ae

Please sign in to comment.