LibWeb: Implement the deriveBits algorithm for X448

This commit is contained in:
Andreas Kling 2024-11-25 15:56:40 +01:00 committed by Andreas Kling
commit d625e12082
Notes: github-actions[bot] 2024-11-25 16:17:43 +00:00
4 changed files with 81 additions and 18 deletions

View file

@ -3751,6 +3751,69 @@ WebIDL::ExceptionOr<GC::Ref<JS::Object>> X25519::export_key(Bindings::KeyFormat
return GC::Ref { *result }; return GC::Ref { *result };
} }
// https://wicg.github.io/webcrypto-secure-curves/#x448-operations
WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> X448::derive_bits(
AlgorithmParams const& params,
GC::Ref<CryptoKey> key,
Optional<u32> length_optional)
{
// 1. If the [[type]] internal slot of key is not "private", then throw an InvalidAccessError.
if (key->type() != Bindings::KeyType::Private)
return WebIDL::InvalidAccessError::create(m_realm, "Key is not a private key"_string);
// 2. Let publicKey be the public member of normalizedAlgorithm.
auto& public_key = static_cast<EcdhKeyDerivePrams const&>(params).public_key;
// 3. If the [[type]] internal slot of publicKey is not "public", then throw an InvalidAccessError.
if (public_key->type() != Bindings::KeyType::Public)
return WebIDL::InvalidAccessError::create(m_realm, "Public key is not a public key"_string);
// 4. If the name attribute of the [[algorithm]] internal slot of publicKey is not equal to
// the name property of the [[algorithm]] internal slot of key, then throw an InvalidAccessError.
auto& internal_algorithm = static_cast<KeyAlgorithm const&>(*key->algorithm());
auto& public_internal_algorithm = static_cast<KeyAlgorithm const&>(*public_key->algorithm());
if (internal_algorithm.name() != public_internal_algorithm.name())
return WebIDL::InvalidAccessError::create(m_realm, "Algorithm mismatch"_string);
// 5. Let secret be the result of performing the X448 function specified in [RFC7748] Section 5
// with key as the X448 private key k and the X448 public key represented by the [[handle]]
// internal slot of publicKey as the X448 public key u.
auto private_key = key->handle().get<ByteBuffer>();
auto public_key_data = public_key->handle().get<ByteBuffer>();
::Crypto::Curves::X448 curve;
auto maybe_secret = curve.compute_coordinate(private_key, public_key_data);
if (maybe_secret.is_error())
return WebIDL::OperationError::create(m_realm, "Failed to compute secret"_string);
auto secret = maybe_secret.release_value();
// 6. If secret is the all-zero value, then throw a OperationError. This check must be performed in constant-time, as per [RFC7748] Section 6.2.
// NOTE: The check may be performed by ORing all the bytes together and checking whether the result is zero,
// as this eliminates standard side-channels in software implementations.
auto or_bytes = 0;
for (auto byte : secret.bytes()) {
or_bytes |= byte;
}
if (or_bytes == 0)
return WebIDL::OperationError::create(m_realm, "Secret is the all-zero value"_string);
// 7. If length is null: Return secret
if (!length_optional.has_value()) {
auto result = TRY_OR_THROW_OOM(m_realm->vm(), ByteBuffer::copy(secret));
return JS::ArrayBuffer::create(m_realm, move(result));
}
// Otherwise: Return an octet string containing the first length bits of secret.
auto length = length_optional.value();
if (secret.size() * 8 < length)
return WebIDL::OperationError::create(m_realm, "Secret is too short"_string);
auto slice = TRY_OR_THROW_OOM(m_realm->vm(), secret.slice(0, length / 8));
return JS::ArrayBuffer::create(m_realm, move(slice));
}
// https://wicg.github.io/webcrypto-secure-curves/#x448-operations // https://wicg.github.io/webcrypto-secure-curves/#x448-operations
WebIDL::ExceptionOr<Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>>> X448::generate_key( WebIDL::ExceptionOr<Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>>> X448::generate_key(
AlgorithmParams const&, AlgorithmParams const&,

View file

@ -545,7 +545,7 @@ private:
class X448 : public AlgorithmMethods { class X448 : public AlgorithmMethods {
public: public:
// FIXME: virtual WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> derive_bits(AlgorithmParams const&, GC::Ref<CryptoKey>, Optional<u32>) override; 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; virtual WebIDL::ExceptionOr<Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>>> generate_key(AlgorithmParams const&, bool, Vector<Bindings::KeyUsage> const&) override;
virtual WebIDL::ExceptionOr<GC::Ref<CryptoKey>> import_key(AlgorithmParams const&, Bindings::KeyFormat, CryptoKey::InternalKeyData, bool, Vector<Bindings::KeyUsage> const&) override; virtual WebIDL::ExceptionOr<GC::Ref<CryptoKey>> import_key(AlgorithmParams const&, Bindings::KeyFormat, CryptoKey::InternalKeyData, bool, Vector<Bindings::KeyUsage> const&) override;
virtual WebIDL::ExceptionOr<GC::Ref<JS::Object>> export_key(Bindings::KeyFormat, GC::Ref<CryptoKey>) override; virtual WebIDL::ExceptionOr<GC::Ref<JS::Object>> export_key(Bindings::KeyFormat, GC::Ref<CryptoKey>) override;

View file

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

View file

@ -6,24 +6,24 @@ Rerun
Found 18 tests Found 18 tests
1 Pass 15 Pass
17 Fail 3 Fail
Details Details
Result Test Name MessagePass setup - define tests Result Test Name MessagePass setup - define tests
Fail X448 key derivation checks for all-zero value result with a key of order 0 Pass X448 key derivation checks for all-zero value result with a key of order 0
Fail X448 key derivation checks for all-zero value result with a key of order 1 Pass X448 key derivation checks for all-zero value result with a key of order 1
Fail X448 key derivation checks for all-zero value result with a key of order p-1 (order 2) Pass X448 key derivation checks for all-zero value result with a key of order p-1 (order 2)
Fail X448 key derivation checks for all-zero value result with a key of order p (=0, order 4) Pass X448 key derivation checks for all-zero value result with a key of order p (=0, order 4)
Fail X448 key derivation checks for all-zero value result with a key of order p+1 (=1, order 1) Pass X448 key derivation checks for all-zero value result with a key of order p+1 (=1, order 1)
Fail X448 good parameters Pass X448 good parameters
Fail X448 mixed case parameters Fail X448 mixed case parameters
Fail X448 short result Pass X448 short result
Fail X448 non-multiple of 8 bits Fail X448 non-multiple of 8 bits
Fail X448 missing public property Pass X448 missing public property
Fail X448 public property of algorithm is not a CryptoKey Pass X448 public property of algorithm is not a CryptoKey
Fail X448 mismatched algorithms Fail X448 mismatched algorithms
Fail X448 no deriveBits usage for base key Pass X448 no deriveBits usage for base key
Fail X448 base key is not a private key Pass X448 base key is not a private key
Fail X448 public property value is a private key Pass X448 public property value is a private key
Fail X448 public property value is a secret key Pass X448 public property value is a secret key
Fail X448 asking for too many bits Pass X448 asking for too many bits