@@ -326,6 +326,12 @@ class AsymmetricKey final: public CryptoKey::Impl {
326
326
ncrypto::EVPKeyPointer key;
327
327
bool isPrivate;
328
328
};
329
+
330
+ int getCurveFromName (kj::StringPtr name) {
331
+ int nid = EC_curve_nist2nid (name.begin ());
332
+ if (nid == NID_undef) nid = OBJ_sn2nid (name.begin ());
333
+ return nid;
334
+ }
329
335
} // namespace
330
336
331
337
kj::OneOf<kj::String, jsg::BufferSource, SubtleCrypto::JsonWebKey> CryptoImpl::exportKey (
@@ -635,15 +641,140 @@ CryptoKeyPair CryptoImpl::generateDsaKeyPair(DsaKeyPairOptions options) {
635
641
}
636
642
637
643
CryptoKeyPair CryptoImpl::generateEcKeyPair (EcKeyPairOptions options) {
638
- JSG_FAIL_REQUIRE (Error, " Not yet implemented" );
644
+ ncrypto::ClearErrorOnReturn clearErrorOnReturn;
645
+
646
+ auto nid = getCurveFromName (options.namedCurve );
647
+ JSG_REQUIRE (nid != NID_undef, Error, " Invalid or unsupported curve" );
648
+
649
+ auto paramEncoding =
650
+ options.paramEncoding == " named" _kj ? OPENSSL_EC_NAMED_CURVE : OPENSSL_EC_EXPLICIT_CURVE;
651
+
652
+ auto ecPrivateKey = ncrypto::ECKeyPointer::NewByCurveName (nid);
653
+ JSG_REQUIRE (ecPrivateKey, Error, " Failed to initialize key" );
654
+ JSG_REQUIRE (ecPrivateKey.generate (), Error, " Failed to generate private key" );
655
+
656
+ EC_KEY_set_enc_flags (ecPrivateKey, paramEncoding);
657
+
658
+ auto ecPublicKey = ncrypto::ECKeyPointer::NewByCurveName (nid);
659
+ JSG_REQUIRE (EC_KEY_set_public_key (ecPublicKey, EC_KEY_get0_public_key (ecPrivateKey)), Error,
660
+ " Failed to derive public key" );
661
+
662
+ auto privateKey = ncrypto::EVPKeyPointer::New ();
663
+ JSG_REQUIRE (privateKey.assign (ecPrivateKey), Error, " Failed to assign private key" );
664
+
665
+ auto publicKey = ncrypto::EVPKeyPointer::New ();
666
+ JSG_REQUIRE (publicKey.assign (ecPublicKey), Error, " Failed to assign public key" );
667
+
668
+ ecPrivateKey.release ();
669
+ ecPublicKey.release ();
670
+
671
+ auto pubKey = AsymmetricKey::NewPublic (kj::mv (publicKey));
672
+ JSG_REQUIRE (pubKey, Error, " Failed to create public key" );
673
+ auto pvtKey = AsymmetricKey::NewPrivate (kj::mv (privateKey));
674
+ JSG_REQUIRE (pvtKey, Error, " Failed to create private key" );
675
+
676
+ return CryptoKeyPair{
677
+ .publicKey = jsg::alloc<CryptoKey>(kj::mv (pubKey)),
678
+ .privateKey = jsg::alloc<CryptoKey>(kj::mv (pvtKey)),
679
+ };
639
680
}
640
681
641
682
CryptoKeyPair CryptoImpl::generateEdKeyPair (EdKeyPairOptions options) {
642
- JSG_FAIL_REQUIRE (Error, " Not yet implemented" );
683
+ ncrypto::ClearErrorOnReturn clearErrorOnReturn;
684
+
685
+ auto nid = ([&] {
686
+ if (options.type == " ed25519" ) {
687
+ return EVP_PKEY_ED25519;
688
+ }
689
+ if (options.type == " x25519" ) {
690
+ return EVP_PKEY_X25519;
691
+ }
692
+ return NID_undef;
693
+ })();
694
+ JSG_REQUIRE (nid != NID_undef, Error, " Invalid or unsupported curve" );
695
+
696
+ auto ctx = ncrypto::EVPKeyCtxPointer::NewFromID (nid);
697
+ JSG_REQUIRE (ctx, Error, " Failed to create keygen context" );
698
+ JSG_REQUIRE (ctx.initForKeygen (), Error, " Failed to initialize keygen" );
699
+
700
+ // Generate the key
701
+ EVP_PKEY* pkey = nullptr ;
702
+ JSG_REQUIRE (EVP_PKEY_keygen (ctx.get (), &pkey), Error, " Failed to generate key" );
703
+
704
+ auto generated = ncrypto::EVPKeyPointer (pkey);
705
+
706
+ auto publicKey = AsymmetricKey::NewPublic (generated.clone ());
707
+ JSG_REQUIRE (publicKey, Error, " Failed to create public key" );
708
+ auto privateKey = AsymmetricKey::NewPrivate (kj::mv (generated));
709
+ JSG_REQUIRE (privateKey, Error, " Failed to create private key" );
710
+
711
+ return CryptoKeyPair{
712
+ .publicKey = jsg::alloc<CryptoKey>(kj::mv (publicKey)),
713
+ .privateKey = jsg::alloc<CryptoKey>(kj::mv (privateKey)),
714
+ };
643
715
}
644
716
645
- CryptoKeyPair CryptoImpl::generateDhKeyPair (kj::OneOf<DhKeyPairOptions, kj::String>) {
646
- JSG_FAIL_REQUIRE (Error, " Not yet implemented" );
717
+ CryptoKeyPair CryptoImpl::generateDhKeyPair (DhKeyPairOptions options) {
718
+ ncrypto::ClearErrorOnReturn clearErrorOnReturn;
719
+
720
+ static constexpr uint32_t kStandardizedGenerator = 2 ;
721
+
722
+ ncrypto::EVPKeyPointer key_params;
723
+ auto generator = options.generator .orDefault (kStandardizedGenerator );
724
+
725
+ KJ_SWITCH_ONEOF (options.primeOrGroup ) {
726
+ KJ_CASE_ONEOF (group, kj::String) {
727
+ std::string_view group_name (group.begin (), group.size ());
728
+ auto found = ncrypto::DHPointer::FindGroup (group_name);
729
+ JSG_REQUIRE (found, Error, " Invalid or unsupported group" );
730
+
731
+ auto bn_g = ncrypto::BignumPointer::New ();
732
+ JSG_REQUIRE (bn_g && bn_g.setWord (generator), Error, " Failed to set generator" );
733
+
734
+ auto dh = ncrypto::DHPointer::New (kj::mv (found), kj::mv (bn_g));
735
+ JSG_REQUIRE (dh, Error, " Failed to create DH key" );
736
+
737
+ key_params = ncrypto::EVPKeyPointer::NewDH (kj::mv (dh));
738
+ }
739
+ KJ_CASE_ONEOF (prime, jsg::BufferSource) {
740
+ ncrypto::BignumPointer bn (prime.asArrayPtr ().begin (), prime.size ());
741
+
742
+ auto bn_g = ncrypto::BignumPointer::New ();
743
+ JSG_REQUIRE (bn_g && bn_g.setWord (generator), Error, " Failed to set generator" );
744
+
745
+ auto dh = ncrypto::DHPointer::New (kj::mv (bn), kj::mv (bn_g));
746
+ JSG_REQUIRE (dh, Error, " Failed to create DH key" );
747
+
748
+ key_params = ncrypto::EVPKeyPointer::NewDH (kj::mv (dh));
749
+ }
750
+ KJ_CASE_ONEOF (length, uint32_t ) {
751
+ // TODO(later): BoringSSL appears to not implement DH key generation
752
+ // from a prime length the same way Node.js does. For now, defer this
753
+ // and come back to implement later.
754
+ JSG_FAIL_REQUIRE (Error, " Generating DH keys from a prime length is not yet implemented" );
755
+ }
756
+ }
757
+
758
+ JSG_REQUIRE (key_params, Error, " Failed to create keygen context" );
759
+ auto ctx = key_params.newCtx ();
760
+ JSG_REQUIRE (ctx, Error, " Failed to create keygen context" );
761
+ JSG_REQUIRE (ctx.initForKeygen (), Error, " Failed to initialize keygen context" );
762
+
763
+ // Generate the key
764
+ EVP_PKEY* pkey = nullptr ;
765
+ JSG_REQUIRE (EVP_PKEY_keygen (ctx.get (), &pkey), Error, " Failed to generate key" );
766
+
767
+ auto generated = ncrypto::EVPKeyPointer (pkey);
768
+
769
+ auto publicKey = AsymmetricKey::NewPublic (generated.clone ());
770
+ JSG_REQUIRE (publicKey, Error, " Failed to create public key" );
771
+ auto privateKey = AsymmetricKey::NewPrivate (kj::mv (generated));
772
+ JSG_REQUIRE (privateKey, Error, " Failed to create private key" );
773
+
774
+ return CryptoKeyPair{
775
+ .publicKey = jsg::alloc<CryptoKey>(kj::mv (publicKey)),
776
+ .privateKey = jsg::alloc<CryptoKey>(kj::mv (privateKey)),
777
+ };
647
778
}
648
779
649
780
} // namespace workerd::api::node
0 commit comments