LibWeb: Implement the generateKey algorithm for X448

This commit is contained in:
Andreas Kling 2024-11-25 11:18:05 +01:00 committed by Andreas Kling
parent a7652d5073
commit 5a8b0a2610
Notes: github-actions[bot] 2024-11-25 16:18:05 +00:00
4 changed files with 122 additions and 35 deletions

View file

@ -2,6 +2,7 @@
* Copyright (c) 2024, Andrew Kaster <akaster@serenityos.org>
* Copyright (c) 2024, stelar7 <dudedbz@gmail.com>
* Copyright (c) 2024, Jelle Raaijmakers <jelle@ladybird.org>
* Copyright (c) 2024, Andreas Kling <andreas@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -17,6 +18,7 @@
#include <LibCrypto/Curves/Ed25519.h>
#include <LibCrypto/Curves/SECPxxxr1.h>
#include <LibCrypto/Curves/X25519.h>
#include <LibCrypto/Curves/X448.h>
#include <LibCrypto/Hash/HKDF.h>
#include <LibCrypto/Hash/HashManager.h>
#include <LibCrypto/Hash/MGF.h>
@ -3749,6 +3751,75 @@ WebIDL::ExceptionOr<GC::Ref<JS::Object>> X25519::export_key(Bindings::KeyFormat
return GC::Ref { *result };
}
// https://wicg.github.io/webcrypto-secure-curves/#x448-operations
WebIDL::ExceptionOr<Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>>> X448::generate_key(
AlgorithmParams const&,
bool extractable,
Vector<Bindings::KeyUsage> const& usages)
{
// 1. If usages contains an entry which is not "deriveKey" or "deriveBits" then throw a SyntaxError.
for (auto const& usage : usages) {
if (usage != Bindings::KeyUsage::Derivekey && usage != Bindings::KeyUsage::Derivebits) {
return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
}
}
// 2. Generate an X448 key pair, with the private key being 56 random bytes, and the public key being X448(a, 5), as defined in [RFC7748], section 6.2.
::Crypto::Curves::X448 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"_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"_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 "X448".
algorithm->set_name("X448"_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 empty list.
public_key->set_usages({});
// 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 [ "deriveKey", "deriveBits" ].
private_key->set_usages(usage_intersection(usages, { { Bindings::KeyUsage::Derivekey, Bindings::KeyUsage::Derivebits } }));
// 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.
auto result = CryptoKeyPair::create(m_realm, public_key, private_key);
// 18. Return the result of converting result to an ECMAScript Object, as defined by [WebIDL].
return Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>> { result };
}
static WebIDL::ExceptionOr<ByteBuffer> hmac_calculate_message_digest(JS::Realm& realm, GC::Ptr<KeyAlgorithm> hash, ReadonlyBytes key, ReadonlyBytes message)
{
auto calculate_digest = [&]<typename T>() -> ByteBuffer {

View file

@ -543,6 +543,22 @@ private:
}
};
class X448 : public AlgorithmMethods {
public:
// FIXME: virtual WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> derive_bits(AlgorithmParams const&, GC::Ref<CryptoKey>, Optional<u32>) override;
virtual WebIDL::ExceptionOr<Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>>> generate_key(AlgorithmParams const&, bool, Vector<Bindings::KeyUsage> const&) override;
// FIXME: virtual WebIDL::ExceptionOr<GC::Ref<CryptoKey>> import_key(AlgorithmParams const&, Bindings::KeyFormat, CryptoKey::InternalKeyData, bool, Vector<Bindings::KeyUsage> const&) override;
// FIXME: virtual WebIDL::ExceptionOr<GC::Ref<JS::Object>> export_key(Bindings::KeyFormat, GC::Ref<CryptoKey>) override;
static NonnullOwnPtr<AlgorithmMethods> create(JS::Realm& realm) { return adopt_own(*new X448(realm)); }
private:
explicit X448(JS::Realm& realm)
: AlgorithmMethods(realm)
{
}
};
class HMAC : public AlgorithmMethods {
public:
virtual WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> sign(AlgorithmParams const&, GC::Ref<CryptoKey>, ByteBuffer const&) override;

View file

@ -874,7 +874,7 @@ SupportedAlgorithmsMap const& supported_algorithms()
// https://wicg.github.io/webcrypto-secure-curves/#x448-registration
// FIXME: define_an_algorithm<X448, EcdhKeyDerivePrams>("deriveBits"_string, "X448"_string);
// FIXME: define_an_algorithm<X448>("generateKey"_string, "X448"_string);
define_an_algorithm<X448>("generateKey"_string, "X448"_string);
// FIXME: define_an_algorithm<X448>("importKey"_string, "X448"_string);
// FIXME: define_an_algorithm<X448>("exportKey"_string, "X448"_string);

View file

@ -6,8 +6,8 @@ Rerun
Found 392 tests
332 Pass
60 Fail
364 Pass
28 Fail
Details
Result Test Name MessagePass Bad algorithm: generateKey(AES, false, [decrypt])
Pass Bad algorithm: generateKey(AES, true, [decrypt])
@ -369,35 +369,35 @@ Pass Empty algorithm: generateKey({}, false, [decrypt, sign, deriveBits, decrypt
Pass Empty algorithm: generateKey({}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Empty algorithm: generateKey({}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Pass Empty algorithm: generateKey({}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])
Fail Bad usages: generateKey({name: X448}, true, [encrypt])
Fail Bad usages: generateKey({name: X448}, true, [deriveKey, encrypt])
Fail Bad usages: generateKey({name: X448}, true, [deriveBits, deriveKey, encrypt])
Fail Bad usages: generateKey({name: X448}, true, [deriveBits, encrypt])
Fail Bad usages: generateKey({name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, encrypt])
Fail Bad usages: generateKey({name: X448}, true, [decrypt])
Fail Bad usages: generateKey({name: X448}, true, [deriveKey, decrypt])
Fail Bad usages: generateKey({name: X448}, true, [deriveBits, deriveKey, decrypt])
Fail Bad usages: generateKey({name: X448}, true, [deriveBits, decrypt])
Fail Bad usages: generateKey({name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, decrypt])
Fail Bad usages: generateKey({name: X448}, true, [sign])
Fail Bad usages: generateKey({name: X448}, true, [deriveKey, sign])
Fail Bad usages: generateKey({name: X448}, true, [deriveBits, deriveKey, sign])
Fail Bad usages: generateKey({name: X448}, true, [deriveBits, sign])
Fail Bad usages: generateKey({name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, sign])
Fail Bad usages: generateKey({name: X448}, true, [verify])
Fail Bad usages: generateKey({name: X448}, true, [deriveKey, verify])
Fail Bad usages: generateKey({name: X448}, true, [deriveBits, deriveKey, verify])
Fail Bad usages: generateKey({name: X448}, true, [deriveBits, verify])
Fail Bad usages: generateKey({name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, verify])
Fail Bad usages: generateKey({name: X448}, true, [wrapKey])
Fail Bad usages: generateKey({name: X448}, true, [deriveKey, wrapKey])
Fail Bad usages: generateKey({name: X448}, true, [deriveBits, deriveKey, wrapKey])
Fail Bad usages: generateKey({name: X448}, true, [deriveBits, wrapKey])
Fail Bad usages: generateKey({name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, wrapKey])
Fail Bad usages: generateKey({name: X448}, true, [unwrapKey])
Fail Bad usages: generateKey({name: X448}, true, [deriveKey, unwrapKey])
Fail Bad usages: generateKey({name: X448}, true, [deriveBits, deriveKey, unwrapKey])
Fail Bad usages: generateKey({name: X448}, true, [deriveBits, unwrapKey])
Fail Bad usages: generateKey({name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, unwrapKey])
Fail Empty usages: generateKey({name: X448}, false, [])
Fail Empty usages: generateKey({name: X448}, true, [])
Pass Bad usages: generateKey({name: X448}, true, [encrypt])
Pass Bad usages: generateKey({name: X448}, true, [deriveKey, encrypt])
Pass Bad usages: generateKey({name: X448}, true, [deriveBits, deriveKey, encrypt])
Pass Bad usages: generateKey({name: X448}, true, [deriveBits, encrypt])
Pass Bad usages: generateKey({name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, encrypt])
Pass Bad usages: generateKey({name: X448}, true, [decrypt])
Pass Bad usages: generateKey({name: X448}, true, [deriveKey, decrypt])
Pass Bad usages: generateKey({name: X448}, true, [deriveBits, deriveKey, decrypt])
Pass Bad usages: generateKey({name: X448}, true, [deriveBits, decrypt])
Pass Bad usages: generateKey({name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, decrypt])
Pass Bad usages: generateKey({name: X448}, true, [sign])
Pass Bad usages: generateKey({name: X448}, true, [deriveKey, sign])
Pass Bad usages: generateKey({name: X448}, true, [deriveBits, deriveKey, sign])
Pass Bad usages: generateKey({name: X448}, true, [deriveBits, sign])
Pass Bad usages: generateKey({name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, sign])
Pass Bad usages: generateKey({name: X448}, true, [verify])
Pass Bad usages: generateKey({name: X448}, true, [deriveKey, verify])
Pass Bad usages: generateKey({name: X448}, true, [deriveBits, deriveKey, verify])
Pass Bad usages: generateKey({name: X448}, true, [deriveBits, verify])
Pass Bad usages: generateKey({name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, verify])
Pass Bad usages: generateKey({name: X448}, true, [wrapKey])
Pass Bad usages: generateKey({name: X448}, true, [deriveKey, wrapKey])
Pass Bad usages: generateKey({name: X448}, true, [deriveBits, deriveKey, wrapKey])
Pass Bad usages: generateKey({name: X448}, true, [deriveBits, wrapKey])
Pass Bad usages: generateKey({name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, wrapKey])
Pass Bad usages: generateKey({name: X448}, true, [unwrapKey])
Pass Bad usages: generateKey({name: X448}, true, [deriveKey, unwrapKey])
Pass Bad usages: generateKey({name: X448}, true, [deriveBits, deriveKey, unwrapKey])
Pass Bad usages: generateKey({name: X448}, true, [deriveBits, unwrapKey])
Pass Bad usages: generateKey({name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, unwrapKey])
Pass Empty usages: generateKey({name: X448}, false, [])
Pass Empty usages: generateKey({name: X448}, true, [])