Skip to content

Commit

Permalink
Release 2.2.0 (#613)
Browse files Browse the repository at this point in the history
  • Loading branch information
seebees authored May 27, 2021
1 parent 06211c8 commit 43813f4
Show file tree
Hide file tree
Showing 99 changed files with 18,236 additions and 24,637 deletions.
3 changes: 2 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[submodule "aws-encryption-sdk-test-vectors"]
path = aws-encryption-sdk-test-vectors
url = https://github.com/awslabs/aws-encryption-sdk-test-vectors.git
url = https://github.com/awslabs/private-aws-encryption-sdk-test-vectors-staging.git
branch = known-invalid-test-vectors
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ A multi keyring can be used to compose keyrings together.
### Wrapping Keys

Wrapping keys are used to protect data keys.
An example of a wrapping key is a `KMS customer master key (CMK)`_.
An example of a wrapping key is a `KMS customer master key (CMK)`.

### Data Keys

Expand Down
2 changes: 1 addition & 1 deletion aws-encryption-sdk-test-vectors
11 changes: 7 additions & 4 deletions modules/client-browser/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,19 @@ export * from '@aws-crypto/raw-aes-keyring-browser'
export * from '@aws-crypto/raw-rsa-keyring-browser'
export * from '@aws-crypto/web-crypto-backend'

import { CommitmentPolicy } from '@aws-crypto/material-management-browser'
import {
CommitmentPolicy,
ClientOptions,
} from '@aws-crypto/material-management-browser'

import { buildEncrypt } from '@aws-crypto/encrypt-browser'
import { buildDecrypt } from '@aws-crypto/decrypt-browser'

export function buildClient(
commitmentPolicy: CommitmentPolicy = CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT
options?: CommitmentPolicy | ClientOptions
): ReturnType<typeof buildEncrypt> & ReturnType<typeof buildDecrypt> {
return {
...buildEncrypt(commitmentPolicy),
...buildDecrypt(commitmentPolicy),
...buildEncrypt(options),
...buildDecrypt(options),
}
}
11 changes: 7 additions & 4 deletions modules/client-node/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,19 @@ export * from '@aws-crypto/kms-keyring-node'
export * from '@aws-crypto/raw-aes-keyring-node'
export * from '@aws-crypto/raw-rsa-keyring-node'

import { CommitmentPolicy } from '@aws-crypto/material-management-node'
import {
CommitmentPolicy,
ClientOptions,
} from '@aws-crypto/material-management-node'

import { buildEncrypt } from '@aws-crypto/encrypt-node'
import { buildDecrypt } from '@aws-crypto/decrypt-node'

export function buildClient(
commitmentPolicy: CommitmentPolicy = CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT
options?: CommitmentPolicy | ClientOptions
): ReturnType<typeof buildEncrypt> & ReturnType<typeof buildDecrypt> {
return {
...buildEncrypt(commitmentPolicy),
...buildDecrypt(commitmentPolicy),
...buildEncrypt(options),
...buildDecrypt(options),
}
}
14 changes: 12 additions & 2 deletions modules/decrypt-browser/src/decrypt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
WebCryptoMaterialsManager,
CommitmentPolicy,
CommitmentPolicySuites,
ClientOptions,
} from '@aws-crypto/material-management-browser'
import {
deserializeSignature,
Expand All @@ -34,20 +35,29 @@ export interface DecryptResult {
}

export async function _decrypt(
commitmentPolicy: CommitmentPolicy,
{ commitmentPolicy, maxEncryptedDataKeys }: ClientOptions,
cmm: KeyringWebCrypto | WebCryptoMaterialsManager,
ciphertext: Uint8Array
): Promise<DecryptResult> {
/* Precondition: _decrypt needs a valid commitmentPolicy. */
needs(CommitmentPolicy[commitmentPolicy], 'Invalid commitment policy.')

// buildDecrypt defaults this to false for backwards compatibility, so this is satisfied
/* Precondition: _decrypt needs a valid maxEncryptedDataKeys. */
needs(
maxEncryptedDataKeys === false || maxEncryptedDataKeys >= 1,
'Invalid maxEncryptedDataKeys value.'
)

/* If the cmm is a Keyring, wrap it with WebCryptoDefaultCryptographicMaterialsManager. */
cmm =
cmm instanceof KeyringWebCrypto
? new WebCryptoDefaultCryptographicMaterialsManager(cmm)
: cmm

const headerInfo = deserialize.deserializeMessageHeader(ciphertext)
const headerInfo = deserialize.deserializeMessageHeader(ciphertext, {
maxEncryptedDataKeys,
})
if (headerInfo === false) throw new Error('Unable to parse Header')
const { messageHeader, algorithmSuite } = headerInfo
const { rawHeader, headerAuth } = headerInfo
Expand Down
20 changes: 18 additions & 2 deletions modules/decrypt-browser/src/decrypt_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { _decrypt } from './decrypt'
import {
CommitmentPolicy,
ClientOptions,
needs,
} from '@aws-crypto/material-management-browser'

Expand All @@ -15,13 +16,28 @@ type CurryFirst<fn extends (...a: any[]) => any> = fn extends (
: []

export function buildDecrypt(
commitmentPolicy: CommitmentPolicy = CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT
options: CommitmentPolicy | Partial<ClientOptions> = {}
): {
decrypt: (...args: CurryFirst<typeof _decrypt>) => ReturnType<typeof _decrypt>
} {
const {
commitmentPolicy = CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT,
maxEncryptedDataKeys = false,
} = typeof options === 'string' ? { commitmentPolicy: options } : options

/* Precondition: browser buildDecrypt needs a valid commitmentPolicy. */
needs(CommitmentPolicy[commitmentPolicy], 'Invalid commitment policy.')
/* Precondition: browser buildDecrypt needs a valid maxEncryptedDataKeys. */
needs(
maxEncryptedDataKeys === false || maxEncryptedDataKeys >= 1,
'Invalid maxEncryptedDataKeys value.'
)

const clientOptions: ClientOptions = {
commitmentPolicy,
maxEncryptedDataKeys,
}
return {
decrypt: _decrypt.bind({}, commitmentPolicy),
decrypt: _decrypt.bind({}, clientOptions),
}
}
1 change: 1 addition & 0 deletions modules/decrypt-browser/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
// SPDX-License-Identifier: Apache-2.0

export { buildDecrypt } from './decrypt_client'
export { DecryptResult } from './decrypt'
export { MessageHeader } from '@aws-crypto/serialize'
64 changes: 61 additions & 3 deletions modules/decrypt-browser/test/decrypt.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
/* eslint-env mocha */

import * as chai from 'chai'
// @ts-ignore
import chaiAsPromised from 'chai-as-promised'
import { buildDecrypt } from '../src/index'
import { _decrypt } from '../src/decrypt'
Expand Down Expand Up @@ -44,14 +45,34 @@ describe('decrypt', () => {

it('Precondition: _decrypt needs a valid commitmentPolicy.', async () => {
await expect(
_decrypt('fake_policy' as any, {} as any, {} as any)
_decrypt(
{ commitmentPolicy: 'fake_policy' as any, maxEncryptedDataKeys: false },
{} as any,
{} as any
)
).to.rejectedWith(Error, 'Invalid commitment policy.')
})

it('Precondition: _decrypt needs a valid maxEncryptedDataKeys.', async () => {
await expect(
_decrypt(
{
commitmentPolicy: CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT,
maxEncryptedDataKeys: 0,
},
{} as any,
{} as any
)
).to.rejectedWith(Error, 'Invalid maxEncryptedDataKeys value.')
})

it('Precondition: The parsed header algorithmSuite in _decrypt must be supported by the commitmentPolicy.', async () => {
await expect(
_decrypt(
CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT,
{
commitmentPolicy: CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT,
maxEncryptedDataKeys: false,
},
fixtures.decryptKeyring(),
fixtures.base64CiphertextAlgAes256GcmIv12Tag16HkdfSha384EcdsaP384With4Frames()
)
Expand All @@ -74,7 +95,10 @@ describe('decrypt', () => {
} as any
await expect(
_decrypt(
CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT,
{
commitmentPolicy: CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT,
maxEncryptedDataKeys: false,
},
cmm,
fromBase64(fixtures.compatibilityVectors().tests[0].ciphertext)
)
Expand Down Expand Up @@ -142,6 +166,40 @@ describe('decrypt', () => {
await expect(decrypt(keyring, data.slice(0, i))).to.rejectedWith(Error)
}
})

it('can decrypt data with less than maxEncryptedDataKeys', async () => {
const { decrypt } = buildDecrypt({
commitmentPolicy: CommitmentPolicy.FORBID_ENCRYPT_ALLOW_DECRYPT,
maxEncryptedDataKeys: 3,
})
const { plaintext } = await decrypt(
fixtures.decryptKeyring(),
fixtures.twoEdksMessage()
)
expect(plaintext).to.deep.equal(Buffer.from('asdf'))
})

it('can decrypt data with exactly maxEncryptedDataKeys', async () => {
const { decrypt } = buildDecrypt({
commitmentPolicy: CommitmentPolicy.FORBID_ENCRYPT_ALLOW_DECRYPT,
maxEncryptedDataKeys: 3,
})
const { plaintext } = await decrypt(
fixtures.decryptKeyring(),
fixtures.threeEdksMessage()
)
expect(plaintext).to.deep.equal(Buffer.from('asdf'))
})

it('will not decrypt data with more than maxEncryptedDataKeys', async () => {
const { decrypt } = buildDecrypt({
commitmentPolicy: CommitmentPolicy.FORBID_ENCRYPT_ALLOW_DECRYPT,
maxEncryptedDataKeys: 3,
})
await expect(
decrypt(fixtures.decryptKeyring(), fixtures.fourEdksMessage())
).to.rejectedWith(Error, 'maxEncryptedDataKeys exceeded.')
})
})

// prettier-ignore
Expand Down
26 changes: 25 additions & 1 deletion modules/decrypt-browser/test/decrypt_client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
/* eslint-env mocha */

import * as chai from 'chai'
// @ts-ignore
import chaiAsPromised from 'chai-as-promised'
import { CommitmentPolicy } from '@aws-crypto/material-management-node'
import { buildDecrypt } from '../src/index'
Expand All @@ -13,11 +14,34 @@ const { expect } = chai

describe('buildDecrypt', () => {
it('can build a client', () => {
const test = buildDecrypt()
expect(test).to.have.property('decrypt').and.to.be.a('function')
})

it('can build a client with a commitment policy', () => {
const test = buildDecrypt(CommitmentPolicy.FORBID_ENCRYPT_ALLOW_DECRYPT)
expect(test).to.have.property('decrypt').and.to.be.a('function')
})

it('can build a client with max encrypted data keys', () => {
for (const numKeys of [1, 10, Math.pow(2, 16) - 1, Math.pow(2, 16)]) {
const test = buildDecrypt({ maxEncryptedDataKeys: numKeys })
expect(test).to.have.property('decrypt').and.to.be.a('function')
}
})

it('Precondition: browser buildDecrypt needs a valid commitmentPolicy.', () => {
expect(() => buildDecrypt({} as any)).to.throw('Invalid commitment policy.')
expect(() => buildDecrypt('BAD_POLICY' as any)).to.throw(
'Invalid commitment policy.'
)
})

it('Precondition: browser buildDecrypt needs a valid maxEncryptedDataKeys.', () => {
expect(() => buildDecrypt({ maxEncryptedDataKeys: 0 })).to.throw(
'Invalid maxEncryptedDataKeys value.'
)
expect(() => buildDecrypt({ maxEncryptedDataKeys: -1 })).to.throw(
'Invalid maxEncryptedDataKeys value.'
)
})
})
21 changes: 21 additions & 0 deletions modules/decrypt-browser/test/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,27 @@ export function frameSequenceOutOfOrder() {
])
}

export function twoEdksMessage() {
// prettier-ignore
return new Uint8Array([
1,128,0,20,81,159,165,226,136,253,2,91,121,212,103,155,181,101,192,42,0,0,0,2,0,4,116,101,109,112,0,24,107,101,121,49,0,0,0,128,0,0,0,12,253,51,172,10,239,164,139,246,179,46,90,151,0,32,112,49,205,185,161,227,110,112,214,205,129,210,255,139,70,54,55,191,225,87,28,109,71,168,124,168,187,90,185,220,183,111,0,4,116,101,109,112,0,24,107,101,121,48,0,0,0,128,0,0,0,12,130,105,57,211,107,129,63,61,28,113,29,245,0,32,223,169,9,70,195,85,36,140,164,225,228,190,70,137,36,66,153,118,45,227,30,48,41,64,4,38,172,46,186,38,100,204,2,0,0,0,0,12,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,241,48,199,72,160,81,240,122,45,194,9,196,238,161,95,137,255,255,255,255,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,4,15,114,189,86,167,87,157,63,128,15,95,53,55,99,185,59,74,12,150,52
])
}

export function threeEdksMessage() {
// prettier-ignore
return new Uint8Array([
1,128,0,20,6,147,84,28,195,247,246,16,92,66,254,35,91,134,21,113,0,0,0,3,0,4,116,101,109,112,0,24,107,101,121,50,0,0,0,128,0,0,0,12,243,10,221,12,30,48,159,193,178,76,143,111,0,32,164,227,105,185,29,231,91,130,47,214,222,135,16,165,55,47,97,135,251,159,33,232,143,25,70,73,55,217,248,216,69,44,0,4,116,101,109,112,0,24,107,101,121,48,0,0,0,128,0,0,0,12,146,167,240,23,105,252,154,26,125,18,74,76,0,32,243,219,32,78,83,237,209,122,150,92,241,94,91,201,171,7,110,218,233,15,20,56,246,15,48,131,41,225,114,157,197,252,0,4,116,101,109,112,0,24,107,101,121,49,0,0,0,128,0,0,0,12,215,162,33,39,252,66,105,179,78,16,42,232,0,32,30,167,255,38,200,18,212,153,115,229,175,89,11,101,31,244,6,146,25,12,80,32,22,53,53,63,239,107,104,139,65,167,2,0,0,0,0,12,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,25,251,17,157,236,34,27,100,13,10,155,194,218,166,195,57,255,255,255,255,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,4,15,114,189,86,231,188,115,162,175,197,222,3,249,202,81,98,227,231,67,146
])
}

export function fourEdksMessage() {
// prettier-ignore
return new Uint8Array([
1,128,0,20,152,195,218,126,82,140,170,75,107,29,97,41,37,39,140,194,0,0,0,4,0,4,116,101,109,112,0,24,107,101,121,50,0,0,0,128,0,0,0,12,232,117,224,17,241,139,48,60,112,45,223,30,0,32,90,160,47,236,89,127,74,188,210,95,186,61,117,166,82,207,243,171,211,192,190,29,63,83,198,122,54,25,74,198,123,0,0,4,116,101,109,112,0,24,107,101,121,48,0,0,0,128,0,0,0,12,179,67,229,65,157,148,209,70,133,50,200,225,0,32,114,101,189,108,89,151,6,211,84,211,236,72,253,45,230,183,9,40,79,146,106,109,224,46,254,102,50,129,174,123,49,247,0,4,116,101,109,112,0,24,107,101,121,49,0,0,0,128,0,0,0,12,122,245,182,159,26,134,245,191,73,101,240,68,0,32,6,247,51,137,165,160,143,119,82,111,242,247,21,58,45,184,62,75,131,72,192,43,205,106,120,75,40,128,102,165,73,128,0,4,116,101,109,112,0,24,107,101,121,51,0,0,0,128,0,0,0,12,58,191,161,65,150,32,99,20,197,143,126,208,0,32,179,18,132,26,48,25,198,187,236,47,191,24,24,153,205,76,158,181,61,82,249,110,192,95,153,90,0,113,113,142,36,173,2,0,0,0,0,12,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,215,170,96,229,229,32,220,210,179,153,146,71,139,224,7,208,255,255,255,255,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,4,15,114,189,86,12,123,234,170,45,72,187,11,199,119,21,216,211,21,95,51
])
}

class TestKeyring extends KeyringWebCrypto {
async _onEncrypt(): Promise<WebCryptoEncryptionMaterial> {
throw new Error('I should never see this error')
Expand Down
2 changes: 1 addition & 1 deletion modules/decrypt-node/src/decipher_stream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export function getDecipherStream() {
decipherState.contentLength -= chunk.length
/* Precondition: Only content should be transformed, so the lengths must always match.
* The BodyHeader and AuthTag are striped in the VerifyStream and passed in
* through events. This means that if I receive a chunk without havening reset
* through events. This means that if I receive a chunk without having reset
* the content accumulation events are out of order. Panic.
*/
needs(decipherState.contentLength >= 0, 'Lengths do not match')
Expand Down
8 changes: 5 additions & 3 deletions modules/decrypt-node/src/decrypt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
import {
NodeMaterialsManager,
KeyringNode,
CommitmentPolicy,
} from '@aws-crypto/material-management-node'
import { _decryptStream } from './decrypt_stream'
import { DecryptParameters } from './types'

// @ts-ignore
import { finished } from 'readable-stream'
Expand All @@ -24,12 +24,14 @@ export interface DecryptOptions {
}

export async function _decrypt(
commitmentPolicy: CommitmentPolicy,
decryptParameters: DecryptParameters,
cmm: NodeMaterialsManager | KeyringNode,
ciphertext: Buffer | Uint8Array | Readable | string | NodeJS.ReadableStream,
{ encoding, maxBodySize }: DecryptOptions = {}
): Promise<DecryptOutput> {
const stream = _decryptStream(commitmentPolicy, cmm, { maxBodySize })
const stream = _decryptStream(decryptParameters, cmm, {
maxBodySize,
})

const plaintext: Buffer[] = []
let messageHeader: MessageHeader | false = false
Expand Down
Loading

0 comments on commit 43813f4

Please sign in to comment.