123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- /*
- * Copyright (c) 2024, Andrew Kaster <akaster@serenityos.org>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #include <LibCrypto/Hash/HashManager.h>
- #include <LibJS/Runtime/ArrayBuffer.h>
- #include <LibJS/Runtime/DataView.h>
- #include <LibJS/Runtime/TypedArray.h>
- #include <LibWeb/Crypto/CryptoAlgorithms.h>
- namespace Web::Crypto {
- // Out of line to ensure this class has a key function
- AlgorithmMethods::~AlgorithmMethods() = default;
- JS::ThrowCompletionOr<NonnullOwnPtr<AlgorithmParams>> AlgorithmParams::from_value(JS::VM& vm, JS::Value value)
- {
- auto& object = value.as_object();
- auto name = TRY(object.get("name"));
- auto name_string = TRY(name.to_string(vm));
- return adopt_own(*new AlgorithmParams { .name = name_string });
- }
- JS::ThrowCompletionOr<NonnullOwnPtr<AlgorithmParams>> PBKDF2Params::from_value(JS::VM& vm, JS::Value value)
- {
- auto& realm = *vm.current_realm();
- auto& object = value.as_object();
- auto name_value = TRY(object.get("name"));
- auto name = TRY(name_value.to_string(vm));
- auto salt_value = TRY(object.get("salt"));
- JS::Handle<WebIDL::BufferSource> salt;
- if (!salt_value.is_object() || !(is<JS::TypedArrayBase>(salt_value.as_object()) || is<JS::ArrayBuffer>(salt_value.as_object()) || is<JS::DataView>(salt_value.as_object())))
- return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "BufferSource");
- salt = JS::make_handle(vm.heap().allocate<WebIDL::BufferSource>(realm, salt_value.as_object()));
- auto iterations_value = TRY(object.get("iterations"));
- auto iterations = TRY(iterations_value.to_u32(vm));
- auto hash_value = TRY(object.get("hash"));
- auto hash = Variant<Empty, HashAlgorithmIdentifier> { Empty {} };
- if (hash_value.is_string()) {
- auto hash_string = TRY(hash_value.to_string(vm));
- hash = HashAlgorithmIdentifier { hash_string };
- } else {
- auto hash_object = TRY(hash_value.to_object(vm));
- hash = HashAlgorithmIdentifier { hash_object };
- }
- return adopt_own<AlgorithmParams>(*new PBKDF2Params { { name }, salt, iterations, hash.downcast<HashAlgorithmIdentifier>() });
- }
- WebIDL::ExceptionOr<JS::NonnullGCPtr<CryptoKey>> PBKDF2::import_key(AlgorithmParams const&, Bindings::KeyFormat format, CryptoKey::InternalKeyData key_data, bool extractable, Vector<Bindings::KeyUsage> const& key_usages)
- {
- // 1. If format is not "raw", throw a NotSupportedError
- if (format != Bindings::KeyFormat::Raw) {
- return WebIDL::NotSupportedError::create(m_realm, "Only raw format is supported"_fly_string);
- }
- // 2. If usages contains a value that is not "deriveKey" or "deriveBits", then throw a SyntaxError.
- for (auto& usage : key_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))));
- }
- }
- // 3. If extractable is not false, then throw a SyntaxError.
- if (extractable)
- return WebIDL::SyntaxError::create(m_realm, "extractable must be false"_fly_string);
- // 4. Let key be a new CryptoKey representing keyData.
- auto key = CryptoKey::create(m_realm, move(key_data));
- // 5. Set the [[type]] internal slot of key to "secret".
- key->set_type(Bindings::KeyType::Secret);
- // 6. Set the [[extractable]] internal slot of key to false.
- key->set_extractable(false);
- // 7. Let algorithm be a new KeyAlgorithm object.
- auto algorithm = Bindings::KeyAlgorithm::create(m_realm);
- // 8. Set the name attribute of algorithm to "PBKDF2".
- algorithm->set_name("PBKDF2"_string);
- // 9. Set the [[algorithm]] internal slot of key to algorithm.
- key->set_algorithm(algorithm);
- // 10. Return key.
- return key;
- }
- WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::ArrayBuffer>> SHA::digest(AlgorithmParams const& algorithm, ByteBuffer const& data)
- {
- auto& algorithm_name = algorithm.name;
- ::Crypto::Hash::HashKind hash_kind;
- if (algorithm_name.equals_ignoring_ascii_case("SHA-1"sv)) {
- hash_kind = ::Crypto::Hash::HashKind::SHA1;
- } else if (algorithm_name.equals_ignoring_ascii_case("SHA-256"sv)) {
- hash_kind = ::Crypto::Hash::HashKind::SHA256;
- } else if (algorithm_name.equals_ignoring_ascii_case("SHA-384"sv)) {
- hash_kind = ::Crypto::Hash::HashKind::SHA384;
- } else if (algorithm_name.equals_ignoring_ascii_case("SHA-512"sv)) {
- hash_kind = ::Crypto::Hash::HashKind::SHA512;
- } else {
- return WebIDL::NotSupportedError::create(m_realm, MUST(String::formatted("Invalid hash function '{}'", algorithm_name)));
- }
- ::Crypto::Hash::Manager hash { hash_kind };
- hash.update(data);
- auto digest = hash.digest();
- auto result_buffer = ByteBuffer::copy(digest.immutable_data(), hash.digest_size());
- if (result_buffer.is_error())
- return WebIDL::OperationError::create(m_realm, "Failed to create result buffer"_fly_string);
- return JS::ArrayBuffer::create(m_realm, result_buffer.release_value());
- }
- }
|