Skip to content

Commit f538dc8

Browse files
committed
fix: Encryption Context changes
resolves aws#54 1. browser/node encrypt function public api should match 1. Encryption context should _only_ be optional in the public interface 1. Encryption context moved into cryptographic materials Internally, it is much more consistent to require an encryption context. Moving the encryption context onto the cryptographic materials brings them in line with the python keyring implementation. It also makes control of the encryption context in the CMM and **not** the keyrings very clear in the interface. NOTE: encrypt in encrypt-node now expects `encryptionContext` instead of `context`. This is **ONLY** done because the project is still in beta.
1 parent eb4813e commit f538dc8

File tree

44 files changed

+436
-403
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+436
-403
lines changed

modules/cache-material/src/build_cryptographic_materials_cache_key_helpers.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,13 @@ export function buildCryptographicMaterialsCacheKeyHelpers<S extends SupportedAl
8484
return hashes.sort(compare)
8585
}
8686

87-
function encryptionContextHash (context?: EncryptionContext) {
87+
function encryptionContextHash (context: EncryptionContext) {
8888
/* The AAD section is uInt16BE(length) + AAD
8989
* see: https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/message-format.html#header-aad
9090
* However, the RAW Keyring wants _only_ the ADD.
9191
* So, I just slice off the length.
9292
*/
93-
const serializedContext = serializeEncryptionContext(context || {}).slice(2)
93+
const serializedContext = serializeEncryptionContext(context).slice(2)
9494
return sha512(serializedContext)
9595
}
9696
}
@@ -105,5 +105,5 @@ export interface CryptographicMaterialsCacheKeyHelpersInterface<S extends Suppor
105105
{ suite, encryptedDataKeys, encryptionContext }: DecryptionRequest<S>
106106
): Promise<string>
107107
encryptedDataKeysHash(encryptedDataKeys: ReadonlyArray<EncryptedDataKey>): Promise<Uint8Array[]>
108-
encryptionContextHash(context?: EncryptionContext): Promise<Uint8Array>
108+
encryptionContextHash(context: EncryptionContext): Promise<Uint8Array>
109109
}

modules/cache-material/src/clone_cryptographic_material.ts

+12-11
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,23 @@ import {
1919
WebCryptoEncryptionMaterial,
2020
WebCryptoDecryptionMaterial,
2121
isEncryptionMaterial,
22-
isDecryptionMaterial
22+
isDecryptionMaterial,
23+
NodeAlgorithmSuite
2324

2425
} from '@aws-crypto/material-management'
2526

2627
type Material = NodeEncryptionMaterial|NodeDecryptionMaterial|WebCryptoEncryptionMaterial|WebCryptoDecryptionMaterial
2728

2829
export function cloneMaterial<M extends Material> (source: M): M {
29-
const clone = source instanceof NodeEncryptionMaterial
30-
? new NodeEncryptionMaterial(source.suite)
31-
: source instanceof NodeDecryptionMaterial
32-
? new NodeDecryptionMaterial(source.suite)
33-
: source instanceof WebCryptoEncryptionMaterial
34-
? new WebCryptoEncryptionMaterial(source.suite)
35-
: source instanceof WebCryptoDecryptionMaterial
36-
? new WebCryptoDecryptionMaterial(source.suite)
37-
: false
30+
const { suite, encryptionContext } = source
3831

39-
if (!clone) throw new Error('Unsupported material type')
32+
const clone = suite instanceof NodeAlgorithmSuite
33+
? source instanceof NodeEncryptionMaterial
34+
? new NodeEncryptionMaterial(suite, encryptionContext)
35+
: new NodeDecryptionMaterial(suite, encryptionContext)
36+
: source instanceof WebCryptoEncryptionMaterial
37+
? new WebCryptoEncryptionMaterial(suite, encryptionContext)
38+
: new WebCryptoDecryptionMaterial(suite, encryptionContext)
4039

4140
const udk = new Uint8Array(source.getUnencryptedDataKey())
4241
clone.setUnencryptedDataKey(udk, source.keyringTrace[0])
@@ -61,6 +60,8 @@ export function cloneMaterial<M extends Material> (source: M): M {
6160
if (source.suite.signatureCurve && source.verificationKey) {
6261
clone.setVerificationKey(source.verificationKey)
6362
}
63+
} else {
64+
throw new Error('Material mismatch')
6465
}
6566

6667
return <M>clone

modules/cache-material/test/caching_cryptographic_materials_decorators.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -207,12 +207,12 @@ describe('Cryptographic Material Functions', () => {
207207
const edk1 = new EncryptedDataKey({ providerId: 'keyNamespace', providerInfo: 'keyName', encryptedDataKey: new Uint8Array([1]) })
208208
const edk2 = new EncryptedDataKey({ providerId: 'p2', providerInfo: 'pi2', encryptedDataKey: new Uint8Array([2]) })
209209

210-
const encryptionMaterial = new NodeEncryptionMaterial(nodeSuite)
210+
const encryptionMaterial = new NodeEncryptionMaterial(nodeSuite, {})
211211
.setUnencryptedDataKey(udk128, trace)
212212
.addEncryptedDataKey(edk1, KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY)
213213
.addEncryptedDataKey(edk2, KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY)
214214

215-
const decryptionMaterial = new NodeDecryptionMaterial(nodeSuite)
215+
const decryptionMaterial = new NodeDecryptionMaterial(nodeSuite, {})
216216
.setUnencryptedDataKey(udk128, trace)
217217

218218
const context = {}

modules/cache-material/test/clone_cryptographic_material.test.ts

+8-4
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ const cryptoKey: any = { type: 'secret', algorithm: { name: webCryptoSuite.encry
4646

4747
describe('cloneMaterial', () => {
4848
it('clone NodeEncryptionMaterial', () => {
49-
const material = new NodeEncryptionMaterial(nodeSuite)
49+
const material = new NodeEncryptionMaterial(nodeSuite, { some: 'context' })
5050
.setUnencryptedDataKey(udk128, trace)
5151
.addEncryptedDataKey(edk1, KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY)
5252
.addEncryptedDataKey(edk2, KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY)
@@ -56,20 +56,22 @@ describe('cloneMaterial', () => {
5656
expect(test.getUnencryptedDataKey()).to.deep.equal(udk128)
5757
expect(test.keyringTrace).to.deep.equal(material.keyringTrace)
5858
expect(test.encryptedDataKeys).to.deep.equal(material.encryptedDataKeys)
59+
expect(test.encryptionContext).to.deep.equal(material.encryptionContext)
5960
})
6061

6162
it('clone NodeDecryptionMaterial', () => {
62-
const material = new NodeDecryptionMaterial(nodeSuite)
63+
const material = new NodeDecryptionMaterial(nodeSuite, { some: 'context' })
6364
.setUnencryptedDataKey(udk128, trace)
6465

6566
const test = cloneMaterial(material)
6667
expect(test).to.be.instanceOf(NodeDecryptionMaterial)
6768
expect(test.getUnencryptedDataKey()).to.deep.equal(udk128)
6869
expect(test.keyringTrace).to.deep.equal(material.keyringTrace)
70+
expect(test.encryptionContext).to.deep.equal(material.encryptionContext)
6971
})
7072

7173
it('clone WebCryptoEncryptionMaterial', () => {
72-
const material = new WebCryptoEncryptionMaterial(webCryptoSuite)
74+
const material = new WebCryptoEncryptionMaterial(webCryptoSuite, { some: 'context' })
7375
.setUnencryptedDataKey(udk128, trace)
7476
.setCryptoKey(cryptoKey, trace)
7577
.addEncryptedDataKey(edk1, KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY)
@@ -81,10 +83,11 @@ describe('cloneMaterial', () => {
8183
expect(test.getCryptoKey()).to.deep.equal(cryptoKey)
8284
expect(test.keyringTrace).to.deep.equal(material.keyringTrace)
8385
expect(test.encryptedDataKeys).to.deep.equal(material.encryptedDataKeys)
86+
expect(test.encryptionContext).to.deep.equal(material.encryptionContext)
8487
})
8588

8689
it('clone WebCryptoDecryptionMaterial', () => {
87-
const material = new WebCryptoDecryptionMaterial(webCryptoSuite)
90+
const material = new WebCryptoDecryptionMaterial(webCryptoSuite, { some: 'context' })
8891
.setUnencryptedDataKey(udk128, trace)
8992
.setCryptoKey(cryptoKey, trace)
9093

@@ -93,5 +96,6 @@ describe('cloneMaterial', () => {
9396
expect(test.getUnencryptedDataKey()).to.deep.equal(udk128)
9497
expect(test.getCryptoKey()).to.deep.equal(cryptoKey)
9598
expect(test.keyringTrace).to.deep.equal(material.keyringTrace)
99+
expect(test.encryptionContext).to.deep.equal(material.encryptionContext)
96100
})
97101
})

modules/cache-material/test/get_local_cryptographic_materials_cache.test.ts

+18-34
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ import {
2626
} from '@aws-crypto/material-management'
2727

2828
const nodeSuite = new NodeAlgorithmSuite(AlgorithmSuiteIdentifier.ALG_AES128_GCM_IV12_TAG16_HKDF_SHA256)
29-
const encryptionMaterial = new NodeEncryptionMaterial(nodeSuite)
30-
const decryptionMaterial = new NodeDecryptionMaterial(nodeSuite)
29+
const encryptionMaterial = new NodeEncryptionMaterial(nodeSuite, {})
30+
const decryptionMaterial = new NodeDecryptionMaterial(nodeSuite, {})
3131

3232
describe('getLocalCryptographicMaterialsCache', () => {
3333
const {
@@ -41,8 +41,7 @@ describe('getLocalCryptographicMaterialsCache', () => {
4141
it('putEncryptionResponse', () => {
4242
const key = 'some encryption key'
4343
const response: any = {
44-
material: encryptionMaterial,
45-
context: {}
44+
material: encryptionMaterial
4645
}
4746

4847
putEncryptionResponse(key, response, 1)
@@ -56,8 +55,7 @@ describe('getLocalCryptographicMaterialsCache', () => {
5655

5756
it('Precondition: putEncryptionResponse plaintextLength can not be negative.', () => {
5857
const response: any = {
59-
material: encryptionMaterial,
60-
context: {}
58+
material: encryptionMaterial
6159
}
6260
const u: any = undefined
6361
const s: any = 'not-number'
@@ -70,8 +68,7 @@ describe('getLocalCryptographicMaterialsCache', () => {
7068
it('Postcondition: Only return EncryptionMaterial.', () => {
7169
const key = 'some decryption key'
7270
const response: any = {
73-
material: decryptionMaterial,
74-
context: {}
71+
material: decryptionMaterial
7572
}
7673

7774
putDecryptionResponse(key, response)
@@ -82,8 +79,7 @@ describe('getLocalCryptographicMaterialsCache', () => {
8279
const key = 'some encryption key'
8380
const suite = new NodeAlgorithmSuite(AlgorithmSuiteIdentifier.ALG_AES128_GCM_IV12_TAG16)
8481
const response: any = {
85-
material: new NodeEncryptionMaterial(suite),
86-
context: {}
82+
material: new NodeEncryptionMaterial(suite, {})
8783
}
8884

8985
expect(() => putEncryptionResponse(key, response, 1)).to.throw()
@@ -92,8 +88,7 @@ describe('getLocalCryptographicMaterialsCache', () => {
9288
it('putDecryptionResponse', () => {
9389
const key = 'some decryption key'
9490
const response: any = {
95-
material: decryptionMaterial,
96-
context: {}
91+
material: decryptionMaterial
9792
}
9893

9994
putDecryptionResponse(key, response)
@@ -108,8 +103,7 @@ describe('getLocalCryptographicMaterialsCache', () => {
108103
it('Precondition: Only cache DecryptionMaterial.', () => {
109104
const key = 'some decryption key'
110105
const response: any = {
111-
material: 'not material',
112-
context: {}
106+
material: 'not material'
113107
}
114108

115109
expect(() => putDecryptionResponse(key, response)).to.throw()
@@ -119,8 +113,7 @@ describe('getLocalCryptographicMaterialsCache', () => {
119113
const key = 'some decryption key'
120114
const suite = new NodeAlgorithmSuite(AlgorithmSuiteIdentifier.ALG_AES128_GCM_IV12_TAG16)
121115
const response: any = {
122-
material: new NodeEncryptionMaterial(suite),
123-
context: {}
116+
material: new NodeEncryptionMaterial(suite, {})
124117
}
125118

126119
expect(() => putDecryptionResponse(key, response)).to.throw()
@@ -143,8 +136,7 @@ describe('getLocalCryptographicMaterialsCache', () => {
143136
it('Precondition: Only cache EncryptionMaterial.', () => {
144137
const key = 'some encryption key'
145138
const response: any = {
146-
material: 'not material',
147-
context: {}
139+
material: 'not material'
148140
}
149141

150142
expect(() => putEncryptionResponse(key, response, 1)).to.throw()
@@ -158,8 +150,7 @@ describe('getLocalCryptographicMaterialsCache', () => {
158150
it('Postcondition: Only return DecryptionMaterial.', () => {
159151
const key = 'some encryption key'
160152
const response: any = {
161-
material: encryptionMaterial,
162-
context: {}
153+
material: encryptionMaterial
163154
}
164155

165156
putEncryptionResponse(key, response, 1)
@@ -173,8 +164,7 @@ describe('getLocalCryptographicMaterialsCache', () => {
173164
it('zero is an acceptable plaintextLength', () => {
174165
const key = 'some encryption key'
175166
const response: any = {
176-
material: encryptionMaterial,
177-
context: {}
167+
material: encryptionMaterial
178168
}
179169

180170
putEncryptionResponse(key, response, 0)
@@ -197,8 +187,7 @@ describe('cache eviction', () => {
197187
const key1 = 'key lost'
198188
const key2 = 'key replace'
199189
const response: any = {
200-
material: decryptionMaterial,
201-
context: {}
190+
material: decryptionMaterial
202191
}
203192

204193
putDecryptionResponse(key1, response)
@@ -218,8 +207,7 @@ describe('cache eviction', () => {
218207

219208
const key = 'key deleted'
220209
const response: any = {
221-
material: decryptionMaterial,
222-
context: {}
210+
material: decryptionMaterial
223211
}
224212

225213
putDecryptionResponse(key, response)
@@ -236,8 +224,7 @@ describe('cache eviction', () => {
236224

237225
const key = 'key lost'
238226
const response: any = {
239-
material: decryptionMaterial,
240-
context: {}
227+
material: decryptionMaterial
241228
}
242229

243230
putDecryptionResponse(key, response, 1)
@@ -255,8 +242,7 @@ describe('cache eviction', () => {
255242
const key1 = 'key lost'
256243
const key2 = 'key replace'
257244
const response: any = {
258-
material: encryptionMaterial,
259-
context: {}
245+
material: encryptionMaterial
260246
}
261247

262248
putEncryptionResponse(key1, response, 0)
@@ -276,8 +262,7 @@ describe('cache eviction', () => {
276262

277263
const key = 'key lost'
278264
const response: any = {
279-
material: encryptionMaterial,
280-
context: {}
265+
material: encryptionMaterial
281266
}
282267

283268
putEncryptionResponse(key, response, 1, 1)
@@ -294,8 +279,7 @@ describe('cache eviction', () => {
294279

295280
const key = 'key lost'
296281
const response: any = {
297-
material: encryptionMaterial,
298-
context: {}
282+
material: encryptionMaterial
299283
}
300284

301285
putEncryptionResponse(key, response, 1, 1)

modules/encrypt-browser/src/encrypt.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export interface EncryptResult {
5858
export async function encrypt (
5959
cmm: KeyringWebCrypto|WebCryptoMaterialsManager,
6060
plaintext: Uint8Array,
61-
{ suiteId, encryptionContext, frameLength = FRAME_LENGTH }: EncryptInput = {}
61+
{ suiteId, encryptionContext = {}, frameLength = FRAME_LENGTH }: EncryptInput = {}
6262
): Promise<EncryptResult> {
6363
const backend = await getWebCryptoBackend()
6464
if (!backend) throw new Error('No supported crypto backend')
@@ -79,7 +79,7 @@ export async function encrypt (
7979
plaintextLength
8080
}
8181

82-
const { material, context } = await cmm.getEncryptionMaterials(encryptionRequest)
82+
const { material } = await cmm.getEncryptionMaterials(encryptionRequest)
8383
const { kdfGetSubtleEncrypt, subtleSign, dispose } = await getEncryptHelper(material)
8484

8585
const messageId = await backend.randomValues(MESSAGE_ID_LENGTH)
@@ -91,7 +91,7 @@ export async function encrypt (
9191
type: ObjectType.CUSTOMER_AE_DATA,
9292
suiteId: id,
9393
messageId,
94-
encryptionContext: context,
94+
encryptionContext: material.encryptionContext,
9595
encryptedDataKeys: material.encryptedDataKeys,
9696
contentType: ContentType.FRAMED_DATA,
9797
headerIvLength: ivLength,

modules/encrypt-node/src/encrypt_stream.ts

+8-7
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ const { serializeMessageHeader, headerAuthIv } = serializeFactory(fromUtf8)
3838

3939
export interface EncryptStreamInput {
4040
suiteId?: AlgorithmSuiteIdentifier
41-
context?: EncryptionContext
41+
encryptionContext?: EncryptionContext
4242
frameLength?: number
4343
plaintextLength?: number
4444
}
@@ -54,7 +54,7 @@ export function encryptStream (
5454
cmm: KeyringNode|NodeMaterialsManager,
5555
op: EncryptStreamInput = {}
5656
): Duplex {
57-
const { suiteId, context, frameLength = FRAME_LENGTH } = op
57+
const { suiteId, encryptionContext = {}, frameLength = FRAME_LENGTH } = op
5858

5959
/* If the cmm is a Keyring, wrap it with NodeDefaultCryptographicMaterialsManager. */
6060
cmm = cmm instanceof KeyringNode
@@ -65,11 +65,11 @@ export function encryptStream (
6565

6666
const wrappingStream = new Duplexify()
6767

68-
cmm.getEncryptionMaterials({ suite, encryptionContext: context, frameLength })
69-
.then(async ({ material, context }) => {
68+
cmm.getEncryptionMaterials({ suite, encryptionContext, frameLength })
69+
.then(async ({ material }) => {
7070
const { dispose, getSigner } = getEncryptHelper(material)
7171

72-
const { getCipher, messageHeader, rawHeader } = getEncryptionInfo(material, frameLength, context)
72+
const { getCipher, messageHeader, rawHeader } = getEncryptionInfo(material, frameLength)
7373

7474
wrappingStream.emit('MessageHeader', messageHeader)
7575

@@ -90,8 +90,9 @@ export function encryptStream (
9090
return wrappingStream
9191
}
9292

93-
export function getEncryptionInfo (material : NodeEncryptionMaterial, frameLength: number, context: EncryptionContext) {
93+
export function getEncryptionInfo (material : NodeEncryptionMaterial, frameLength: number) {
9494
const { kdfGetCipher } = getEncryptHelper(material)
95+
const { encryptionContext } = material
9596

9697
const messageId = randomBytes(MESSAGE_ID_LENGTH)
9798
const { id, ivLength } = material.suite
@@ -100,7 +101,7 @@ export function getEncryptionInfo (material : NodeEncryptionMaterial, frameLengt
100101
type: ObjectType.CUSTOMER_AE_DATA,
101102
suiteId: id,
102103
messageId,
103-
encryptionContext: context,
104+
encryptionContext,
104105
encryptedDataKeys: Object.freeze(material.encryptedDataKeys), // freeze me please
105106
contentType: ContentType.FRAMED_DATA,
106107
headerIvLength: ivLength,

0 commit comments

Comments
 (0)