Skip to content
File

Blob: src/node/internal/crypto_cipher.ts

typescript713 lines
1// Copyright (c) 2017-2023 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4//
5// Copyright Joyent, Inc. and other Node contributors.
6//
7// Permission is hereby granted, free of charge, to any person obtaining a
8// copy of this software and associated documentation files (the
9// "Software"), to deal in the Software without restriction, including
10// without limitation the rights to use, copy, modify, merge, publish,
11// distribute, sublicense, and/or sell copies of the Software, and to permit
12// persons to whom the Software is furnished to do so, subject to the
13// following conditions:
14//
15// The above copyright notice and this permission notice shall be included
16// in all copies or substantial portions of the Software.
17//
18// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
21// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24// USE OR OTHER DEALINGS IN THE SOFTWARE.
25 
26import {
27 default as cryptoImpl,
28 type GetCipherInfoOptions,
29 type CipherInfo,
30 type PublicPrivateCipherOptions,
31 type CipherHandle,
32 type AeadHandle,
33 type CipherMode,
34} from 'node-internal:crypto';
35 
36import {
37 Transform,
38 type TransformOptions,
39 type TransformCallback,
40} from 'node-internal:streams_transform';
41 
42import {
43 type KeyObject,
44 createSecretKey,
45 createPublicKey,
46 createPrivateKey,
47 isKeyObject,
48 getKeyObjectHandle,
49} from 'node-internal:crypto_keys';
50 
51import {
52 validateNumber,
53 validateObject,
54 validateString,
55 validateUint32,
56} from 'node-internal:validators';
57 
58import {
59 ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE,
60 ERR_INVALID_ARG_TYPE,
61 ERR_INVALID_ARG_VALUE,
62 ERR_MISSING_ARGS,
63} from 'node-internal:internal_errors';
64 
65import {
66 isAnyArrayBuffer,
67 isArrayBufferView,
68} from 'node-internal:internal_types';
69 
70import {
71 type KeyData,
72 type CreateAsymmetricKeyOptions,
73} from 'node-internal:crypto';
74 
75import { Buffer } from 'node-internal:internal_buffer';
76 
77export interface AADOptions {
78 plaintextLength?: number;
79 encoding?: string;
80}
81 
82const kHandle = Symbol('kHandle');
83 
84const CipherMode: CipherMode = {
85 CIPHER: 0,
86 DECIPHER: 1,
87};
88 
89export interface Cipheriv extends Transform {
90 [kHandle]: CipherHandle | AeadHandle;
91 update(
92 data: string | ArrayBuffer | ArrayBufferView,
93 inputEncoding?: string,
94 outputEncoding?: string
95 ): string | Buffer;
96 final(outputEncoding?: string): string | Buffer;
97 setAAD(
98 buffer: string | ArrayBuffer | ArrayBufferView,
99 options?: AADOptions
100 ): this;
101 setAutoPadding(autoPadding?: boolean): this;
102 getAuthTag(): Buffer | undefined;
103}
104 
105export interface Decipheriv extends Transform {
106 [kHandle]: CipherHandle | AeadHandle;
107 update(
108 data: string | ArrayBuffer | ArrayBufferView,
109 inputEncoding?: string,
110 outputEncoding?: string
111 ): string | Buffer;
112 final(outputEncoding?: string): string | Buffer;
113 setAAD(
114 buffer: string | ArrayBuffer | ArrayBufferView,
115 options?: AADOptions
116 ): this;
117 setAutoPadding(autoPadding?: boolean): this;
118 setAuthTag(buffer: ArrayBuffer | ArrayBufferView): this;
119 setAuthTag(buffer: string, encoding?: string): this;
120}
121 
122export interface CipherOptions extends TransformOptions {
123 authLengthTag?: number;
124}
125 
126function getSecretKey(
127 key: string | ArrayBuffer | ArrayBufferView | KeyObject | CryptoKey
128): CryptoKey {
129 if (key instanceof CryptoKey) {
130 if (key.type !== 'secret') {
131 throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(key.type, 'secret');
132 }
133 return key;
134 } else if (isKeyObject(key)) {
135 if (key.type !== 'secret') {
136 throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(key.type, 'secret');
137 }
138 return getKeyObjectHandle(key);
139 } else if (isAnyArrayBuffer(key) || isArrayBufferView(key)) {
140 return getKeyObjectHandle(createSecretKey(key));
141 } else if (typeof key === 'string') {
142 return getKeyObjectHandle(createSecretKey(key, 'utf8'));
143 }
144 
145 throw new ERR_INVALID_ARG_TYPE(
146 'key',
147 ['string', 'Buffer', 'TypedArray', 'DataView', 'KeyObject', 'CryptoKey'],
148 key
149 );
150}
151 
152function getIv(
153 iv: string | ArrayBuffer | ArrayBufferView | null
154): ArrayBuffer | ArrayBufferView {
155 if (isAnyArrayBuffer(iv) || isArrayBufferView(iv)) {
156 return iv;
157 } else if (typeof iv === 'string') {
158 return Buffer.from(iv, 'utf8');
159 }
160 
161 throw new ERR_INVALID_ARG_TYPE(
162 'iv',
163 ['string', 'Buffer', 'TypedArray', 'DataView', 'null'],
164 iv
165 );
166}
167 
168export const Cipheriv = function (
169 this: Cipheriv,
170 algorithm: string,
171 key: string | ArrayBuffer | ArrayBufferView | KeyObject | CryptoKey,
172 iv: string | ArrayBuffer | ArrayBufferView | null,
173 options: CipherOptions = {}
174) {
175 validateString(algorithm, 'algorithm');
176 const secretKey = getSecretKey(key);
177 const ivBuf = getIv(iv);
178 
179 if (options.authLengthTag !== undefined) {
180 validateUint32(options.authLengthTag, 'options.authLengthTag');
181 }
182 this[kHandle] = cryptoImpl.newHandle(
183 CipherMode.CIPHER,
184 algorithm,
185 secretKey,
186 ivBuf,
187 options.authLengthTag
188 );
189 
190 Transform.call(this, options as TransformOptions);
191} as unknown as {
192 new (
193 algorithm: string,
194 key: string | ArrayBuffer | ArrayBufferView | KeyObject | CryptoKey,
195 iv: string | ArrayBuffer | ArrayBufferView | null,
196 options?: TransformOptions
197 ): Cipheriv;
198};
199Object.setPrototypeOf(Cipheriv.prototype, Transform.prototype);
200Object.setPrototypeOf(Cipheriv, Transform);
201 
202// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
203Cipheriv.prototype.update = function (
204 this: Cipheriv,
205 data: string | ArrayBuffer | ArrayBufferView,
206 inputEncoding?: string,
207 outputEncoding?: string
208): string | Buffer {
209 let ret: ArrayBuffer;
210 if (typeof data === 'string') {
211 if (inputEncoding === undefined) {
212 throw new ERR_INVALID_ARG_VALUE(
213 'inputEncoding',
214 inputEncoding,
215 'If inputEncoding is not provided then the data must be a Buffer'
216 );
217 }
218 ret = this[kHandle].update(Buffer.from(data, inputEncoding));
219 } else if (isAnyArrayBuffer(data)) {
220 ret = this[kHandle].update(data);
221 } else if (isArrayBufferView(data)) {
222 ret = this[kHandle].update(data);
223 } else {
224 throw new ERR_INVALID_ARG_TYPE(
225 'data',
226 ['string', 'Buffer', 'TypedArray', 'DataView'],
227 data
228 );
229 }
230 
231 if (outputEncoding === undefined) {
232 return Buffer.from(ret);
233 }
234 
235 return Buffer.from(ret).toString(outputEncoding);
236};
237 
238// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
239Cipheriv.prototype.final = function (
240 this: Cipheriv,
241 outputEncoding?: string
242): string | Buffer {
243 const ret = this[kHandle].final();
244 if (outputEncoding === undefined) {
245 return Buffer.from(ret);
246 }
247 return Buffer.from(ret).toString(outputEncoding);
248};
249 
250// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
251Cipheriv.prototype.setAAD = function (
252 this: Cipheriv,
253 buffer: string | ArrayBuffer | ArrayBufferView,
254 options: AADOptions = {}
255): Cipheriv {
256 validateObject(options, 'options');
257 const { plaintextLength, encoding } = options;
258 if (plaintextLength !== undefined) {
259 validateUint32(plaintextLength, 'options.plaintextLength');
260 }
261 if (encoding !== undefined) {
262 validateString(encoding, 'options.encoding');
263 }
264 
265 if (typeof buffer === 'string') {
266 this[kHandle].setAAD(Buffer.from(buffer, encoding), plaintextLength);
267 } else if (isAnyArrayBuffer(buffer) || isArrayBufferView(buffer)) {
268 this[kHandle].setAAD(buffer, plaintextLength);
269 }
270 return this;
271};
272 
273// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
274Cipheriv.prototype.setAutoPadding = function (
275 this: Cipheriv,
276 autoPadding?: boolean
277): Cipheriv {
278 this[kHandle].setAutoPadding(autoPadding ? true : false);
279 return this;
280};
281 
282// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
283Cipheriv.prototype.getAuthTag = function (this: Cipheriv): Buffer | undefined {
284 const ret = this[kHandle].getAuthTag();
285 if (ret === undefined) return undefined;
286 return Buffer.from(ret);
287};
288 
289// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
290Cipheriv.prototype._transform = function (
291 this: Cipheriv,
292 chunk: string | Buffer | ArrayBufferView,
293 encoding: string,
294 callback: TransformCallback
295): void {
296 if (typeof chunk === 'string') {
297 chunk = Buffer.from(chunk, encoding);
298 }
299 this.push(Buffer.from(this[kHandle].update(chunk)));
300 callback();
301};
302 
303// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
304Cipheriv.prototype._flush = function (
305 this: Cipheriv,
306 callback: TransformCallback
307): void {
308 this.push(Buffer.from(this[kHandle].final()));
309 callback();
310};
311 
312export const Decipheriv = function (
313 this: Decipheriv,
314 algorithm: string,
315 key: string | ArrayBuffer | ArrayBufferView | KeyObject | CryptoKey,
316 iv: string | ArrayBuffer | ArrayBufferView | null,
317 options: CipherOptions = {}
318) {
319 validateString(algorithm, 'algorithm');
320 const secretKey = getSecretKey(key);
321 const ivBuf = getIv(iv);
322 
323 if (options.authLengthTag !== undefined) {
324 validateUint32(options.authLengthTag, 'options.authLengthTag');
325 }
326 
327 this[kHandle] = cryptoImpl.newHandle(
328 CipherMode.DECIPHER,
329 algorithm,
330 secretKey,
331 ivBuf,
332 options.authLengthTag
333 );
334 
335 Transform.call(this, options as TransformOptions);
336 return this;
337} as unknown as {
338 new (
339 algorithm: string,
340 key: string | ArrayBuffer | ArrayBufferView | KeyObject | CryptoKey,
341 iv: string | ArrayBuffer | ArrayBufferView | null,
342 options?: TransformOptions
343 ): Decipheriv;
344};
345 
346Object.setPrototypeOf(Decipheriv.prototype, Transform.prototype);
347Object.setPrototypeOf(Decipheriv, Transform);
348 
349// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
350Decipheriv.prototype.update = function (
351 this: Decipheriv,
352 data: string | ArrayBuffer | ArrayBufferView,
353 inputEncoding?: string,
354 outputEncoding?: string
355): string | Buffer {
356 let ret: ArrayBuffer;
357 if (typeof data === 'string') {
358 if (inputEncoding === undefined) {
359 throw new ERR_INVALID_ARG_VALUE(
360 'inputEncoding',
361 inputEncoding,
362 'If inputEncoding is not provided then the data must be a Buffer'
363 );
364 }
365 ret = this[kHandle].update(Buffer.from(data, inputEncoding));
366 } else if (isAnyArrayBuffer(data)) {
367 ret = this[kHandle].update(data);
368 } else if (isArrayBufferView(data)) {
369 ret = this[kHandle].update(data);
370 } else {
371 throw new ERR_INVALID_ARG_TYPE(
372 'data',
373 ['string', 'Buffer', 'TypedArray', 'DataView'],
374 data
375 );
376 }
377 
378 if (outputEncoding === undefined) {
379 return Buffer.from(ret);
380 }
381 
382 return Buffer.from(ret).toString(outputEncoding);
383};
384 
385// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
386Decipheriv.prototype.final = function (
387 this: Decipheriv,
388 outputEncoding?: string
389): string | Buffer {
390 const ret = this[kHandle].final();
391 if (outputEncoding === undefined) {
392 return Buffer.from(ret);
393 }
394 return Buffer.from(ret).toString(outputEncoding);
395};
396 
397// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
398Decipheriv.prototype.setAAD = function (
399 this: Decipheriv,
400 buffer: string | ArrayBuffer | ArrayBufferView,
401 options: AADOptions = {}
402): Decipheriv {
403 validateObject(options, 'options');
404 const { plaintextLength, encoding } = options;
405 if (plaintextLength !== undefined) {
406 validateUint32(plaintextLength, 'options.plaintextLength');
407 }
408 if (encoding !== undefined) {
409 validateString(encoding, 'options.encoding');
410 }
411 
412 if (typeof buffer === 'string') {
413 this[kHandle].setAAD(Buffer.from(buffer, encoding), plaintextLength);
414 } else if (isAnyArrayBuffer(buffer) || isArrayBufferView(buffer)) {
415 this[kHandle].setAAD(buffer, plaintextLength);
416 }
417 return this;
418};
419 
420// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
421Decipheriv.prototype.setAutoPadding = function (
422 this: Decipheriv,
423 autoPadding?: boolean
424): Decipheriv {
425 this[kHandle].setAutoPadding(autoPadding ? true : false);
426 return this;
427};
428 
429// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
430Decipheriv.prototype.setAuthTag = function (
431 this: Decipheriv,
432 buffer: ArrayBuffer | ArrayBufferView
433): Decipheriv {
434 this[kHandle].setAuthTag(buffer);
435 return this;
436};
437 
438// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
439Decipheriv.prototype._transform = function (
440 this: Decipheriv,
441 chunk: string | Buffer | ArrayBufferView,
442 encoding: string,
443 callback: TransformCallback
444): void {
445 if (typeof chunk === 'string') {
446 chunk = Buffer.from(chunk, encoding);
447 }
448 this.push(Buffer.from(this[kHandle].update(chunk)));
449 callback();
450};
451 
452// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
453Decipheriv.prototype._flush = function (
454 this: Decipheriv,
455 callback: TransformCallback
456): void {
457 this.push(Buffer.from(this[kHandle].final()));
458 callback();
459};
460 
461export function createCipheriv(
462 algorithm: string,
463 key: string | ArrayBuffer | ArrayBufferView | KeyObject | CryptoKey,
464 iv: string | ArrayBuffer | ArrayBufferView | null,
465 options: TransformOptions = {}
466): Cipheriv {
467 return new Cipheriv(algorithm, key, iv, options);
468}
469 
470export function createDecipheriv(
471 algorithm: string,
472 key: string | ArrayBuffer | ArrayBufferView | KeyObject | CryptoKey,
473 iv: string | ArrayBuffer | ArrayBufferView | null,
474 options: TransformOptions = {}
475): Decipheriv {
476 return new Decipheriv(algorithm, key, iv, options);
477}
478 
479// ======================================================================================
480 
481interface HashOptions {
482 padding?: number;
483 oaepHash?: string;
484 oaepLabel?: string | ArrayBuffer | ArrayBufferView;
485 encoding?: string;
486}
487 
488export const kRsaPkcs1Padding = 1;
489export const kRsaNoPadding = 3;
490export const kRsaPkcs1OaepPadding = 4;
491 
492function getPaddingAndHash(options: HashOptions): PublicPrivateCipherOptions {
493 const {
494 padding = kRsaPkcs1Padding,
495 oaepHash = 'sha256',
496 oaepLabel,
497 encoding = 'utf8',
498 } = options;
499 
500 validateNumber(padding, 'options.padding');
501 validateString(oaepHash, 'options.oaepHash');
502 
503 let label: ArrayBufferView | ArrayBuffer | undefined;
504 if (oaepLabel !== undefined) {
505 if (typeof oaepLabel === 'string') {
506 label = Buffer.from(oaepLabel, encoding);
507 } else if (isAnyArrayBuffer(oaepLabel) || isArrayBufferView(oaepLabel)) {
508 label = oaepLabel;
509 } else {
510 throw new ERR_INVALID_ARG_TYPE(
511 'options.oaepLabel',
512 ['string', 'Buffer', 'TypedArray', 'DataView', 'ArrayBuffer'],
513 oaepLabel
514 );
515 }
516 }
517 
518 return { padding, oaepHash, oaepLabel: label };
519}
520 
521export function privateEncrypt(
522 privateKey: CreateAsymmetricKeyOptions | KeyObject | CryptoKey | undefined,
523 buffer: string | ArrayBufferView | ArrayBuffer | undefined
524): Buffer {
525 if (privateKey === undefined) {
526 throw new ERR_MISSING_ARGS('privateKey');
527 }
528 if (buffer === undefined) {
529 throw new ERR_MISSING_ARGS('buffer');
530 }
531 const key = ((): CryptoKey => {
532 if (privateKey instanceof CryptoKey) {
533 if (privateKey.type !== 'private') {
534 throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(
535 privateKey.type,
536 'private'
537 );
538 }
539 return privateKey;
540 } else if (isKeyObject(privateKey)) {
541 if (privateKey.type !== 'private') {
542 throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(
543 privateKey.type,
544 'private'
545 );
546 }
547 return getKeyObjectHandle(privateKey);
548 } else {
549 const pvtKey = createPrivateKey(privateKey);
550 return getKeyObjectHandle(pvtKey);
551 }
552 })();
553 if (typeof buffer === 'string') {
554 const { encoding = 'utf8' } = privateKey as { encoding?: string };
555 buffer = Buffer.from(buffer, encoding);
556 }
557 
558 return Buffer.from(
559 cryptoImpl.privateEncrypt(
560 key,
561 buffer,
562 getPaddingAndHash(privateKey as HashOptions)
563 )
564 );
565}
566 
567export function privateDecrypt(
568 privateKey: CreateAsymmetricKeyOptions | KeyData,
569 buffer: string | ArrayBufferView | ArrayBuffer
570): Buffer {
571 // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
572 if (privateKey === undefined) {
573 throw new ERR_MISSING_ARGS('privateKey');
574 }
575 // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
576 if (buffer === undefined) {
577 throw new ERR_MISSING_ARGS('buffer');
578 }
579 const key = ((): CryptoKey => {
580 if (privateKey instanceof CryptoKey) {
581 if (privateKey.type !== 'private') {
582 throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(
583 privateKey.type,
584 'private'
585 );
586 }
587 return privateKey;
588 } else if (isKeyObject(privateKey)) {
589 if (privateKey.type !== 'private') {
590 throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(
591 privateKey.type,
592 'private'
593 );
594 }
595 return getKeyObjectHandle(privateKey);
596 } else {
597 const pvtKey = createPrivateKey(privateKey as CreateAsymmetricKeyOptions);
598 return getKeyObjectHandle(pvtKey);
599 }
600 })();
601 if (typeof buffer === 'string') {
602 const { encoding = 'utf8' } = privateKey as { encoding?: string };
603 buffer = Buffer.from(buffer, encoding);
604 }
605 
606 return Buffer.from(
607 cryptoImpl.privateDecrypt(
608 key,
609 buffer,
610 getPaddingAndHash(privateKey as HashOptions)
611 )
612 );
613}
614 
615export function publicEncrypt(
616 key: CreateAsymmetricKeyOptions | KeyData,
617 buffer: string | ArrayBufferView | ArrayBuffer
618): Buffer {
619 // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
620 if (key === undefined) {
621 throw new ERR_MISSING_ARGS('key');
622 }
623 // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
624 if (buffer === undefined) {
625 throw new ERR_MISSING_ARGS('buffer');
626 }
627 const pkey = ((): CryptoKey => {
628 if (key instanceof CryptoKey) {
629 if (key.type !== 'public') {
630 throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(key.type, 'public');
631 }
632 return key;
633 } else if (isKeyObject(key)) {
634 if (key.type !== 'public') {
635 throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(key.type, 'public');
636 }
637 return getKeyObjectHandle(key);
638 } else {
639 const pubKey = createPublicKey(key as CreateAsymmetricKeyOptions);
640 return getKeyObjectHandle(pubKey);
641 }
642 })();
643 if (typeof buffer === 'string') {
644 const { encoding = 'utf8' } = key as { encoding?: string };
645 buffer = Buffer.from(buffer, encoding);
646 }
647 
648 return Buffer.from(
649 cryptoImpl.publicEncrypt(
650 pkey,
651 buffer,
652 getPaddingAndHash(key as HashOptions)
653 )
654 );
655}
656 
657export function publicDecrypt(
658 key: CreateAsymmetricKeyOptions | KeyData,
659 buffer: string | ArrayBufferView | ArrayBuffer
660): Buffer {
661 // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
662 if (key === undefined) {
663 throw new ERR_MISSING_ARGS('key');
664 }
665 // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
666 if (buffer === undefined) {
667 throw new ERR_MISSING_ARGS('buffer');
668 }
669 const pkey = ((): CryptoKey => {
670 if (key instanceof CryptoKey) {
671 if (key.type !== 'public') {
672 throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(key.type, 'public');
673 }
674 return key;
675 } else if (isKeyObject(key)) {
676 if (key.type !== 'public') {
677 throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(key.type, 'public');
678 }
679 return getKeyObjectHandle(key);
680 } else {
681 const pubKey = createPublicKey(key as CreateAsymmetricKeyOptions);
682 return getKeyObjectHandle(pubKey);
683 }
684 })();
685 if (typeof buffer === 'string') {
686 const { encoding = 'utf8' } = key as { encoding?: string };
687 buffer = Buffer.from(buffer, encoding);
688 }
689 
690 return Buffer.from(
691 cryptoImpl.publicDecrypt(
692 pkey,
693 buffer,
694 getPaddingAndHash(key as HashOptions)
695 )
696 );
697}
698 
699export function getCipherInfo(
700 nameOrId: string | number,
701 options: GetCipherInfoOptions = {}
702): CipherInfo | undefined {
703 if (typeof nameOrId !== 'string' && typeof nameOrId !== 'number') {
704 throw new ERR_INVALID_ARG_TYPE('nameOrId', ['string', 'number'], nameOrId);
705 }
706 
707 validateObject(options, 'options');
708 
709 return cryptoImpl.getCipherInfo(nameOrId, options);
710}
711 
712export const getCiphers = cryptoImpl.getCiphers.bind(cryptoImpl);