Skip to content

fix: Encryption Context changes #148

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

Merged
merged 15 commits into from
Jul 26, 2019
Merged
Show file tree
Hide file tree
Changes from 2 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
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,13 @@ export function buildCryptographicMaterialsCacheKeyHelpers<S extends SupportedAl
return hashes.sort(compare)
}

function encryptionContextHash (context?: EncryptionContext) {
function encryptionContextHash (context: EncryptionContext) {
/* The AAD section is uInt16BE(length) + AAD
* see: https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/message-format.html#header-aad
* However, the RAW Keyring wants _only_ the ADD.
* So, I just slice off the length.
*/
const serializedContext = serializeEncryptionContext(context || {}).slice(2)
const serializedContext = serializeEncryptionContext(context).slice(2)
return sha512(serializedContext)
}
}
Expand All @@ -105,5 +105,5 @@ export interface CryptographicMaterialsCacheKeyHelpersInterface<S extends Suppor
{ suite, encryptedDataKeys, encryptionContext }: DecryptionRequest<S>
): Promise<string>
encryptedDataKeysHash(encryptedDataKeys: ReadonlyArray<EncryptedDataKey>): Promise<Uint8Array[]>
encryptionContextHash(context?: EncryptionContext): Promise<Uint8Array>
encryptionContextHash(context: EncryptionContext): Promise<Uint8Array>
}
23 changes: 12 additions & 11 deletions modules/cache-material/src/clone_cryptographic_material.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,23 @@ import {
WebCryptoEncryptionMaterial,
WebCryptoDecryptionMaterial,
isEncryptionMaterial,
isDecryptionMaterial
isDecryptionMaterial,
NodeAlgorithmSuite

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

type Material = NodeEncryptionMaterial|NodeDecryptionMaterial|WebCryptoEncryptionMaterial|WebCryptoDecryptionMaterial

export function cloneMaterial<M extends Material> (source: M): M {
const clone = source instanceof NodeEncryptionMaterial
? new NodeEncryptionMaterial(source.suite)
: source instanceof NodeDecryptionMaterial
? new NodeDecryptionMaterial(source.suite)
: source instanceof WebCryptoEncryptionMaterial
? new WebCryptoEncryptionMaterial(source.suite)
: source instanceof WebCryptoDecryptionMaterial
? new WebCryptoDecryptionMaterial(source.suite)
: false
const { suite, encryptionContext } = source

if (!clone) throw new Error('Unsupported material type')
const clone = suite instanceof NodeAlgorithmSuite
? source instanceof NodeEncryptionMaterial
? new NodeEncryptionMaterial(suite, encryptionContext)
: new NodeDecryptionMaterial(suite, encryptionContext)
: source instanceof WebCryptoEncryptionMaterial
? new WebCryptoEncryptionMaterial(suite, encryptionContext)
: new WebCryptoDecryptionMaterial(suite, encryptionContext)

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

return <M>clone
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,12 +207,12 @@ describe('Cryptographic Material Functions', () => {
const edk1 = new EncryptedDataKey({ providerId: 'keyNamespace', providerInfo: 'keyName', encryptedDataKey: new Uint8Array([1]) })
const edk2 = new EncryptedDataKey({ providerId: 'p2', providerInfo: 'pi2', encryptedDataKey: new Uint8Array([2]) })

const encryptionMaterial = new NodeEncryptionMaterial(nodeSuite)
const encryptionMaterial = new NodeEncryptionMaterial(nodeSuite, {})
.setUnencryptedDataKey(udk128, trace)
.addEncryptedDataKey(edk1, KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY)
.addEncryptedDataKey(edk2, KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY)

const decryptionMaterial = new NodeDecryptionMaterial(nodeSuite)
const decryptionMaterial = new NodeDecryptionMaterial(nodeSuite, {})
.setUnencryptedDataKey(udk128, trace)

const context = {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const cryptoKey: any = { type: 'secret', algorithm: { name: webCryptoSuite.encry

describe('cloneMaterial', () => {
it('clone NodeEncryptionMaterial', () => {
const material = new NodeEncryptionMaterial(nodeSuite)
const material = new NodeEncryptionMaterial(nodeSuite, { some: 'context' })
.setUnencryptedDataKey(udk128, trace)
.addEncryptedDataKey(edk1, KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY)
.addEncryptedDataKey(edk2, KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY)
Expand All @@ -56,20 +56,22 @@ describe('cloneMaterial', () => {
expect(test.getUnencryptedDataKey()).to.deep.equal(udk128)
expect(test.keyringTrace).to.deep.equal(material.keyringTrace)
expect(test.encryptedDataKeys).to.deep.equal(material.encryptedDataKeys)
expect(test.encryptionContext).to.deep.equal(material.encryptionContext)
})

it('clone NodeDecryptionMaterial', () => {
const material = new NodeDecryptionMaterial(nodeSuite)
const material = new NodeDecryptionMaterial(nodeSuite, { some: 'context' })
.setUnencryptedDataKey(udk128, trace)

const test = cloneMaterial(material)
expect(test).to.be.instanceOf(NodeDecryptionMaterial)
expect(test.getUnencryptedDataKey()).to.deep.equal(udk128)
expect(test.keyringTrace).to.deep.equal(material.keyringTrace)
expect(test.encryptionContext).to.deep.equal(material.encryptionContext)
})

it('clone WebCryptoEncryptionMaterial', () => {
const material = new WebCryptoEncryptionMaterial(webCryptoSuite)
const material = new WebCryptoEncryptionMaterial(webCryptoSuite, { some: 'context' })
.setUnencryptedDataKey(udk128, trace)
.setCryptoKey(cryptoKey, trace)
.addEncryptedDataKey(edk1, KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY)
Expand All @@ -81,10 +83,11 @@ describe('cloneMaterial', () => {
expect(test.getCryptoKey()).to.deep.equal(cryptoKey)
expect(test.keyringTrace).to.deep.equal(material.keyringTrace)
expect(test.encryptedDataKeys).to.deep.equal(material.encryptedDataKeys)
expect(test.encryptionContext).to.deep.equal(material.encryptionContext)
})

it('clone WebCryptoDecryptionMaterial', () => {
const material = new WebCryptoDecryptionMaterial(webCryptoSuite)
const material = new WebCryptoDecryptionMaterial(webCryptoSuite, { some: 'context' })
.setUnencryptedDataKey(udk128, trace)
.setCryptoKey(cryptoKey, trace)

Expand All @@ -93,5 +96,6 @@ describe('cloneMaterial', () => {
expect(test.getUnencryptedDataKey()).to.deep.equal(udk128)
expect(test.getCryptoKey()).to.deep.equal(cryptoKey)
expect(test.keyringTrace).to.deep.equal(material.keyringTrace)
expect(test.encryptionContext).to.deep.equal(material.encryptionContext)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import {
} from '@aws-crypto/material-management'

const nodeSuite = new NodeAlgorithmSuite(AlgorithmSuiteIdentifier.ALG_AES128_GCM_IV12_TAG16_HKDF_SHA256)
const encryptionMaterial = new NodeEncryptionMaterial(nodeSuite)
const decryptionMaterial = new NodeDecryptionMaterial(nodeSuite)
const encryptionMaterial = new NodeEncryptionMaterial(nodeSuite, {})
const decryptionMaterial = new NodeDecryptionMaterial(nodeSuite, {})

describe('getLocalCryptographicMaterialsCache', () => {
const {
Expand All @@ -41,8 +41,7 @@ describe('getLocalCryptographicMaterialsCache', () => {
it('putEncryptionResponse', () => {
const key = 'some encryption key'
const response: any = {
material: encryptionMaterial,
context: {}
material: encryptionMaterial
}

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

it('Precondition: putEncryptionResponse plaintextLength can not be negative.', () => {
const response: any = {
material: encryptionMaterial,
context: {}
material: encryptionMaterial
}
const u: any = undefined
const s: any = 'not-number'
Expand All @@ -70,8 +68,7 @@ describe('getLocalCryptographicMaterialsCache', () => {
it('Postcondition: Only return EncryptionMaterial.', () => {
const key = 'some decryption key'
const response: any = {
material: decryptionMaterial,
context: {}
material: decryptionMaterial
}

putDecryptionResponse(key, response)
Expand All @@ -82,8 +79,7 @@ describe('getLocalCryptographicMaterialsCache', () => {
const key = 'some encryption key'
const suite = new NodeAlgorithmSuite(AlgorithmSuiteIdentifier.ALG_AES128_GCM_IV12_TAG16)
const response: any = {
material: new NodeEncryptionMaterial(suite),
context: {}
material: new NodeEncryptionMaterial(suite, {})
}

expect(() => putEncryptionResponse(key, response, 1)).to.throw()
Expand All @@ -92,8 +88,7 @@ describe('getLocalCryptographicMaterialsCache', () => {
it('putDecryptionResponse', () => {
const key = 'some decryption key'
const response: any = {
material: decryptionMaterial,
context: {}
material: decryptionMaterial
}

putDecryptionResponse(key, response)
Expand All @@ -108,8 +103,7 @@ describe('getLocalCryptographicMaterialsCache', () => {
it('Precondition: Only cache DecryptionMaterial.', () => {
const key = 'some decryption key'
const response: any = {
material: 'not material',
context: {}
material: 'not material'
}

expect(() => putDecryptionResponse(key, response)).to.throw()
Expand All @@ -119,8 +113,7 @@ describe('getLocalCryptographicMaterialsCache', () => {
const key = 'some decryption key'
const suite = new NodeAlgorithmSuite(AlgorithmSuiteIdentifier.ALG_AES128_GCM_IV12_TAG16)
const response: any = {
material: new NodeEncryptionMaterial(suite),
context: {}
material: new NodeEncryptionMaterial(suite, {})
}

expect(() => putDecryptionResponse(key, response)).to.throw()
Expand All @@ -143,8 +136,7 @@ describe('getLocalCryptographicMaterialsCache', () => {
it('Precondition: Only cache EncryptionMaterial.', () => {
const key = 'some encryption key'
const response: any = {
material: 'not material',
context: {}
material: 'not material'
}

expect(() => putEncryptionResponse(key, response, 1)).to.throw()
Expand All @@ -158,8 +150,7 @@ describe('getLocalCryptographicMaterialsCache', () => {
it('Postcondition: Only return DecryptionMaterial.', () => {
const key = 'some encryption key'
const response: any = {
material: encryptionMaterial,
context: {}
material: encryptionMaterial
}

putEncryptionResponse(key, response, 1)
Expand All @@ -173,8 +164,7 @@ describe('getLocalCryptographicMaterialsCache', () => {
it('zero is an acceptable plaintextLength', () => {
const key = 'some encryption key'
const response: any = {
material: encryptionMaterial,
context: {}
material: encryptionMaterial
}

putEncryptionResponse(key, response, 0)
Expand All @@ -197,8 +187,7 @@ describe('cache eviction', () => {
const key1 = 'key lost'
const key2 = 'key replace'
const response: any = {
material: decryptionMaterial,
context: {}
material: decryptionMaterial
}

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

const key = 'key deleted'
const response: any = {
material: decryptionMaterial,
context: {}
material: decryptionMaterial
}

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

const key = 'key lost'
const response: any = {
material: decryptionMaterial,
context: {}
material: decryptionMaterial
}

putDecryptionResponse(key, response, 1)
Expand All @@ -255,8 +242,7 @@ describe('cache eviction', () => {
const key1 = 'key lost'
const key2 = 'key replace'
const response: any = {
material: encryptionMaterial,
context: {}
material: encryptionMaterial
}

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

const key = 'key lost'
const response: any = {
material: encryptionMaterial,
context: {}
material: encryptionMaterial
}

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

const key = 'key lost'
const response: any = {
material: encryptionMaterial,
context: {}
material: encryptionMaterial
}

putEncryptionResponse(key, response, 1, 1)
Expand Down
6 changes: 3 additions & 3 deletions modules/encrypt-browser/src/encrypt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export interface EncryptResult {
export async function encrypt (
cmm: KeyringWebCrypto|WebCryptoMaterialsManager,
plaintext: Uint8Array,
{ suiteId, encryptionContext, frameLength = FRAME_LENGTH }: EncryptInput = {}
{ suiteId, encryptionContext = {}, frameLength = FRAME_LENGTH }: EncryptInput = {}
): Promise<EncryptResult> {
const backend = await getWebCryptoBackend()
if (!backend) throw new Error('No supported crypto backend')
Expand All @@ -79,7 +79,7 @@ export async function encrypt (
plaintextLength
}

const { material, context } = await cmm.getEncryptionMaterials(encryptionRequest)
const { material } = await cmm.getEncryptionMaterials(encryptionRequest)
const { kdfGetSubtleEncrypt, subtleSign, dispose } = await getEncryptHelper(material)

const messageId = await backend.randomValues(MESSAGE_ID_LENGTH)
Expand All @@ -91,7 +91,7 @@ export async function encrypt (
type: ObjectType.CUSTOMER_AE_DATA,
suiteId: id,
messageId,
encryptionContext: context,
encryptionContext: material.encryptionContext,
encryptedDataKeys: material.encryptedDataKeys,
contentType: ContentType.FRAMED_DATA,
headerIvLength: ivLength,
Expand Down
15 changes: 8 additions & 7 deletions modules/encrypt-node/src/encrypt_stream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const { serializeMessageHeader, headerAuthIv } = serializeFactory(fromUtf8)

export interface EncryptStreamInput {
suiteId?: AlgorithmSuiteIdentifier
context?: EncryptionContext
encryptionContext?: EncryptionContext
frameLength?: number
plaintextLength?: number
}
Expand All @@ -54,7 +54,7 @@ export function encryptStream (
cmm: KeyringNode|NodeMaterialsManager,
op: EncryptStreamInput = {}
): Duplex {
const { suiteId, context, frameLength = FRAME_LENGTH } = op
const { suiteId, encryptionContext = {}, frameLength = FRAME_LENGTH } = op

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

const wrappingStream = new Duplexify()

cmm.getEncryptionMaterials({ suite, encryptionContext: context, frameLength })
.then(async ({ material, context }) => {
cmm.getEncryptionMaterials({ suite, encryptionContext, frameLength })
.then(async ({ material }) => {
const { dispose, getSigner } = getEncryptHelper(material)

const { getCipher, messageHeader, rawHeader } = getEncryptionInfo(material, frameLength, context)
const { getCipher, messageHeader, rawHeader } = getEncryptionInfo(material, frameLength)

wrappingStream.emit('MessageHeader', messageHeader)

Expand All @@ -90,8 +90,9 @@ export function encryptStream (
return wrappingStream
}

export function getEncryptionInfo (material : NodeEncryptionMaterial, frameLength: number, context: EncryptionContext) {
export function getEncryptionInfo (material : NodeEncryptionMaterial, frameLength: number) {
const { kdfGetCipher } = getEncryptHelper(material)
const { encryptionContext } = material

const messageId = randomBytes(MESSAGE_ID_LENGTH)
const { id, ivLength } = material.suite
Expand All @@ -100,7 +101,7 @@ export function getEncryptionInfo (material : NodeEncryptionMaterial, frameLengt
type: ObjectType.CUSTOMER_AE_DATA,
suiteId: id,
messageId,
encryptionContext: context,
encryptionContext,
encryptedDataKeys: Object.freeze(material.encryptedDataKeys), // freeze me please
contentType: ContentType.FRAMED_DATA,
headerIvLength: ivLength,
Expand Down
Loading