-
Notifications
You must be signed in to change notification settings - Fork 443
Expand file tree
/
Copy pathkey-crypto.ts
More file actions
106 lines (83 loc) · 3.46 KB
/
key-crypto.ts
File metadata and controls
106 lines (83 loc) · 3.46 KB
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
// This code is based on the `mssql-jdbc` library published under the conditions of MIT license.
// Copyright (c) 2019 Microsoft Corporation
import { type CryptoMetadata, type EncryptionKeyInfo } from './types';
import { type ParserOptions } from '../token/stream-parser';
import SymmetricKey from './symmetric-key';
import { getKey } from './symmetric-key-cache';
import { AeadAes256CbcHmac256Algorithm, algorithmName } from './aead-aes-256-cbc-hmac-algorithm';
import { AeadAes256CbcHmac256EncryptionKey } from './aead-aes-256-cbc-hmac-encryption-key';
export const validateAndGetEncryptionAlgorithmName = (cipherAlgorithmId: number, cipherAlgorithmName?: string): string => {
if (cipherAlgorithmId !== 2) {
throw new Error('Custom cipher algorithm not supported.');
}
return algorithmName;
};
export const encryptWithKey = async (plaintext: Buffer, md: CryptoMetadata, options: ParserOptions): Promise<Buffer> => {
if (!options.trustedServerNameAE) {
throw new Error('Server name should not be null in EncryptWithKey');
}
if (!md.cipherAlgorithm) {
await decryptSymmetricKey(md, options);
}
if (!md.cipherAlgorithm) {
throw new Error('Cipher Algorithm should not be null in EncryptWithKey');
}
const cipherText: Buffer = md.cipherAlgorithm.encryptData(plaintext);
if (!cipherText) {
throw new Error('Internal error. Ciphertext value cannot be null.');
}
return cipherText;
};
export const decryptWithKey = async (cipherText: Buffer, md: CryptoMetadata, options: ParserOptions): Promise<Buffer> => {
if (!options.trustedServerNameAE) {
throw new Error('Server name should not be null in DecryptWithKey');
}
if (!md.cipherAlgorithm) {
await decryptSymmetricKey(md, options);
}
if (!md.cipherAlgorithm) {
throw new Error('Cipher Algorithm should not be null in DecryptWithKey');
}
const plainText: Buffer = md.cipherAlgorithm.decryptData(cipherText);
if (!plainText) {
throw new Error('Internal error. Plaintext value cannot be null.');
}
return plainText;
};
export const decryptSymmetricKey = async (md: CryptoMetadata, options: ParserOptions): Promise<void> => {
if (!md) {
throw new Error('md should not be null in DecryptSymmetricKey.');
}
if (!md.cekEntry) {
throw new Error('md.EncryptionInfo should not be null in DecryptSymmetricKey.');
}
if (!md.cekEntry.columnEncryptionKeyValues) {
throw new Error('md.EncryptionInfo.ColumnEncryptionKeyValues should not be null in DecryptSymmetricKey.');
}
let symKey: SymmetricKey | undefined;
let encryptionKeyInfoChosen: EncryptionKeyInfo | undefined;
const CEKValues: EncryptionKeyInfo[] = md.cekEntry.columnEncryptionKeyValues;
let lastError: Error | undefined;
for (const CEKValue of CEKValues) {
try {
symKey = await getKey(CEKValue, options);
if (symKey) {
encryptionKeyInfoChosen = CEKValue;
break;
}
} catch (error: any) {
lastError = error;
}
}
if (!symKey) {
if (lastError) {
throw lastError;
} else {
throw new Error('Exception while decryption of encrypted column encryption key.');
}
}
const algorithmName = validateAndGetEncryptionAlgorithmName(md.cipherAlgorithmId, md.cipherAlgorithmName);
const cipherAlgorithm = new AeadAes256CbcHmac256Algorithm(new AeadAes256CbcHmac256EncryptionKey(symKey.rootKey, algorithmName), md.encryptionType);
md.cipherAlgorithm = cipherAlgorithm;
md.encryptionKeyInfo = encryptionKeyInfoChosen as EncryptionKeyInfo;
};