From ec015034bd9dbc0a57fe748e5b4c4f6af5c3255a Mon Sep 17 00:00:00 2001 From: stelar7 Date: Sun, 31 Mar 2024 23:04:12 +0200 Subject: [PATCH] LibWeb: Implement ED25519 generateKey for SubtleCrypto --- .../LibWeb/Crypto/CryptoAlgorithms.cpp | 68 +++++++++++++++++++ .../LibWeb/Crypto/CryptoAlgorithms.h | 13 ++++ .../Libraries/LibWeb/Crypto/SubtleCrypto.cpp | 3 + 3 files changed, 84 insertions(+) diff --git a/Userland/Libraries/LibWeb/Crypto/CryptoAlgorithms.cpp b/Userland/Libraries/LibWeb/Crypto/CryptoAlgorithms.cpp index 7a5d239d240..3f2cd6298b8 100644 --- a/Userland/Libraries/LibWeb/Crypto/CryptoAlgorithms.cpp +++ b/Userland/Libraries/LibWeb/Crypto/CryptoAlgorithms.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -1210,4 +1211,71 @@ WebIDL::ExceptionOr ECDSA::verify(AlgorithmParams const& params, JS:: return JS::Value(result); } +// https://wicg.github.io/webcrypto-secure-curves/#ed25519-operations +WebIDL::ExceptionOr, JS::NonnullGCPtr>> ED25519::generate_key([[maybe_unused]] AlgorithmParams const& params, bool extractable, Vector const& key_usages) +{ + // 1. If usages contains a value which is not one of "sign" or "verify", then throw a SyntaxError. + for (auto const& usage : key_usages) { + if (usage != Bindings::KeyUsage::Sign && usage != Bindings::KeyUsage::Verify) { + return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage)))); + } + } + + // 2. Generate an Ed25519 key pair, as defined in [RFC8032], section 5.1.5. + ::Crypto::Curves::Ed25519 curve; + auto maybe_private_key = curve.generate_private_key(); + if (maybe_private_key.is_error()) + return WebIDL::OperationError::create(m_realm, "Failed to generate private key"_fly_string); + auto private_key_data = maybe_private_key.release_value(); + + auto maybe_public_key = curve.generate_public_key(private_key_data); + if (maybe_public_key.is_error()) + return WebIDL::OperationError::create(m_realm, "Failed to generate public key"_fly_string); + auto public_key_data = maybe_public_key.release_value(); + + // 3. Let algorithm be a new KeyAlgorithm object. + auto algorithm = KeyAlgorithm::create(m_realm); + + // 4. Set the name attribute of algorithm to "Ed25519". + algorithm->set_name("Ed25519"_string); + + // 5. Let publicKey be a new CryptoKey associated with the relevant global object of this [HTML], + // and representing the public key of the generated key pair. + auto public_key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { public_key_data }); + + // 6. Set the [[type]] internal slot of publicKey to "public" + public_key->set_type(Bindings::KeyType::Public); + + // 7. Set the [[algorithm]] internal slot of publicKey to algorithm. + public_key->set_algorithm(algorithm); + + // 8. Set the [[extractable]] internal slot of publicKey to true. + public_key->set_extractable(true); + + // 9. Set the [[usages]] internal slot of publicKey to be the usage intersection of usages and [ "verify" ]. + public_key->set_usages(usage_intersection(key_usages, { { Bindings::KeyUsage::Verify } })); + + // 10. Let privateKey be a new CryptoKey associated with the relevant global object of this [HTML], + // and representing the private key of the generated key pair. + auto private_key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { private_key_data }); + + // 11. Set the [[type]] internal slot of privateKey to "private" + private_key->set_type(Bindings::KeyType::Private); + + // 12. Set the [[algorithm]] internal slot of privateKey to algorithm. + private_key->set_algorithm(algorithm); + + // 13. Set the [[extractable]] internal slot of privateKey to extractable. + private_key->set_extractable(extractable); + + // 14. Set the [[usages]] internal slot of privateKey to be the usage intersection of usages and [ "sign" ]. + private_key->set_usages(usage_intersection(key_usages, { { Bindings::KeyUsage::Sign } })); + + // 15. Let result be a new CryptoKeyPair dictionary. + // 16. Set the publicKey attribute of result to be publicKey. + // 17. Set the privateKey attribute of result to be privateKey. + // 18. Return the result of converting result to an ECMAScript Object, as defined by [WebIDL]. + return Variant, JS::NonnullGCPtr> { CryptoKeyPair::create(m_realm, public_key, private_key) }; +} + } diff --git a/Userland/Libraries/LibWeb/Crypto/CryptoAlgorithms.h b/Userland/Libraries/LibWeb/Crypto/CryptoAlgorithms.h index d298bc8a245..3955c83da70 100644 --- a/Userland/Libraries/LibWeb/Crypto/CryptoAlgorithms.h +++ b/Userland/Libraries/LibWeb/Crypto/CryptoAlgorithms.h @@ -264,6 +264,19 @@ private: } }; +class ED25519 : public AlgorithmMethods { +public: + virtual WebIDL::ExceptionOr, JS::NonnullGCPtr>> generate_key(AlgorithmParams const&, bool, Vector const&) override; + + static NonnullOwnPtr create(JS::Realm& realm) { return adopt_own(*new ED25519(realm)); } + +private: + explicit ED25519(JS::Realm& realm) + : AlgorithmMethods(realm) + { + } +}; + ErrorOr base64_url_uint_encode(::Crypto::UnsignedBigInteger); WebIDL::ExceptionOr<::Crypto::UnsignedBigInteger> base64_url_uint_decode(JS::Realm&, String const& base64_url_string); diff --git a/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.cpp b/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.cpp index a19feed59b8..bf9f2f230c9 100644 --- a/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.cpp +++ b/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.cpp @@ -644,6 +644,9 @@ SupportedAlgorithmsMap supported_algorithms() define_an_algorithm("verify"_string, "ECDSA"_string); define_an_algorithm("generateKey"_string, "ECDSA"_string); + // https://wicg.github.io/webcrypto-secure-curves/#ed25519 + define_an_algorithm("generateKey"_string, "Ed25519"_string); + return internal_object; }