Skip to content

Commit cf464c6

Browse files
committed
Add H-Keyring vectors
1 parent ff3aad6 commit cf464c6

File tree

3 files changed

+311
-50
lines changed

3 files changed

+311
-50
lines changed

modules/decrypt-node/test/compatibility.test.ts

Lines changed: 187 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -12,53 +12,46 @@ import {
1212
NodeDecryptionMaterial,
1313
NodeEncryptionMaterial,
1414
} from '@aws-crypto/material-management-node'
15-
import { buildDecrypt } from '../src/index'
15+
import { buildDecrypt, DecryptOutput } from '../src/index'
16+
import { buildEncrypt } from '@aws-crypto/encrypt-node'
1617
import * as fixtures from './fixtures'
1718
chai.use(chaiAsPromised)
1819
const { expect } = chai
1920
import {
21+
AlgorithmSuiteIdentifier,
2022
CommitmentPolicy,
2123
MessageFormat,
2224
needs,
25+
NodeBranchKeyMaterial,
2326
} from '@aws-crypto/material-management'
2427

25-
import { KmsKeyringNode } from '@aws-crypto/kms-keyring-node'
28+
import {
29+
KmsHierarchicalKeyRingNode,
30+
KmsKeyringNode,
31+
} from '@aws-crypto/kms-keyring-node'
32+
import { BranchKeyStoreNode } from '@aws-crypto/branch-keystore-node'
33+
34+
import { deserializeFactory } from '@aws-crypto/serialize'
35+
import { NodeAlgorithmSuite } from '@aws-crypto/material-management-node'
36+
import { readFileSync, writeFileSync } from 'fs'
37+
const toUtf8 = (input: Uint8Array) =>
38+
Buffer.from(input.buffer, input.byteOffset, input.byteLength).toString('utf8')
39+
const deserialize = deserializeFactory(toUtf8, NodeAlgorithmSuite)
2640

2741
const { decrypt } = buildDecrypt(CommitmentPolicy.FORBID_ENCRYPT_ALLOW_DECRYPT)
42+
const { encrypt } = buildEncrypt(CommitmentPolicy.REQUIRE_ENCRYPT_ALLOW_DECRYPT)
2843

2944
describe('committing algorithm test', () => {
3045
fixtures.compatibilityVectors().tests.forEach((test) => {
3146
it(test.comment, async () => {
32-
const {
33-
ciphertext,
34-
status,
35-
'plaintext-frames': plaintextFrames,
36-
commitment,
37-
'message-id': messageId,
38-
'encryption-context': encryptionContext,
39-
} = test
47+
const { ciphertext, status } = test
4048
const keyring = buildKeyring(test)
4149
if (status) {
42-
const { plaintext, messageHeader } = await decrypt(
43-
keyring,
44-
ciphertext,
45-
{
46-
encoding: 'base64',
47-
}
48-
)
49-
needs(
50-
plaintextFrames && messageHeader.version === MessageFormat.V2,
51-
'Message Failure'
52-
)
53-
54-
expect(plaintext.toString()).to.equal(plaintextFrames.join(''))
55-
expect(
56-
Buffer.from(messageHeader.suiteData).toString('base64')
57-
).to.deep.equal(commitment)
58-
expect(
59-
Buffer.from(messageHeader.messageId).toString('base64')
60-
).to.deep.equal(messageId)
61-
expect(messageHeader.encryptionContext).to.deep.equal(encryptionContext)
50+
const output = await decrypt(keyring, ciphertext, {
51+
encoding: 'base64',
52+
})
53+
54+
ExpectCompatibilityVector(test, output)
6255
} else {
6356
await expect(
6457
decrypt(keyring, ciphertext, { encoding: 'base64' })
@@ -67,26 +60,172 @@ describe('committing algorithm test', () => {
6760
})
6861
})
6962

63+
fixtures.hierarchicalKeyringCompatibilityVectors().tests.forEach((test) => {
64+
it(`Decrypt test: ${test.comment}`, async () => {
65+
const { ciphertext, status } = test
66+
const keyring = buildKeyring(test)
67+
needs(status, 'Unexpected Status')
68+
const output = await decrypt(keyring, ciphertext, {
69+
encoding: 'base64',
70+
})
71+
72+
ExpectCompatibilityVector(test, output)
73+
})
74+
})
75+
76+
fixtures.hierarchicalKeyringCompatibilityVectors().tests.forEach((test) => {
77+
let once = false
78+
it(`Encrypt test: ${test.comment}`, async () => {
79+
const { plaintextBase64, status } = test
80+
const keyring = buildKeyring(test)
81+
needs(status, 'Unexpected Status')
82+
needs(plaintextBase64, 'Nothing to encrypt')
83+
84+
const suiteId = AlgorithmSuiteIdentifier.ALG_AES256_GCM_IV12_TAG16_HKDF_SHA512_COMMIT_KEY
85+
once = true
86+
87+
const encryptOutput = await encrypt(keyring, plaintextBase64, {
88+
encoding: 'base64',
89+
suiteId,
90+
})
91+
92+
const decryptOutput = await decrypt(keyring, encryptOutput.result)
93+
expect(decryptOutput.plaintext.toString('base64')).to.equal(
94+
plaintextBase64
95+
)
96+
})
97+
})
98+
99+
function ExpectCompatibilityVector(
100+
{
101+
'plaintext-frames': plaintextFrames,
102+
plaintextBase64,
103+
commitment,
104+
'message-id': messageId,
105+
'encryption-context': encryptionContext,
106+
}: fixtures.VectorTest,
107+
{ plaintext, messageHeader }: DecryptOutput
108+
) {
109+
needs(messageHeader.version === MessageFormat.V2, 'Message Failure')
110+
111+
if (plaintextBase64) {
112+
expect(plaintext.toString('base64')).to.equal(plaintextBase64)
113+
}
114+
if (plaintextFrames) {
115+
expect(plaintext.toString()).to.equal(plaintextFrames.join(''))
116+
}
117+
expect(
118+
Buffer.from(messageHeader.suiteData).toString('base64')
119+
).to.deep.equal(commitment)
120+
expect(
121+
Buffer.from(messageHeader.messageId).toString('base64')
122+
).to.deep.equal(messageId)
123+
expect(messageHeader.encryptionContext).to.deep.equal(encryptionContext)
124+
}
125+
70126
function buildKeyring(test: fixtures.VectorTest) {
71-
if (test['keyring-type'] === 'aws-kms') {
72-
return new KmsKeyringNode({ discovery: true })
127+
switch (test['keyring-type']) {
128+
case 'aws-kms':
129+
return new KmsKeyringNode({ discovery: true })
130+
case 'static':
131+
const dataKey = Buffer.alloc(32, test['decrypted-dek'], 'base64')
132+
133+
return new (class TestKeyring extends KeyringNode {
134+
async _onEncrypt(): Promise<NodeEncryptionMaterial> {
135+
throw new Error('I should never see this error')
136+
}
137+
async _onDecrypt(material: NodeDecryptionMaterial) {
138+
const unencryptedDataKey = dataKey
139+
const trace = {
140+
keyNamespace: 'k',
141+
keyName: 'k',
142+
flags: KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY,
143+
}
144+
return material.setUnencryptedDataKey(unencryptedDataKey, trace)
145+
}
146+
})()
147+
148+
case 'static-branch-key':
149+
// This is serious hackery.
150+
// This is *NOT* recommended.
151+
// The proper extension point for the KeyStore is _only_ the Storage interface!
152+
// However, this does let us do some quick test vector testing.
153+
// At this time this is overly perscriptive,
154+
// but the expectation is to be able to depracate this
155+
// in favor of the test vectors project (integration-node)
156+
const keyStore = {
157+
__proto__: BranchKeyStoreNode.prototype,
158+
kmsConfiguration: {
159+
getRegion() {
160+
return null
161+
},
162+
},
163+
164+
getKeyStoreInfo() {
165+
return {
166+
logicalKeyStoreName: 'logicalKeyStoreName',
167+
}
168+
},
169+
170+
async getBranchKeyVersion(
171+
branchKeyId: string,
172+
branchKeyVersion: string
173+
): Promise<NodeBranchKeyMaterial> {
174+
needs(
175+
branchKeyId == 'bd3842ff-3076-4092-9918-4395730050b8',
176+
branchKeyId
177+
)
178+
needs(
179+
branchKeyVersion == 'e9ce18a3-edb5-4272-9f86-1cacb7997ff6',
180+
branchKeyVersion
181+
)
182+
183+
return new NodeBranchKeyMaterial(
184+
Buffer.from(
185+
'tJwf65epYvUt5HMiQsl/6jlvLxS0tgdjIuvFy2BLIwg=',
186+
'base64'
187+
),
188+
branchKeyId,
189+
branchKeyVersion,
190+
{}
191+
)
192+
},
193+
async getActiveBranchKey(
194+
branchKeyId: string
195+
): Promise<NodeBranchKeyMaterial> {
196+
needs(
197+
branchKeyId == 'bd3842ff-3076-4092-9918-4395730050b8',
198+
branchKeyId
199+
)
200+
201+
return new NodeBranchKeyMaterial(
202+
Buffer.from(
203+
'tJwf65epYvUt5HMiQsl/6jlvLxS0tgdjIuvFy2BLIwg=',
204+
'base64'
205+
),
206+
branchKeyId,
207+
'e9ce18a3-edb5-4272-9f86-1cacb7997ff6',
208+
{}
209+
)
210+
},
211+
212+
storage: {
213+
_config: {},
214+
getKeyStorageInfo() {
215+
return {
216+
logicalName: 'logicalKeyStoreName',
217+
}
218+
},
219+
},
220+
} as any
221+
222+
return new KmsHierarchicalKeyRingNode({
223+
branchKeyId: 'bd3842ff-3076-4092-9918-4395730050b8',
224+
keyStore,
225+
cacheLimitTtl: 1,
226+
})
73227
}
74-
needs(test['keyring-type'] === 'static', 'wtf yo')
75-
const dataKey = Buffer.alloc(32, test['decrypted-dek'], 'base64')
76228

77-
return new (class TestKeyring extends KeyringNode {
78-
async _onEncrypt(): Promise<NodeEncryptionMaterial> {
79-
throw new Error('I should never see this error')
80-
}
81-
async _onDecrypt(material: NodeDecryptionMaterial) {
82-
const unencryptedDataKey = dataKey
83-
const trace = {
84-
keyNamespace: 'k',
85-
keyName: 'k',
86-
flags: KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY,
87-
}
88-
return material.setUnencryptedDataKey(unencryptedDataKey, trace)
89-
}
90-
})()
229+
needs(false, 'Unexpected keyring-type:' + test['keyring-type'])
91230
}
92231
})

0 commit comments

Comments
 (0)