forked from aws/aws-encryption-sdk-javascript
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathget_import_options.ts
159 lines (144 loc) · 4.69 KB
/
get_import_options.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import {
RsaPadding,
JsonWebKeyRsaAlg,
RsaHash,
BinaryKey,
RsaJsonWebKey,
RsaImportableKey,
RsaWrappingKeyAlgorithm,
} from './types'
import {
MixedBackendCryptoKey,
needs,
isCryptoKey,
AwsEsdkJsCryptoKey,
} from '@aws-crypto/material-management-browser'
type WebCryptoRsaName = keyof typeof JsonWebKeyRsaAlg
const OAEP_SHA1_MFG1: RsaWrappingKeyAlgorithm = {
name: 'RSA-OAEP',
hash: { name: 'SHA-1' },
}
Object.freeze(OAEP_SHA1_MFG1)
Object.freeze(OAEP_SHA1_MFG1.hash)
const OAEP_SHA256_MFG1: RsaWrappingKeyAlgorithm = {
name: 'RSA-OAEP',
hash: { name: 'SHA-256' },
}
Object.freeze(OAEP_SHA256_MFG1)
Object.freeze(OAEP_SHA256_MFG1.hash)
const OAEP_SHA384_MFG1: RsaWrappingKeyAlgorithm = {
name: 'RSA-OAEP',
hash: { name: 'SHA-384' },
}
Object.freeze(OAEP_SHA384_MFG1)
Object.freeze(OAEP_SHA384_MFG1.hash)
const OAEP_SHA512_MFG1: RsaWrappingKeyAlgorithm = {
name: 'RSA-OAEP',
hash: { name: 'SHA-512' },
}
Object.freeze(OAEP_SHA512_MFG1)
Object.freeze(OAEP_SHA512_MFG1.hash)
const JsonWebKeyMap: {
[key in JsonWebKeyRsaAlg]: RsaWrappingKeyAlgorithm
} = Object.freeze({
[JsonWebKeyRsaAlg['RSA-OAEP']]: OAEP_SHA1_MFG1,
[JsonWebKeyRsaAlg['RSA-OAEP-256']]: OAEP_SHA256_MFG1,
[JsonWebKeyRsaAlg['RSA-OAEP-384']]: OAEP_SHA384_MFG1,
[JsonWebKeyRsaAlg['RSA-OAEP-512']]: OAEP_SHA512_MFG1,
})
const RsaPaddingMap: {
[key in RsaPadding]: RsaWrappingKeyAlgorithm
} = Object.freeze({
[RsaPadding.OAEP_SHA1_MFG1]: OAEP_SHA1_MFG1,
[RsaPadding.OAEP_SHA256_MFG1]: OAEP_SHA256_MFG1,
[RsaPadding.OAEP_SHA384_MFG1]: OAEP_SHA384_MFG1,
[RsaPadding.OAEP_SHA512_MFG1]: OAEP_SHA512_MFG1,
})
export function getImportOptions(keyInfo: RsaImportableKey):
| {
format: 'jwk'
wrappingAlgorithm: RsaWrappingKeyAlgorithm
key: RsaJsonWebKey
}
| {
format: 'raw' | 'pkcs8' | 'spki'
wrappingAlgorithm: RsaWrappingKeyAlgorithm
key: Uint8Array
} {
const { alg } = keyInfo as RsaJsonWebKey
const { padding } = keyInfo as BinaryKey
if (JsonWebKeyMap[alg]) {
return {
format: 'jwk',
key: keyInfo as RsaJsonWebKey,
wrappingAlgorithm: JsonWebKeyMap[alg],
}
} else if (RsaPaddingMap[padding]) {
const { format, key } = keyInfo as BinaryKey
return {
format,
key,
wrappingAlgorithm: RsaPaddingMap[padding],
}
}
throw new Error('Unsupported RsaImportableKey')
}
export function getWrappingAlgorithm(
publicKey?: AwsEsdkJsCryptoKey,
privateKey?: AwsEsdkJsCryptoKey | MixedBackendCryptoKey
) {
const privateKeys = flattenMixedCryptoKey(privateKey)
if (publicKey && privateKeys.length) {
return verify(...[publicKey, ...privateKeys].map(extract))
} else if (publicKey) {
return verify(extract(publicKey))
} else if (privateKeys.length) {
return verify(...privateKeys.map(extract))
}
throw new Error('No Key provided.')
}
export function extract(key: AwsEsdkJsCryptoKey): RsaWrappingKeyAlgorithm {
const { algorithm } = key
// @ts-ignore
const { name, hash } = algorithm
return { name: name as WebCryptoRsaName, hash }
}
export function verify(...args: RsaWrappingKeyAlgorithm[]) {
const [wrappingAlgorithm, ...rest] = args
/* Precondition: Need at least 1 algorithm to verify. */
needs(wrappingAlgorithm, 'Can not verify an empty set of algorithms.')
const { name, hash } = wrappingAlgorithm
/* Precondition: The wrappingAlgorithm name must be a supported value. */
needs(JsonWebKeyRsaAlg[name], 'Algorithm name is not supported.')
/* Precondition: The hash name must be a supported value. */
needs(hash && RsaHash[hash.name], 'Hash name is not supported.')
/* Check for early return (Postcondition): Only 1 wrappingAlgorithm is clearly valid. */
if (!rest.length) return wrappingAlgorithm
/* Precondition: All keys must have the same wrappingAlgorithm. */
needs(
rest.every(equalWrappingAlgorithm),
'Not all RSA keys have the same wrappingAlgorithm.'
)
return wrappingAlgorithm
function equalWrappingAlgorithm(algorithm: RsaWrappingKeyAlgorithm) {
return (
algorithm.name === name &&
algorithm.hash &&
algorithm.hash.name === hash.name
)
}
}
export function flattenMixedCryptoKey(
key?: AwsEsdkJsCryptoKey | MixedBackendCryptoKey
): AwsEsdkJsCryptoKey[] {
/* Check for early return (Postcondition): empty inputs should return an empty array. */
if (!key) return []
if (isCryptoKey(key)) return [key]
const { nonZeroByteCryptoKey, zeroByteCryptoKey } = key
const keys = [nonZeroByteCryptoKey, zeroByteCryptoKey]
/* Postcondition: Not all keys are CryptoKeys. */
needs(keys.every(isCryptoKey), 'Not all keys are CryptoKeys.')
return keys
}