@@ -67,12 +67,14 @@ import {
67
67
} from 'node-internal:internal_errors' ;
68
68
69
69
import {
70
+ validateInteger ,
70
71
validateObject ,
71
72
validateOneOf ,
72
73
validateString ,
73
74
} from 'node-internal:validators' ;
74
75
75
76
import { inspect } from 'node-internal:internal_inspect' ;
77
+ import { randomBytes } from 'node-internal:crypto_random' ;
76
78
const kInspect = inspect . custom ;
77
79
78
80
// Key input contexts.
@@ -515,7 +517,7 @@ export function createPublicKey(
515
517
516
518
export type PublicKeyResult = KeyExportResult | PublicKeyObject ;
517
519
export type PrivateKeyResult = KeyExportResult | PrivateKeyObject ;
518
- export type GenerateKeyCallback = ( err ?: any , key ?: KeyObject ) => void ;
520
+ export type GenerateKeyCallback = ( err ?: any , key ?: SecretKeyObject ) => void ;
519
521
export type GenerateKeyPairCallback = (
520
522
err ?: any ,
521
523
publicKey ?: PublicKeyResult ,
@@ -532,25 +534,87 @@ export function generateKey(
532
534
_options : GenerateKeyOptions ,
533
535
callback : GenerateKeyCallback
534
536
) {
535
- // This API is not implemented yet.
536
- callback ( new ERR_METHOD_NOT_IMPLEMENTED ( 'crypto.generateKeySync' ) ) ;
537
- }
538
-
539
- export function generateKeySync (
540
- _type : SecretKeyType ,
541
- _options : GenerateKeyOptions
542
- ) {
543
- // This API is not implemented yet.
544
- throw new ERR_METHOD_NOT_IMPLEMENTED ( 'crypto.generateKeySync' ) ;
537
+ try {
538
+ // Unlike Node.js, which implements async crypto functions using the
539
+ // libuv thread pool, we don't actually perform async crypto operations.
540
+ // Here we just defer to the sync version of the function and then "fake"
541
+ // async by using queueMicrotask to call the callback.
542
+ const result = generateKeySync ( _type , _options ) ;
543
+ queueMicrotask ( ( ) => {
544
+ try {
545
+ callback ( null , result ) ;
546
+ } catch ( err ) {
547
+ reportError ( err ) ;
548
+ }
549
+ } ) ;
550
+ } catch ( err ) {
551
+ queueMicrotask ( ( ) => {
552
+ try {
553
+ callback ( err ) ;
554
+ } catch ( otherErr ) {
555
+ reportError ( otherErr ) ;
556
+ }
557
+ } ) ;
558
+ }
545
559
}
546
560
547
561
export function generateKeyPair (
548
562
_type : AsymmetricKeyType ,
549
563
_options : GenerateKeyPairOptions ,
550
564
callback : GenerateKeyPairCallback
551
565
) {
552
- // This API is not implemented yet.
553
- callback ( new ERR_METHOD_NOT_IMPLEMENTED ( 'crypto.generateKeyPair' ) ) ;
566
+ try {
567
+ // Unlike Node.js, which implements async crypto functions using the
568
+ // libuv thread pool, we don't actually perform async crypto operations.
569
+ // Here we just defer to the sync version of the function and then "fake"
570
+ // async by using queueMicrotask to call the callback.
571
+ const { publicKey, privateKey } = generateKeyPairSync ( _type , _options ) ;
572
+ queueMicrotask ( ( ) => {
573
+ try {
574
+ callback ( null , publicKey , privateKey ) ;
575
+ } catch ( err ) {
576
+ reportError ( err ) ;
577
+ }
578
+ } ) ;
579
+ } catch ( err ) {
580
+ queueMicrotask ( ( ) => {
581
+ try {
582
+ callback ( err ) ;
583
+ } catch ( otherErr ) {
584
+ reportError ( otherErr ) ;
585
+ }
586
+ } ) ;
587
+ }
588
+ }
589
+
590
+ export function generateKeySync (
591
+ type : SecretKeyType ,
592
+ options : GenerateKeyOptions
593
+ ) : SecretKeyObject {
594
+ validateOneOf ( type , 'type' , [ 'hmac' , 'aes' ] ) ;
595
+ validateObject ( options , 'options' ) ;
596
+ const { length } = options ;
597
+
598
+ switch ( type ) {
599
+ case 'hmac' : {
600
+ // The minimum is 8, and the maximum length is 65,536. If the length is
601
+ // not a multiple of 8, the generated key will be truncated to
602
+ // Math.floor(length / 8).
603
+ // Note that the upper bound of 65536 is intentionally more limited than
604
+ // what Node.js allows. This puts the maximum size limit on generated
605
+ // secret keys to 8192 bytes. We can adjust this up if necessary but
606
+ // it's a good starting point.
607
+ validateInteger ( length , 'options.length' , 8 , 65536 ) ;
608
+ const buf = randomBytes ( Math . floor ( length / 8 ) ) ;
609
+ return createSecretKey ( buf ) ;
610
+ }
611
+ case 'aes' : {
612
+ // The length must be one of 128, 192, or 256.
613
+ validateOneOf ( length , 'options.length' , [ 128 , 192 , 256 ] ) ;
614
+ const buf = randomBytes ( length / 8 ) ;
615
+ return createSecretKey ( buf ) ;
616
+ }
617
+ }
554
618
}
555
619
556
620
export function generateKeyPairSync (
0 commit comments