diff --git a/Libraries/LibWeb/Crypto/CryptoAlgorithms.cpp b/Libraries/LibWeb/Crypto/CryptoAlgorithms.cpp index 3e88f43278..2241036c5c 100644 --- a/Libraries/LibWeb/Crypto/CryptoAlgorithms.cpp +++ b/Libraries/LibWeb/Crypto/CryptoAlgorithms.cpp @@ -9009,4 +9009,48 @@ WebIDL::ExceptionOr, GC::Ref>> MLKEM:: return WebIDL::ExceptionOr, GC::Ref>>(result); } +// https://wicg.github.io/webcrypto-modern-algos/#ml-kem-operations-encapsulate +WebIDL::ExceptionOr MLKEM::encapsulate(AlgorithmParams const& params, GC::Ref key) +{ + // 1. If the [[type]] internal slot of key is not "public", then throw an InvalidAccessError. + if (key->type() != Bindings::KeyType::Public) + return WebIDL::InvalidAccessError::create(m_realm, "Invalid key type"_utf16); + + // 2. Perform the encapsulation key check described in Section 7.2 of [FIPS-203] with the parameter set indicated + // by the name member of algorithm, using the key represented by the [[handle]] internal slot of key as the ek + // input parameter. + // 3. If the encapsulation key check failed, return an OperationError. + // NOTE: Presumably done by OpenSSL for us + + // 4. Let sharedKey and ciphertext be the outputs that result from performing the ML-KEM.Encaps function + // described in Section 7.2 of [FIPS-203] with the parameter set indicated by the name member of algorithm, + // using the key represented by the [[handle]] internal slot of key as the ek input parameter. + VERIFY(key->handle().has<::Crypto::PK::MLKEMPublicKey>()); + auto maybe_encapsulation = [&]() { + if (params.name == "ML-KEM-512") { + return ::Crypto::PK::MLKEM::encapsulate(::Crypto::PK::MLKEMSize::MLKEM512, key->handle().get<::Crypto::PK::MLKEMPublicKey>()); + } + if (params.name == "ML-KEM-768") { + return ::Crypto::PK::MLKEM::encapsulate(::Crypto::PK::MLKEMSize::MLKEM768, key->handle().get<::Crypto::PK::MLKEMPublicKey>()); + } + if (params.name == "ML-KEM-1024") { + return ::Crypto::PK::MLKEM::encapsulate(::Crypto::PK::MLKEMSize::MLKEM1024, key->handle().get<::Crypto::PK::MLKEMPublicKey>()); + } + VERIFY_NOT_REACHED(); + }(); + + // 5. If the ML-KEM.Encaps function returned an error, return an OperationError. + if (maybe_encapsulation.is_error()) + return WebIDL::OperationError::create(m_realm, Utf16String::formatted("Key encapsulation failed: {}", maybe_encapsulation.release_error())); + auto const [shared_key, ciphertext] = maybe_encapsulation.release_value(); + + // 6. Let result be a new EncapsulatedBits dictionary. + // 7. Set the sharedKey attribute of result to the result of creating an ArrayBuffer containing sharedKey. + // 8. Set the ciphertext attribute of result to the result of creating an ArrayBuffer containing ciphertext. + auto result = EncapsulatedBits { shared_key, ciphertext }; + + // 9. Return result. + return result; +} + } diff --git a/Libraries/LibWeb/Crypto/CryptoAlgorithms.h b/Libraries/LibWeb/Crypto/CryptoAlgorithms.h index 28c2eb0e7f..b7ec1cb077 100644 --- a/Libraries/LibWeb/Crypto/CryptoAlgorithms.h +++ b/Libraries/LibWeb/Crypto/CryptoAlgorithms.h @@ -710,6 +710,7 @@ private: class MLKEM : public AlgorithmMethods { public: virtual WebIDL::ExceptionOr, GC::Ref>> generate_key(AlgorithmParams const&, bool, Vector const&) override; + virtual WebIDL::ExceptionOr encapsulate(AlgorithmParams const&, GC::Ref) override; static NonnullOwnPtr create(JS::Realm& realm) { return adopt_own(*new MLKEM(realm)); } diff --git a/Libraries/LibWeb/Crypto/SubtleCrypto.cpp b/Libraries/LibWeb/Crypto/SubtleCrypto.cpp index feabb9c566..41843a166a 100644 --- a/Libraries/LibWeb/Crypto/SubtleCrypto.cpp +++ b/Libraries/LibWeb/Crypto/SubtleCrypto.cpp @@ -1443,6 +1443,8 @@ SupportedAlgorithmsMap const& supported_algorithms() "importKey"_string, "exportKey"_string, "get key length"_string, + "encapsulate"_string, + "decapsulate"_string }; for (auto& operation : supported_operations) { @@ -1584,6 +1586,7 @@ SupportedAlgorithmsMap const& supported_algorithms() // https://wicg.github.io/webcrypto-modern-algos/#ml-kem-registration for (auto const& name : { "ML-KEM-512"_string, "ML-KEM-768"_string, "ML-KEM-1024"_string }) { define_an_algorithm("generateKey"_string, name); + define_an_algorithm("encapsulate"_string, name); } return internal_object;