node-opcua-crypto 1.8.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/.fossa.yml +18 -18
  2. package/.github/FUNDING.yml +12 -12
  3. package/.github/workflows/main.yml +32 -0
  4. package/.prettierrc.js +6 -6
  5. package/LICENSE +22 -22
  6. package/README.md +14 -14
  7. package/dist/asn1.d.ts +69 -0
  8. package/dist/asn1.js +349 -0
  9. package/dist/asn1.js.map +1 -0
  10. package/dist/buffer_utils.d.ts +6 -0
  11. package/dist/buffer_utils.js +22 -0
  12. package/dist/buffer_utils.js.map +1 -0
  13. package/dist/common.d.ts +11 -0
  14. package/dist/common.js +3 -0
  15. package/dist/common.js.map +1 -0
  16. package/dist/crypto_explore_certificate.d.ts +95 -0
  17. package/dist/crypto_explore_certificate.js +547 -0
  18. package/dist/crypto_explore_certificate.js.map +1 -0
  19. package/dist/crypto_utils.d.ts +106 -0
  20. package/dist/crypto_utils.js +370 -0
  21. package/dist/crypto_utils.js.map +1 -0
  22. package/dist/derived_keys.d.ts +72 -0
  23. package/dist/derived_keys.js +247 -0
  24. package/dist/derived_keys.js.map +1 -0
  25. package/dist/explore_certificate.d.ts +30 -0
  26. package/dist/explore_certificate.js +44 -0
  27. package/dist/explore_certificate.js.map +1 -0
  28. package/dist/explore_certificate_revocation_list.d.ts +30 -0
  29. package/dist/explore_certificate_revocation_list.js +67 -0
  30. package/dist/explore_certificate_revocation_list.js.map +1 -0
  31. package/dist/index.d.ts +10 -0
  32. package/dist/index.js +23 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/oid_map.d.ts +7 -0
  35. package/dist/oid_map.js +262 -0
  36. package/dist/oid_map.js.map +1 -0
  37. package/dist/source/asn1.d.ts +73 -72
  38. package/dist/source/asn1.js +359 -350
  39. package/dist/source/asn1.js.map +1 -1
  40. package/dist/source/buffer_utils.d.ts +6 -6
  41. package/dist/source/buffer_utils.js +21 -21
  42. package/dist/source/common.d.ts +12 -12
  43. package/dist/source/common.js +2 -2
  44. package/dist/source/crypto_explore_certificate.d.ts +107 -107
  45. package/dist/source/crypto_explore_certificate.js +600 -571
  46. package/dist/source/crypto_explore_certificate.js.map +1 -1
  47. package/dist/source/crypto_utils.d.ts +78 -78
  48. package/dist/source/crypto_utils.js +280 -280
  49. package/dist/source/crypto_utils.js.map +1 -1
  50. package/dist/source/derived_keys.d.ts +72 -72
  51. package/dist/source/derived_keys.js +248 -245
  52. package/dist/source/derived_keys.js.map +1 -1
  53. package/dist/source/explore_certificate.d.ts +30 -30
  54. package/dist/source/explore_certificate.js +43 -43
  55. package/dist/source/explore_certificate.js.map +1 -1
  56. package/dist/source/explore_certificate_revocation_list.d.ts +28 -28
  57. package/dist/source/explore_certificate_revocation_list.js +44 -44
  58. package/dist/source/explore_certificate_revocation_list.js.map +1 -1
  59. package/dist/source/explore_certificate_signing_request.d.ts +13 -13
  60. package/dist/source/explore_certificate_signing_request.js +44 -44
  61. package/dist/source/explore_certificate_signing_request.js.map +1 -1
  62. package/dist/source/explore_private_key.d.ts +29 -29
  63. package/dist/source/explore_private_key.js +96 -96
  64. package/dist/source/explore_private_key.js.map +1 -1
  65. package/dist/source/index.d.ts +13 -13
  66. package/dist/source/index.js +25 -25
  67. package/dist/source/oid_map.d.ts +7 -7
  68. package/dist/source/oid_map.js +303 -261
  69. package/dist/source/oid_map.js.map +1 -1
  70. package/dist/source/public_private_match.d.ts +3 -3
  71. package/dist/source/public_private_match.js +16 -16
  72. package/dist/source/public_private_match.js.map +1 -1
  73. package/dist/source/verify_certificate_signature.d.ts +10 -10
  74. package/dist/source/verify_certificate_signature.js +101 -101
  75. package/dist/source/verify_certificate_signature.js.map +1 -1
  76. package/dist/source_nodejs/index.d.ts +3 -3
  77. package/dist/source_nodejs/index.js +15 -15
  78. package/dist/source_nodejs/read.d.ts +29 -29
  79. package/dist/source_nodejs/read.js +94 -94
  80. package/dist/source_nodejs/read.js.map +1 -1
  81. package/dist/source_nodejs/read_certificate_revocation_list.d.ts +2 -2
  82. package/dist/source_nodejs/read_certificate_revocation_list.js +27 -27
  83. package/dist/source_nodejs/read_certificate_revocation_list.js.map +1 -1
  84. package/dist/source_nodejs/read_certificate_signing_request.d.ts +3 -3
  85. package/dist/source_nodejs/read_certificate_signing_request.js +27 -27
  86. package/dist/source_nodejs/read_certificate_signing_request.js.map +1 -1
  87. package/dist/verify_cerficate_signature.d.ts +10 -0
  88. package/dist/verify_cerficate_signature.js +102 -0
  89. package/dist/verify_cerficate_signature.js.map +1 -0
  90. package/index.d.ts +2 -2
  91. package/index.js +4 -4
  92. package/index_web.js +3 -3
  93. package/package.json +19 -22
  94. package/source/asn1.ts +404 -398
  95. package/source/buffer_utils.ts +18 -18
  96. package/source/common.ts +13 -13
  97. package/source/crypto_explore_certificate.ts +763 -728
  98. package/source/crypto_utils.ts +321 -321
  99. package/source/derived_keys.ts +287 -284
  100. package/source/explore_certificate.ts +66 -66
  101. package/source/explore_certificate_revocation_list.ts +93 -93
  102. package/source/explore_certificate_signing_request.ts +58 -58
  103. package/source/explore_private_key.ts +121 -121
  104. package/source/index.ts +13 -13
  105. package/source/oid_map.ts +310 -265
  106. package/source/public_private_match.ts +17 -17
  107. package/source/verify_certificate_signature.ts +105 -105
  108. package/source_nodejs/index.ts +2 -2
  109. package/source_nodejs/read.ts +95 -95
  110. package/source_nodejs/read_certificate_revocation_list.ts +14 -14
  111. package/source_nodejs/read_certificate_signing_request.ts +17 -17
  112. package/test_certificate.ts +34 -34
  113. package/tsconfig.json +18 -18
  114. package/tslint.json +34 -34
  115. package/pnpm-lock.yaml +0 -1767
@@ -1,321 +1,321 @@
1
- // tslint:disabled:no-var-requires
2
- /**
3
- * @module node_opcua_crypto
4
- */
5
- import * as constants from "constants";
6
- import * as crypto from "crypto";
7
- import { createFastUninitializedBuffer } from "./buffer_utils";
8
- import { Certificate, CertificatePEM, DER, PEM, PrivateKey, PrivateKeyPEM, PublicKey, PublicKeyPEM, Signature } from "./common";
9
- import { combine_der } from "./crypto_explore_certificate";
10
- import * as assert from "assert";
11
- import { hexy } from "hexy";
12
-
13
- const jsrsasign = require("jsrsasign");
14
-
15
- const PEM_REGEX = /^(-----BEGIN (.*)-----\r?\n([\/+=a-zA-Z0-9\r\n]*)\r?\n-----END \2-----\r?\n)/gm;
16
-
17
- const PEM_TYPE_REGEX = /^(-----BEGIN (.*)-----)/m;
18
- // Copyright 2012 The Obvious Corporation.
19
- // identifyPemType
20
-
21
- /*=
22
- * Extract and identify the PEM file type represented in the given
23
- * buffer. Returns the extracted type string or undefined if the
24
- * buffer doesn't seem to be any sort of PEM format file.
25
- */
26
- export function identifyPemType(rawKey: Buffer | string): undefined | string {
27
- if (rawKey instanceof Buffer) {
28
- rawKey = rawKey.toString("utf8");
29
- }
30
- const match = PEM_TYPE_REGEX.exec(rawKey);
31
- return !match ? undefined : match[2];
32
- }
33
-
34
- export function convertPEMtoDER(raw_key: PEM): DER {
35
- let match: any;
36
- let pemType;
37
- let base64str;
38
-
39
- const parts: DER[] = [];
40
-
41
- PEM_REGEX.lastIndex = 0;
42
- // tslint:disable-next-line:no-conditional-assignment
43
- while ((match = PEM_REGEX.exec(raw_key)) !== null) {
44
- pemType = match[2];
45
- // pemType shall be "RSA PRIVATE KEY" , "PUBLIC KEY", "CERTIFICATE", "X509 CRL"
46
- base64str = match[3];
47
- base64str = base64str.replace(/\r?\n/g, "");
48
- parts.push(Buffer.from(base64str, "base64"));
49
- }
50
- return combine_der(parts);
51
- }
52
-
53
- /**
54
- * @method toPem
55
- * @param raw_key
56
- * @param pem
57
- * @return
58
- */
59
- export function toPem(raw_key: Buffer | string, pem: string): string {
60
- assert(raw_key, "expecting a key");
61
- assert(typeof pem === "string");
62
- let pemType = identifyPemType(raw_key);
63
- if (pemType) {
64
- return raw_key instanceof Buffer ? raw_key.toString("utf8") : raw_key;
65
- } else {
66
- pemType = pem;
67
- assert(["CERTIFICATE REQUEST", "CERTIFICATE", "RSA PRIVATE KEY", "PUBLIC KEY", "X509 CRL"].indexOf(pemType) >= 0);
68
- let b = (raw_key as Buffer).toString("base64");
69
- let str = "-----BEGIN " + pemType + "-----\n";
70
- while (b.length) {
71
- str += b.substr(0, 64) + "\n";
72
- b = b.substr(64);
73
- }
74
- str += "-----END " + pemType + "-----";
75
- str += "\n";
76
- return str;
77
- }
78
- }
79
-
80
- // istanbul ignore next
81
- export function hexDump(buffer: Buffer, width?: number): string {
82
- if (!buffer) {
83
- return "<>";
84
- }
85
- width = width || 32;
86
- if (buffer.length > 1024) {
87
- return hexy(buffer.slice(0, 1024), { width, format: "twos" }) + "\n .... ( " + buffer.length + ")";
88
- } else {
89
- return hexy(buffer, { width, format: "twos" });
90
- }
91
- }
92
-
93
- interface MakeMessageChunkSignatureOptions {
94
- signatureLength: number;
95
- algorithm: string;
96
- privateKey: CertificatePEM;
97
- }
98
-
99
- /**
100
- * @method makeMessageChunkSignature
101
- * @param chunk
102
- * @param options
103
- * @param options.signatureLength
104
- * @param options.algorithm for example "RSA-SHA256"
105
- * @param options.privateKey
106
- * @return - the signature
107
- */
108
- export function makeMessageChunkSignature(chunk: Buffer, options: MakeMessageChunkSignatureOptions): Buffer {
109
- assert(options.hasOwnProperty("algorithm"));
110
- assert(chunk instanceof Buffer);
111
- assert(["RSA PRIVATE KEY", "PRIVATE KEY"].indexOf(identifyPemType(options.privateKey) as string) >= 0);
112
- // signature length = 128 bytes
113
- const signer = crypto.createSign(options.algorithm);
114
- signer.update(chunk);
115
- const signature = signer.sign(options.privateKey);
116
- assert(!options.signatureLength || signature.length === options.signatureLength);
117
- return signature as Buffer; // Buffer
118
- }
119
-
120
- export interface VerifyMessageChunkSignatureOptions {
121
- signatureLength?: number;
122
- algorithm: string;
123
- publicKey: PublicKeyPEM;
124
- }
125
-
126
- /**
127
- * @method verifyMessageChunkSignature
128
- *
129
- * const signer = {
130
- * signatureLength : 128,
131
- * algorithm : "RSA-SHA256",
132
- * publicKey: "qsdqsdqsd"
133
- * };
134
- * @param blockToVerify
135
- * @param signature
136
- * @param options
137
- * @param options.signatureLength
138
- * @param options.algorithm for example "RSA-SHA256"
139
- * @param options.publicKey
140
- * @return true if the signature is valid
141
- */
142
- export function verifyMessageChunkSignature(
143
- blockToVerify: Buffer,
144
- signature: Signature,
145
- options: VerifyMessageChunkSignatureOptions
146
- ): boolean {
147
- assert(blockToVerify instanceof Buffer);
148
- assert(signature instanceof Buffer);
149
- assert(typeof options.publicKey === "string");
150
- assert(identifyPemType(options.publicKey));
151
-
152
- const verify = crypto.createVerify(options.algorithm);
153
- verify.update(blockToVerify);
154
- return verify.verify(options.publicKey, signature);
155
- }
156
-
157
- export function makeSHA1Thumbprint(buffer: Buffer): Signature {
158
- return crypto.createHash("sha1").update(buffer).digest();
159
- }
160
-
161
- // Basically when you =encrypt something using an RSA key (whether public or private), the encrypted value must
162
- // be smaller than the key (due to the maths used to do the actual encryption). So if you have a 1024-bit key,
163
- // in theory you could encrypt any 1023-bit value (or a 1024-bit value smaller than the key) with that key.
164
- // However, the PKCS#1 standard, which OpenSSL uses, specifies a padding scheme (so you can encrypt smaller
165
- // quantities without losing security), and that padding scheme takes a minimum of 11 bytes (it will be longer
166
- // if the value you're encrypting is smaller). So the highest number of bits you can encrypt with a 1024-bit
167
- // key is 936 bits because of this (unless you disable the padding by adding the OPENSSL_NO_PADDING flag,
168
- // in which case you can go up to 1023-1024 bits). With a 2048-bit key it's 1960 bits instead.
169
-
170
- export const RSA_PKCS1_OAEP_PADDING: number = constants.RSA_PKCS1_OAEP_PADDING;
171
- export const RSA_PKCS1_PADDING: number = constants.RSA_PKCS1_PADDING;
172
-
173
- export enum PaddingAlgorithm {
174
- RSA_PKCS1_OAEP_PADDING = 4,
175
- RSA_PKCS1_PADDING = 1,
176
- }
177
-
178
- assert(PaddingAlgorithm.RSA_PKCS1_OAEP_PADDING === constants.RSA_PKCS1_OAEP_PADDING);
179
- assert(PaddingAlgorithm.RSA_PKCS1_PADDING === constants.RSA_PKCS1_PADDING);
180
-
181
- // publicEncrypt and privateDecrypt only work with
182
- // small buffer that depends of the key size.
183
- export function publicEncrypt_native(buffer: Buffer, publicKey: PublicKeyPEM, algorithm?: PaddingAlgorithm): Buffer {
184
- if (algorithm === undefined) {
185
- algorithm = PaddingAlgorithm.RSA_PKCS1_PADDING;
186
- }
187
- assert(algorithm === RSA_PKCS1_PADDING || algorithm === RSA_PKCS1_OAEP_PADDING);
188
- assert(buffer instanceof Buffer, "Expecting a buffer");
189
- return crypto.publicEncrypt(
190
- {
191
- key: publicKey,
192
- padding: algorithm,
193
- },
194
- buffer
195
- );
196
- }
197
-
198
- export function privateDecrypt_native(buffer: Buffer, privateKey: PrivateKeyPEM, algorithm?: PaddingAlgorithm): Buffer {
199
- if (algorithm === undefined) {
200
- algorithm = PaddingAlgorithm.RSA_PKCS1_PADDING;
201
- }
202
-
203
- assert(algorithm === RSA_PKCS1_PADDING || algorithm === RSA_PKCS1_OAEP_PADDING);
204
- assert(buffer instanceof Buffer, "Expecting a buffer");
205
- try {
206
- return crypto.privateDecrypt(
207
- {
208
- key: privateKey,
209
- padding: algorithm,
210
- },
211
- buffer
212
- );
213
- } catch (err) {
214
- return Buffer.alloc(1);
215
- }
216
- }
217
-
218
- export const publicEncrypt = publicEncrypt_native;
219
- export const privateDecrypt = privateDecrypt_native;
220
-
221
- export function publicEncrypt_long(
222
- buffer: Buffer,
223
- publicKey: PublicKeyPEM,
224
- blockSize: number,
225
- padding: number,
226
- algorithm?: PaddingAlgorithm
227
- ): Buffer {
228
- if (algorithm === undefined) {
229
- algorithm = PaddingAlgorithm.RSA_PKCS1_PADDING;
230
- }
231
- assert(algorithm === RSA_PKCS1_PADDING || algorithm === RSA_PKCS1_OAEP_PADDING);
232
-
233
- const chunk_size = blockSize - padding;
234
- const nbBlocks = Math.ceil(buffer.length / chunk_size);
235
-
236
- const outputBuffer = createFastUninitializedBuffer(nbBlocks * blockSize);
237
- for (let i = 0; i < nbBlocks; i++) {
238
- const currentBlock = buffer.slice(chunk_size * i, chunk_size * (i + 1));
239
- const encrypted_chunk = publicEncrypt(currentBlock, publicKey, algorithm);
240
- assert(encrypted_chunk.length === blockSize);
241
- encrypted_chunk.copy(outputBuffer, i * blockSize);
242
- }
243
- return outputBuffer;
244
- }
245
-
246
- export function privateDecrypt_long(buffer: Buffer, privateKey: PrivateKeyPEM, blockSize: number, algorithm?: number): Buffer {
247
- algorithm = algorithm || RSA_PKCS1_PADDING;
248
- assert(algorithm === RSA_PKCS1_PADDING || algorithm === RSA_PKCS1_OAEP_PADDING);
249
-
250
- const nbBlocks = Math.ceil(buffer.length / blockSize);
251
-
252
- const outputBuffer = createFastUninitializedBuffer(nbBlocks * blockSize);
253
-
254
- let total_length = 0;
255
- for (let i = 0; i < nbBlocks; i++) {
256
- const currentBlock = buffer.slice(blockSize * i, Math.min(blockSize * (i + 1), buffer.length));
257
- const decrypted_buf = privateDecrypt(currentBlock, privateKey, algorithm);
258
- decrypted_buf.copy(outputBuffer, total_length);
259
- total_length += decrypted_buf.length;
260
- }
261
- return outputBuffer.slice(0, total_length);
262
- }
263
-
264
- export function coerceCertificatePem(certificate: Certificate | CertificatePEM): CertificatePEM {
265
- if (certificate instanceof Buffer) {
266
- certificate = toPem(certificate, "CERTIFICATE");
267
- }
268
- assert(typeof certificate === "string");
269
- return certificate;
270
- }
271
-
272
- export function coercePublicKeyPem(publicKey: PublicKey | PublicKeyPEM): PublicKeyPEM {
273
- if (publicKey instanceof Buffer) {
274
- publicKey = toPem(publicKey, "PUBLIC KEY");
275
- }
276
- assert(typeof publicKey === "string");
277
- return publicKey;
278
- }
279
-
280
- /***
281
- * @method rsa_length
282
- * A very expensive way to determine the rsa key length ( i.e 2048bits or 1024bits)
283
- * @param key a PEM public key or a PEM rsa private key
284
- * @return { the key length in bytes.
285
- */
286
- export function rsa_length(key: PublicKeyPEM | PublicKey): number {
287
- key = coercePublicKeyPem(key);
288
- assert(typeof key === "string");
289
- const a = jsrsasign.KEYUTIL.getKey(key);
290
- return a.n.toString(16).length / 2;
291
- }
292
-
293
- export function extractPublicKeyFromCertificateSync(certificate: Certificate | CertificatePEM): PublicKeyPEM {
294
- certificate = coerceCertificatePem(certificate);
295
- const key = jsrsasign.KEYUTIL.getKey(certificate);
296
- const publicKeyAsPem = jsrsasign.KEYUTIL.getPEM(key);
297
- assert(typeof publicKeyAsPem === "string");
298
- return publicKeyAsPem;
299
- }
300
-
301
- // https://github.com/kjur/jsrsasign/blob/master/x509-1.1.js
302
- // tool to analyse asn1 base64 blocks : http://lapo.it/asn1js
303
- /**
304
- * extract the publickey from a certificate
305
- * @async
306
- */
307
- export function extractPublicKeyFromCertificate(
308
- certificate: CertificatePEM | Certificate,
309
- callback: (err: Error | null, publicKeyPEM?: PublicKeyPEM) => void
310
- ): void {
311
- let err1: any = null;
312
- let keyPem: PublicKeyPEM;
313
- try {
314
- keyPem = extractPublicKeyFromCertificateSync(certificate);
315
- } catch (err) {
316
- err1 = err;
317
- }
318
- setImmediate(() => {
319
- callback(err1, keyPem);
320
- });
321
- }
1
+ // tslint:disabled:no-var-requires
2
+ /**
3
+ * @module node_opcua_crypto
4
+ */
5
+ import * as constants from "constants";
6
+ import * as crypto from "crypto";
7
+ import { createFastUninitializedBuffer } from "./buffer_utils";
8
+ import { Certificate, CertificatePEM, DER, PEM, PrivateKey, PrivateKeyPEM, PublicKey, PublicKeyPEM, Signature } from "./common";
9
+ import { combine_der } from "./crypto_explore_certificate";
10
+ import * as assert from "assert";
11
+ import { hexy } from "hexy";
12
+
13
+ const jsrsasign = require("jsrsasign");
14
+
15
+ const PEM_REGEX = /^(-----BEGIN (.*)-----\r?\n([/+=a-zA-Z0-9\r\n]*)\r?\n-----END \2-----\r?\n)/gm;
16
+
17
+ const PEM_TYPE_REGEX = /^(-----BEGIN (.*)-----)/m;
18
+ // Copyright 2012 The Obvious Corporation.
19
+ // identifyPemType
20
+
21
+ /*=
22
+ * Extract and identify the PEM file type represented in the given
23
+ * buffer. Returns the extracted type string or undefined if the
24
+ * buffer doesn't seem to be any sort of PEM format file.
25
+ */
26
+ export function identifyPemType(rawKey: Buffer | string): undefined | string {
27
+ if (rawKey instanceof Buffer) {
28
+ rawKey = rawKey.toString("utf8");
29
+ }
30
+ const match = PEM_TYPE_REGEX.exec(rawKey);
31
+ return !match ? undefined : match[2];
32
+ }
33
+
34
+ export function convertPEMtoDER(raw_key: PEM): DER {
35
+ let match: any;
36
+ let pemType;
37
+ let base64str;
38
+
39
+ const parts: DER[] = [];
40
+
41
+ PEM_REGEX.lastIndex = 0;
42
+ // tslint:disable-next-line:no-conditional-assignment
43
+ while ((match = PEM_REGEX.exec(raw_key)) !== null) {
44
+ pemType = match[2];
45
+ // pemType shall be "RSA PRIVATE KEY" , "PUBLIC KEY", "CERTIFICATE", "X509 CRL"
46
+ base64str = match[3];
47
+ base64str = base64str.replace(/\r?\n/g, "");
48
+ parts.push(Buffer.from(base64str, "base64"));
49
+ }
50
+ return combine_der(parts);
51
+ }
52
+
53
+ /**
54
+ * @method toPem
55
+ * @param raw_key
56
+ * @param pem
57
+ * @return
58
+ */
59
+ export function toPem(raw_key: Buffer | string, pem: string): string {
60
+ assert(raw_key, "expecting a key");
61
+ assert(typeof pem === "string");
62
+ let pemType = identifyPemType(raw_key);
63
+ if (pemType) {
64
+ return raw_key instanceof Buffer ? raw_key.toString("utf8") : raw_key;
65
+ } else {
66
+ pemType = pem;
67
+ assert(["CERTIFICATE REQUEST", "CERTIFICATE", "RSA PRIVATE KEY", "PUBLIC KEY", "X509 CRL"].indexOf(pemType) >= 0);
68
+ let b = (raw_key as Buffer).toString("base64");
69
+ let str = "-----BEGIN " + pemType + "-----\n";
70
+ while (b.length) {
71
+ str += b.substr(0, 64) + "\n";
72
+ b = b.substr(64);
73
+ }
74
+ str += "-----END " + pemType + "-----";
75
+ str += "\n";
76
+ return str;
77
+ }
78
+ }
79
+
80
+ // istanbul ignore next
81
+ export function hexDump(buffer: Buffer, width?: number): string {
82
+ if (!buffer) {
83
+ return "<>";
84
+ }
85
+ width = width || 32;
86
+ if (buffer.length > 1024) {
87
+ return hexy(buffer.slice(0, 1024), { width, format: "twos" }) + "\n .... ( " + buffer.length + ")";
88
+ } else {
89
+ return hexy(buffer, { width, format: "twos" });
90
+ }
91
+ }
92
+
93
+ interface MakeMessageChunkSignatureOptions {
94
+ signatureLength: number;
95
+ algorithm: string;
96
+ privateKey: CertificatePEM;
97
+ }
98
+
99
+ /**
100
+ * @method makeMessageChunkSignature
101
+ * @param chunk
102
+ * @param options
103
+ * @param options.signatureLength
104
+ * @param options.algorithm for example "RSA-SHA256"
105
+ * @param options.privateKey
106
+ * @return - the signature
107
+ */
108
+ export function makeMessageChunkSignature(chunk: Buffer, options: MakeMessageChunkSignatureOptions): Buffer {
109
+ assert(Object.prototype.hasOwnProperty.call(options,"algorithm"));
110
+ assert(chunk instanceof Buffer);
111
+ assert(["RSA PRIVATE KEY", "PRIVATE KEY"].indexOf(identifyPemType(options.privateKey) as string) >= 0);
112
+ // signature length = 128 bytes
113
+ const signer = crypto.createSign(options.algorithm);
114
+ signer.update(chunk);
115
+ const signature = signer.sign(options.privateKey);
116
+ assert(!options.signatureLength || signature.length === options.signatureLength);
117
+ return signature;
118
+ }
119
+
120
+ export interface VerifyMessageChunkSignatureOptions {
121
+ signatureLength?: number;
122
+ algorithm: string;
123
+ publicKey: PublicKeyPEM;
124
+ }
125
+
126
+ /**
127
+ * @method verifyMessageChunkSignature
128
+ *
129
+ * const signer = {
130
+ * signatureLength : 128,
131
+ * algorithm : "RSA-SHA256",
132
+ * publicKey: "qsdqsdqsd"
133
+ * };
134
+ * @param blockToVerify
135
+ * @param signature
136
+ * @param options
137
+ * @param options.signatureLength
138
+ * @param options.algorithm for example "RSA-SHA256"
139
+ * @param options.publicKey
140
+ * @return true if the signature is valid
141
+ */
142
+ export function verifyMessageChunkSignature(
143
+ blockToVerify: Buffer,
144
+ signature: Signature,
145
+ options: VerifyMessageChunkSignatureOptions
146
+ ): boolean {
147
+ assert(blockToVerify instanceof Buffer);
148
+ assert(signature instanceof Buffer);
149
+ assert(typeof options.publicKey === "string");
150
+ assert(identifyPemType(options.publicKey));
151
+
152
+ const verify = crypto.createVerify(options.algorithm);
153
+ verify.update(blockToVerify);
154
+ return verify.verify(options.publicKey, signature);
155
+ }
156
+
157
+ export function makeSHA1Thumbprint(buffer: Buffer): Signature {
158
+ return crypto.createHash("sha1").update(buffer).digest();
159
+ }
160
+
161
+ // Basically when you =encrypt something using an RSA key (whether public or private), the encrypted value must
162
+ // be smaller than the key (due to the maths used to do the actual encryption). So if you have a 1024-bit key,
163
+ // in theory you could encrypt any 1023-bit value (or a 1024-bit value smaller than the key) with that key.
164
+ // However, the PKCS#1 standard, which OpenSSL uses, specifies a padding scheme (so you can encrypt smaller
165
+ // quantities without losing security), and that padding scheme takes a minimum of 11 bytes (it will be longer
166
+ // if the value you're encrypting is smaller). So the highest number of bits you can encrypt with a 1024-bit
167
+ // key is 936 bits because of this (unless you disable the padding by adding the OPENSSL_NO_PADDING flag,
168
+ // in which case you can go up to 1023-1024 bits). With a 2048-bit key it's 1960 bits instead.
169
+
170
+ export const RSA_PKCS1_OAEP_PADDING: number = constants.RSA_PKCS1_OAEP_PADDING;
171
+ export const RSA_PKCS1_PADDING: number = constants.RSA_PKCS1_PADDING;
172
+
173
+ export enum PaddingAlgorithm {
174
+ RSA_PKCS1_OAEP_PADDING = 4,
175
+ RSA_PKCS1_PADDING = 1,
176
+ }
177
+
178
+ assert(PaddingAlgorithm.RSA_PKCS1_OAEP_PADDING === constants.RSA_PKCS1_OAEP_PADDING);
179
+ assert(PaddingAlgorithm.RSA_PKCS1_PADDING === constants.RSA_PKCS1_PADDING);
180
+
181
+ // publicEncrypt and privateDecrypt only work with
182
+ // small buffer that depends of the key size.
183
+ export function publicEncrypt_native(buffer: Buffer, publicKey: PublicKeyPEM, algorithm?: PaddingAlgorithm): Buffer {
184
+ if (algorithm === undefined) {
185
+ algorithm = PaddingAlgorithm.RSA_PKCS1_PADDING;
186
+ }
187
+ assert(algorithm === RSA_PKCS1_PADDING || algorithm === RSA_PKCS1_OAEP_PADDING);
188
+ assert(buffer instanceof Buffer, "Expecting a buffer");
189
+ return crypto.publicEncrypt(
190
+ {
191
+ key: publicKey,
192
+ padding: algorithm,
193
+ },
194
+ buffer
195
+ );
196
+ }
197
+
198
+ export function privateDecrypt_native(buffer: Buffer, privateKey: PrivateKeyPEM, algorithm?: PaddingAlgorithm): Buffer {
199
+ if (algorithm === undefined) {
200
+ algorithm = PaddingAlgorithm.RSA_PKCS1_PADDING;
201
+ }
202
+
203
+ assert(algorithm === RSA_PKCS1_PADDING || algorithm === RSA_PKCS1_OAEP_PADDING);
204
+ assert(buffer instanceof Buffer, "Expecting a buffer");
205
+ try {
206
+ return crypto.privateDecrypt(
207
+ {
208
+ key: privateKey,
209
+ padding: algorithm,
210
+ },
211
+ buffer
212
+ );
213
+ } catch (err) {
214
+ return Buffer.alloc(1);
215
+ }
216
+ }
217
+
218
+ export const publicEncrypt = publicEncrypt_native;
219
+ export const privateDecrypt = privateDecrypt_native;
220
+
221
+ export function publicEncrypt_long(
222
+ buffer: Buffer,
223
+ publicKey: PublicKeyPEM,
224
+ blockSize: number,
225
+ padding: number,
226
+ algorithm?: PaddingAlgorithm
227
+ ): Buffer {
228
+ if (algorithm === undefined) {
229
+ algorithm = PaddingAlgorithm.RSA_PKCS1_PADDING;
230
+ }
231
+ assert(algorithm === RSA_PKCS1_PADDING || algorithm === RSA_PKCS1_OAEP_PADDING);
232
+
233
+ const chunk_size = blockSize - padding;
234
+ const nbBlocks = Math.ceil(buffer.length / chunk_size);
235
+
236
+ const outputBuffer = createFastUninitializedBuffer(nbBlocks * blockSize);
237
+ for (let i = 0; i < nbBlocks; i++) {
238
+ const currentBlock = buffer.slice(chunk_size * i, chunk_size * (i + 1));
239
+ const encrypted_chunk = publicEncrypt(currentBlock, publicKey, algorithm);
240
+ assert(encrypted_chunk.length === blockSize);
241
+ encrypted_chunk.copy(outputBuffer, i * blockSize);
242
+ }
243
+ return outputBuffer;
244
+ }
245
+
246
+ export function privateDecrypt_long(buffer: Buffer, privateKey: PrivateKeyPEM, blockSize: number, algorithm?: number): Buffer {
247
+ algorithm = algorithm || RSA_PKCS1_PADDING;
248
+ assert(algorithm === RSA_PKCS1_PADDING || algorithm === RSA_PKCS1_OAEP_PADDING);
249
+
250
+ const nbBlocks = Math.ceil(buffer.length / blockSize);
251
+
252
+ const outputBuffer = createFastUninitializedBuffer(nbBlocks * blockSize);
253
+
254
+ let total_length = 0;
255
+ for (let i = 0; i < nbBlocks; i++) {
256
+ const currentBlock = buffer.slice(blockSize * i, Math.min(blockSize * (i + 1), buffer.length));
257
+ const decrypted_buf = privateDecrypt(currentBlock, privateKey, algorithm);
258
+ decrypted_buf.copy(outputBuffer, total_length);
259
+ total_length += decrypted_buf.length;
260
+ }
261
+ return outputBuffer.slice(0, total_length);
262
+ }
263
+
264
+ export function coerceCertificatePem(certificate: Certificate | CertificatePEM): CertificatePEM {
265
+ if (certificate instanceof Buffer) {
266
+ certificate = toPem(certificate, "CERTIFICATE");
267
+ }
268
+ assert(typeof certificate === "string");
269
+ return certificate;
270
+ }
271
+
272
+ export function coercePublicKeyPem(publicKey: PublicKey | PublicKeyPEM): PublicKeyPEM {
273
+ if (publicKey instanceof Buffer) {
274
+ publicKey = toPem(publicKey, "PUBLIC KEY");
275
+ }
276
+ assert(typeof publicKey === "string");
277
+ return publicKey;
278
+ }
279
+
280
+ /***
281
+ * @method rsa_length
282
+ * A very expensive way to determine the rsa key length ( i.e 2048bits or 1024bits)
283
+ * @param key a PEM public key or a PEM rsa private key
284
+ * @return { the key length in bytes.
285
+ */
286
+ export function rsa_length(key: PublicKeyPEM | PublicKey): number {
287
+ key = coercePublicKeyPem(key);
288
+ assert(typeof key === "string");
289
+ const a = jsrsasign.KEYUTIL.getKey(key);
290
+ return a.n.toString(16).length / 2;
291
+ }
292
+
293
+ export function extractPublicKeyFromCertificateSync(certificate: Certificate | CertificatePEM): PublicKeyPEM {
294
+ certificate = coerceCertificatePem(certificate);
295
+ const key = jsrsasign.KEYUTIL.getKey(certificate);
296
+ const publicKeyAsPem = jsrsasign.KEYUTIL.getPEM(key);
297
+ assert(typeof publicKeyAsPem === "string");
298
+ return publicKeyAsPem;
299
+ }
300
+
301
+ // https://github.com/kjur/jsrsasign/blob/master/x509-1.1.js
302
+ // tool to analyse asn1 base64 blocks : http://lapo.it/asn1js
303
+ /**
304
+ * extract the publickey from a certificate
305
+ * @async
306
+ */
307
+ export function extractPublicKeyFromCertificate(
308
+ certificate: CertificatePEM | Certificate,
309
+ callback: (err: Error | null, publicKeyPEM?: PublicKeyPEM) => void
310
+ ): void {
311
+ let err1: any = null;
312
+ let keyPem: PublicKeyPEM;
313
+ try {
314
+ keyPem = extractPublicKeyFromCertificateSync(certificate);
315
+ } catch (err) {
316
+ err1 = err;
317
+ }
318
+ setImmediate(() => {
319
+ callback(err1, keyPem);
320
+ });
321
+ }