/* * Copyright (c) 2024, Andrew Kaster * Copyright (c) 2024, stelar7 * Copyright (c) 2024, Jelle Raaijmakers * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include #include #include #include #include namespace Web::Crypto { using AlgorithmIdentifier = Variant, String>; using NamedCurve = String; using KeyDataType = Variant, Bindings::JsonWebKey>; struct HashAlgorithmIdentifier : public AlgorithmIdentifier { using AlgorithmIdentifier::AlgorithmIdentifier; JS::ThrowCompletionOr name(JS::VM& vm) const { auto value = visit( [](String const& name) -> JS::ThrowCompletionOr { return name; }, [&](GC::Root const& obj) -> JS::ThrowCompletionOr { auto name_property = TRY(obj->get("name")); return name_property.to_string(vm); }); return value; } }; // https://w3c.github.io/webcrypto/#algorithm-overview struct AlgorithmParams { virtual ~AlgorithmParams(); explicit AlgorithmParams(String name) : name(move(name)) { } String name; static JS::ThrowCompletionOr> from_value(JS::VM&, JS::Value); }; // https://w3c.github.io/webcrypto/#aes-cbc struct AesCbcParams : public AlgorithmParams { virtual ~AesCbcParams() override; AesCbcParams(String name, ByteBuffer iv) : AlgorithmParams(move(name)) , iv(move(iv)) { } ByteBuffer iv; static JS::ThrowCompletionOr> from_value(JS::VM&, JS::Value); }; // https://w3c.github.io/webcrypto/#dfn-AesCtrParams struct AesCtrParams : public AlgorithmParams { virtual ~AesCtrParams() override; AesCtrParams(String name, ByteBuffer counter, u8 length) : AlgorithmParams(move(name)) , counter(move(counter)) , length(length) { } ByteBuffer counter; u8 length; static JS::ThrowCompletionOr> from_value(JS::VM&, JS::Value); }; // https://w3c.github.io/webcrypto/#dfn-AesGcmParams struct AesGcmParams : public AlgorithmParams { virtual ~AesGcmParams() override; AesGcmParams(String name, ByteBuffer iv, Optional additional_data, Optional tag_length) : AlgorithmParams(move(name)) , iv(move(iv)) , additional_data(move(additional_data)) , tag_length(tag_length) { } ByteBuffer iv; Optional additional_data; Optional tag_length; static JS::ThrowCompletionOr> from_value(JS::VM&, JS::Value); }; // https://w3c.github.io/webcrypto/#hkdf-params struct HKDFParams : public AlgorithmParams { virtual ~HKDFParams() override; HKDFParams(String name, HashAlgorithmIdentifier hash, ByteBuffer salt, ByteBuffer info) : AlgorithmParams(move(name)) , hash(move(hash)) , salt(move(salt)) , info(move(info)) { } HashAlgorithmIdentifier hash; ByteBuffer salt; ByteBuffer info; static JS::ThrowCompletionOr> from_value(JS::VM&, JS::Value); }; // https://w3c.github.io/webcrypto/#pbkdf2-params struct PBKDF2Params : public AlgorithmParams { virtual ~PBKDF2Params() override; PBKDF2Params(String name, ByteBuffer salt, u32 iterations, HashAlgorithmIdentifier hash) : AlgorithmParams(move(name)) , salt(move(salt)) , iterations(iterations) , hash(move(hash)) { } ByteBuffer salt; u32 iterations; HashAlgorithmIdentifier hash; static JS::ThrowCompletionOr> from_value(JS::VM&, JS::Value); }; // https://w3c.github.io/webcrypto/#dfn-RsaKeyGenParams struct RsaKeyGenParams : public AlgorithmParams { virtual ~RsaKeyGenParams() override; RsaKeyGenParams(String name, u32 modulus_length, ::Crypto::UnsignedBigInteger public_exponent) : AlgorithmParams(move(name)) , modulus_length(modulus_length) , public_exponent(move(public_exponent)) { } u32 modulus_length; // NOTE that the raw data is going to be in Big Endian u8[] format ::Crypto::UnsignedBigInteger public_exponent; static JS::ThrowCompletionOr> from_value(JS::VM&, JS::Value); }; // https://w3c.github.io/webcrypto/#dfn-RsaHashedKeyGenParams struct RsaHashedKeyGenParams : public RsaKeyGenParams { virtual ~RsaHashedKeyGenParams() override; RsaHashedKeyGenParams(String name, u32 modulus_length, ::Crypto::UnsignedBigInteger public_exponent, HashAlgorithmIdentifier hash) : RsaKeyGenParams(move(name), modulus_length, move(public_exponent)) , hash(move(hash)) { } HashAlgorithmIdentifier hash; static JS::ThrowCompletionOr> from_value(JS::VM&, JS::Value); }; // https://w3c.github.io/webcrypto/#dfn-RsaHashedImportParams struct RsaHashedImportParams : public AlgorithmParams { virtual ~RsaHashedImportParams() override; RsaHashedImportParams(String name, HashAlgorithmIdentifier hash) : AlgorithmParams(move(name)) , hash(move(hash)) { } HashAlgorithmIdentifier hash; static JS::ThrowCompletionOr> from_value(JS::VM&, JS::Value); }; // https://w3c.github.io/webcrypto/#dfn-RsaOaepParams struct RsaOaepParams : public AlgorithmParams { virtual ~RsaOaepParams() override; RsaOaepParams(String name, ByteBuffer label) : AlgorithmParams(move(name)) , label(move(label)) { } ByteBuffer label; static JS::ThrowCompletionOr> from_value(JS::VM&, JS::Value); }; // https://w3c.github.io/webcrypto/#dfn-EcdsaParams struct EcdsaParams : public AlgorithmParams { virtual ~EcdsaParams() override; EcdsaParams(String name, HashAlgorithmIdentifier hash) : AlgorithmParams(move(name)) , hash(move(hash)) { } HashAlgorithmIdentifier hash; static JS::ThrowCompletionOr> from_value(JS::VM&, JS::Value); }; // https://w3c.github.io/webcrypto/#dfn-EcKeyGenParams struct EcKeyGenParams : public AlgorithmParams { virtual ~EcKeyGenParams() override; EcKeyGenParams(String name, NamedCurve named_curve) : AlgorithmParams(move(name)) , named_curve(move(named_curve)) { } NamedCurve named_curve; static JS::ThrowCompletionOr> from_value(JS::VM&, JS::Value); }; // https://w3c.github.io/webcrypto/#dfn-AesKeyGenParams struct AesKeyGenParams : public AlgorithmParams { virtual ~AesKeyGenParams() override; AesKeyGenParams(String name, u16 length) : AlgorithmParams(move(name)) , length(length) { } u16 length; static JS::ThrowCompletionOr> from_value(JS::VM&, JS::Value); }; // https://w3c.github.io/webcrypto/#dfn-AesDerivedKeyParams struct AesDerivedKeyParams : public AlgorithmParams { virtual ~AesDerivedKeyParams() override; AesDerivedKeyParams(String name, u16 length) : AlgorithmParams(move(name)) , length(length) { } u16 length; static JS::ThrowCompletionOr> from_value(JS::VM&, JS::Value); }; // https://w3c.github.io/webcrypto/#hmac-importparams struct HmacImportParams : public AlgorithmParams { virtual ~HmacImportParams() override; HmacImportParams(String name, HashAlgorithmIdentifier hash, Optional length) : AlgorithmParams(move(name)) , hash(move(hash)) , length(length) { } HashAlgorithmIdentifier hash; Optional length; static JS::ThrowCompletionOr> from_value(JS::VM&, JS::Value); }; // https://w3c.github.io/webcrypto/#hmac-keygen-params struct HmacKeyGenParams : public AlgorithmParams { virtual ~HmacKeyGenParams() override; HmacKeyGenParams(String name, HashAlgorithmIdentifier hash, Optional length) : AlgorithmParams(move(name)) , hash(move(hash)) , length(length) { } HashAlgorithmIdentifier hash; Optional length; static JS::ThrowCompletionOr> from_value(JS::VM&, JS::Value); }; class AlgorithmMethods { public: virtual ~AlgorithmMethods(); virtual WebIDL::ExceptionOr> encrypt(AlgorithmParams const&, GC::Ref, ByteBuffer const&) { return WebIDL::NotSupportedError::create(m_realm, "encrypt is not supported"_string); } virtual WebIDL::ExceptionOr> decrypt(AlgorithmParams const&, GC::Ref, ByteBuffer const&) { return WebIDL::NotSupportedError::create(m_realm, "decrypt is not supported"_string); } virtual WebIDL::ExceptionOr> sign(AlgorithmParams const&, GC::Ref, ByteBuffer const&) { return WebIDL::NotSupportedError::create(m_realm, "sign is not supported"_string); } virtual WebIDL::ExceptionOr verify(AlgorithmParams const&, GC::Ref, ByteBuffer const&, ByteBuffer const&) { return WebIDL::NotSupportedError::create(m_realm, "verify is not supported"_string); } virtual WebIDL::ExceptionOr> digest(AlgorithmParams const&, ByteBuffer const&) { return WebIDL::NotSupportedError::create(m_realm, "digest is not supported"_string); } virtual WebIDL::ExceptionOr> derive_bits(AlgorithmParams const&, GC::Ref, Optional) { return WebIDL::NotSupportedError::create(m_realm, "deriveBits is not supported"_string); } virtual WebIDL::ExceptionOr> import_key(AlgorithmParams const&, Bindings::KeyFormat, CryptoKey::InternalKeyData, bool, Vector const&) { return WebIDL::NotSupportedError::create(m_realm, "importKey is not supported"_string); } virtual WebIDL::ExceptionOr, GC::Ref>> generate_key(AlgorithmParams const&, bool, Vector const&) { return WebIDL::NotSupportedError::create(m_realm, "generateKey is not supported"_string); } virtual WebIDL::ExceptionOr> export_key(Bindings::KeyFormat, GC::Ref) { return WebIDL::NotSupportedError::create(m_realm, "exportKey is not supported"_string); } virtual WebIDL::ExceptionOr get_key_length(AlgorithmParams const&) { return WebIDL::NotSupportedError::create(m_realm, "getKeyLength is not supported"_string); } static NonnullOwnPtr create(JS::Realm& realm) { return adopt_own(*new AlgorithmMethods(realm)); } protected: explicit AlgorithmMethods(JS::Realm& realm) : m_realm(realm) { } GC::Ref m_realm; }; class RSAOAEP : public AlgorithmMethods { public: virtual WebIDL::ExceptionOr> encrypt(AlgorithmParams const&, GC::Ref, ByteBuffer const&) override; virtual WebIDL::ExceptionOr> decrypt(AlgorithmParams const&, GC::Ref, ByteBuffer const&) override; virtual WebIDL::ExceptionOr, GC::Ref>> generate_key(AlgorithmParams const&, bool, Vector const&) override; virtual WebIDL::ExceptionOr> import_key(AlgorithmParams const&, Bindings::KeyFormat, CryptoKey::InternalKeyData, bool, Vector const&) override; virtual WebIDL::ExceptionOr> export_key(Bindings::KeyFormat, GC::Ref) override; static NonnullOwnPtr create(JS::Realm& realm) { return adopt_own(*new RSAOAEP(realm)); } private: explicit RSAOAEP(JS::Realm& realm) : AlgorithmMethods(realm) { } }; class AesCbc : public AlgorithmMethods { public: virtual WebIDL::ExceptionOr> encrypt(AlgorithmParams const&, GC::Ref, ByteBuffer const&) override; virtual WebIDL::ExceptionOr> decrypt(AlgorithmParams const&, GC::Ref, ByteBuffer const&) override; virtual WebIDL::ExceptionOr> import_key(AlgorithmParams const&, Bindings::KeyFormat, CryptoKey::InternalKeyData, bool, Vector const&) override; virtual WebIDL::ExceptionOr, GC::Ref>> generate_key(AlgorithmParams const&, bool, Vector const&) override; virtual WebIDL::ExceptionOr> export_key(Bindings::KeyFormat, GC::Ref) override; virtual WebIDL::ExceptionOr get_key_length(AlgorithmParams const&) override; static NonnullOwnPtr create(JS::Realm& realm) { return adopt_own(*new AesCbc(realm)); } private: explicit AesCbc(JS::Realm& realm) : AlgorithmMethods(realm) { } }; class AesCtr : public AlgorithmMethods { public: virtual WebIDL::ExceptionOr> import_key(AlgorithmParams const&, Bindings::KeyFormat, CryptoKey::InternalKeyData, bool, Vector const&) override; virtual WebIDL::ExceptionOr> export_key(Bindings::KeyFormat, GC::Ref) override; virtual WebIDL::ExceptionOr get_key_length(AlgorithmParams const&) override; virtual WebIDL::ExceptionOr, GC::Ref>> generate_key(AlgorithmParams const&, bool, Vector const&) override; virtual WebIDL::ExceptionOr> encrypt(AlgorithmParams const&, GC::Ref, ByteBuffer const&) override; virtual WebIDL::ExceptionOr> decrypt(AlgorithmParams const&, GC::Ref, ByteBuffer const&) override; static NonnullOwnPtr create(JS::Realm& realm) { return adopt_own(*new AesCtr(realm)); } private: explicit AesCtr(JS::Realm& realm) : AlgorithmMethods(realm) { } }; class AesGcm : public AlgorithmMethods { public: virtual WebIDL::ExceptionOr get_key_length(AlgorithmParams const&) override; virtual WebIDL::ExceptionOr> import_key(AlgorithmParams const&, Bindings::KeyFormat, CryptoKey::InternalKeyData, bool, Vector const&) override; virtual WebIDL::ExceptionOr> export_key(Bindings::KeyFormat, GC::Ref) override; virtual WebIDL::ExceptionOr> encrypt(AlgorithmParams const&, GC::Ref, ByteBuffer const&) override; virtual WebIDL::ExceptionOr> decrypt(AlgorithmParams const&, GC::Ref, ByteBuffer const&) override; virtual WebIDL::ExceptionOr, GC::Ref>> generate_key(AlgorithmParams const&, bool, Vector const&) override; static NonnullOwnPtr create(JS::Realm& realm) { return adopt_own(*new AesGcm(realm)); } private: explicit AesGcm(JS::Realm& realm) : AlgorithmMethods(realm) { } }; class HKDF : public AlgorithmMethods { public: virtual WebIDL::ExceptionOr> import_key(AlgorithmParams const&, Bindings::KeyFormat, CryptoKey::InternalKeyData, bool, Vector const&) override; virtual WebIDL::ExceptionOr> derive_bits(AlgorithmParams const&, GC::Ref, Optional) override; virtual WebIDL::ExceptionOr get_key_length(AlgorithmParams const&) override; static NonnullOwnPtr create(JS::Realm& realm) { return adopt_own(*new HKDF(realm)); } private: explicit HKDF(JS::Realm& realm) : AlgorithmMethods(realm) { } }; class PBKDF2 : public AlgorithmMethods { public: virtual WebIDL::ExceptionOr> import_key(AlgorithmParams const&, Bindings::KeyFormat, CryptoKey::InternalKeyData, bool, Vector const&) override; virtual WebIDL::ExceptionOr> derive_bits(AlgorithmParams const&, GC::Ref, Optional) override; virtual WebIDL::ExceptionOr get_key_length(AlgorithmParams const&) override; static NonnullOwnPtr create(JS::Realm& realm) { return adopt_own(*new PBKDF2(realm)); } private: explicit PBKDF2(JS::Realm& realm) : AlgorithmMethods(realm) { } }; class SHA : public AlgorithmMethods { public: virtual WebIDL::ExceptionOr> digest(AlgorithmParams const&, ByteBuffer const&) override; static NonnullOwnPtr create(JS::Realm& realm) { return adopt_own(*new SHA(realm)); } private: explicit SHA(JS::Realm& realm) : AlgorithmMethods(realm) { } }; class ECDSA : public AlgorithmMethods { public: virtual WebIDL::ExceptionOr> sign(AlgorithmParams const&, GC::Ref, ByteBuffer const&) override; virtual WebIDL::ExceptionOr verify(AlgorithmParams const&, GC::Ref, ByteBuffer const&, ByteBuffer const&) override; virtual WebIDL::ExceptionOr, GC::Ref>> generate_key(AlgorithmParams const&, bool, Vector const&) override; static NonnullOwnPtr create(JS::Realm& realm) { return adopt_own(*new ECDSA(realm)); } private: explicit ECDSA(JS::Realm& realm) : AlgorithmMethods(realm) { } }; class ECDH : public AlgorithmMethods { public: virtual WebIDL::ExceptionOr, GC::Ref>> generate_key(AlgorithmParams const&, bool, Vector const&) override; // TODO: virtual WebIDL::ExceptionOr> export_key(Bindings::KeyFormat, GC::Ref) override; virtual WebIDL::ExceptionOr> import_key(AlgorithmParams const&, Bindings::KeyFormat, CryptoKey::InternalKeyData, bool, Vector const&) override; virtual WebIDL::ExceptionOr> derive_bits(AlgorithmParams const&, GC::Ref, Optional) override; static NonnullOwnPtr create(JS::Realm& realm) { return adopt_own(*new ECDH(realm)); } private: explicit ECDH(JS::Realm& realm) : AlgorithmMethods(realm) { } }; class ED25519 : public AlgorithmMethods { public: virtual WebIDL::ExceptionOr> sign(AlgorithmParams const&, GC::Ref, ByteBuffer const&) override; virtual WebIDL::ExceptionOr verify(AlgorithmParams const&, GC::Ref, ByteBuffer const&, ByteBuffer const&) override; virtual WebIDL::ExceptionOr, GC::Ref>> generate_key(AlgorithmParams const&, bool, Vector const&) override; virtual WebIDL::ExceptionOr> import_key(AlgorithmParams const&, Bindings::KeyFormat, CryptoKey::InternalKeyData, bool, Vector const&) override; virtual WebIDL::ExceptionOr> export_key(Bindings::KeyFormat, GC::Ref) override; static NonnullOwnPtr create(JS::Realm& realm) { return adopt_own(*new ED25519(realm)); } private: explicit ED25519(JS::Realm& realm) : AlgorithmMethods(realm) { } }; class X25519 : public AlgorithmMethods { public: virtual WebIDL::ExceptionOr> derive_bits(AlgorithmParams const&, GC::Ref, Optional) override; virtual WebIDL::ExceptionOr, GC::Ref>> generate_key(AlgorithmParams const&, bool, Vector const&) override; virtual WebIDL::ExceptionOr> import_key(AlgorithmParams const&, Bindings::KeyFormat, CryptoKey::InternalKeyData, bool, Vector const&) override; virtual WebIDL::ExceptionOr> export_key(Bindings::KeyFormat, GC::Ref) override; static NonnullOwnPtr create(JS::Realm& realm) { return adopt_own(*new X25519(realm)); } private: explicit X25519(JS::Realm& realm) : AlgorithmMethods(realm) { } }; class X448 : public AlgorithmMethods { public: virtual WebIDL::ExceptionOr> derive_bits(AlgorithmParams const&, GC::Ref, Optional) override; virtual WebIDL::ExceptionOr, GC::Ref>> generate_key(AlgorithmParams const&, bool, Vector const&) override; virtual WebIDL::ExceptionOr> import_key(AlgorithmParams const&, Bindings::KeyFormat, CryptoKey::InternalKeyData, bool, Vector const&) override; virtual WebIDL::ExceptionOr> export_key(Bindings::KeyFormat, GC::Ref) override; static NonnullOwnPtr 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> sign(AlgorithmParams const&, GC::Ref, ByteBuffer const&) override; virtual WebIDL::ExceptionOr verify(AlgorithmParams const&, GC::Ref, ByteBuffer const&, ByteBuffer const&) override; virtual WebIDL::ExceptionOr, GC::Ref>> generate_key(AlgorithmParams const&, bool, Vector const&) override; virtual WebIDL::ExceptionOr> import_key(AlgorithmParams const&, Bindings::KeyFormat, CryptoKey::InternalKeyData, bool, Vector const&) override; virtual WebIDL::ExceptionOr> export_key(Bindings::KeyFormat, GC::Ref) override; virtual WebIDL::ExceptionOr get_key_length(AlgorithmParams const&) override; static NonnullOwnPtr create(JS::Realm& realm) { return adopt_own(*new HMAC(realm)); } private: explicit HMAC(JS::Realm& realm) : AlgorithmMethods(realm) { } }; struct EcdhKeyDerivePrams : public AlgorithmParams { virtual ~EcdhKeyDerivePrams() override; EcdhKeyDerivePrams(String name, CryptoKey& public_key) : AlgorithmParams(move(name)) , public_key(public_key) { } GC::Ref public_key; static JS::ThrowCompletionOr> from_value(JS::VM&, JS::Value); }; struct EcKeyImportParams : public AlgorithmParams { virtual ~EcKeyImportParams() override; EcKeyImportParams(String name, String named_curve) : AlgorithmParams(move(name)) , named_curve(move(named_curve)) { } String named_curve; static JS::ThrowCompletionOr> from_value(JS::VM&, JS::Value); }; ErrorOr base64_url_uint_encode(::Crypto::UnsignedBigInteger); WebIDL::ExceptionOr base64_url_bytes_decode(JS::Realm&, String const& base64_url_string); WebIDL::ExceptionOr<::Crypto::UnsignedBigInteger> base64_url_uint_decode(JS::Realm&, String const& base64_url_string); }