CryptoAlgorithms.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /*
  2. * Copyright (c) 2024, Andrew Kaster <akaster@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibCrypto/Hash/HashManager.h>
  7. #include <LibJS/Runtime/ArrayBuffer.h>
  8. #include <LibJS/Runtime/DataView.h>
  9. #include <LibJS/Runtime/TypedArray.h>
  10. #include <LibWeb/Crypto/CryptoAlgorithms.h>
  11. namespace Web::Crypto {
  12. // Out of line to ensure this class has a key function
  13. AlgorithmMethods::~AlgorithmMethods() = default;
  14. JS::ThrowCompletionOr<NonnullOwnPtr<AlgorithmParams>> AlgorithmParams::from_value(JS::VM& vm, JS::Value value)
  15. {
  16. auto& object = value.as_object();
  17. auto name = TRY(object.get("name"));
  18. auto name_string = TRY(name.to_string(vm));
  19. return adopt_own(*new AlgorithmParams { .name = name_string });
  20. }
  21. JS::ThrowCompletionOr<NonnullOwnPtr<AlgorithmParams>> PBKDF2Params::from_value(JS::VM& vm, JS::Value value)
  22. {
  23. auto& realm = *vm.current_realm();
  24. auto& object = value.as_object();
  25. auto name_value = TRY(object.get("name"));
  26. auto name = TRY(name_value.to_string(vm));
  27. auto salt_value = TRY(object.get("salt"));
  28. JS::Handle<WebIDL::BufferSource> salt;
  29. 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())))
  30. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "BufferSource");
  31. salt = JS::make_handle(vm.heap().allocate<WebIDL::BufferSource>(realm, salt_value.as_object()));
  32. auto iterations_value = TRY(object.get("iterations"));
  33. auto iterations = TRY(iterations_value.to_u32(vm));
  34. auto hash_value = TRY(object.get("hash"));
  35. auto hash = Variant<Empty, HashAlgorithmIdentifier> { Empty {} };
  36. if (hash_value.is_string()) {
  37. auto hash_string = TRY(hash_value.to_string(vm));
  38. hash = HashAlgorithmIdentifier { hash_string };
  39. } else {
  40. auto hash_object = TRY(hash_value.to_object(vm));
  41. hash = HashAlgorithmIdentifier { hash_object };
  42. }
  43. return adopt_own<AlgorithmParams>(*new PBKDF2Params { { name }, salt, iterations, hash.downcast<HashAlgorithmIdentifier>() });
  44. }
  45. 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)
  46. {
  47. // 1. If format is not "raw", throw a NotSupportedError
  48. if (format != Bindings::KeyFormat::Raw) {
  49. return WebIDL::NotSupportedError::create(m_realm, "Only raw format is supported"_fly_string);
  50. }
  51. // 2. If usages contains a value that is not "deriveKey" or "deriveBits", then throw a SyntaxError.
  52. for (auto& usage : key_usages) {
  53. if (usage != Bindings::KeyUsage::Derivekey && usage != Bindings::KeyUsage::Derivebits) {
  54. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
  55. }
  56. }
  57. // 3. If extractable is not false, then throw a SyntaxError.
  58. if (extractable)
  59. return WebIDL::SyntaxError::create(m_realm, "extractable must be false"_fly_string);
  60. // 4. Let key be a new CryptoKey representing keyData.
  61. auto key = CryptoKey::create(m_realm, move(key_data));
  62. // 5. Set the [[type]] internal slot of key to "secret".
  63. key->set_type(Bindings::KeyType::Secret);
  64. // 6. Set the [[extractable]] internal slot of key to false.
  65. key->set_extractable(false);
  66. // 7. Let algorithm be a new KeyAlgorithm object.
  67. auto algorithm = Bindings::KeyAlgorithm::create(m_realm);
  68. // 8. Set the name attribute of algorithm to "PBKDF2".
  69. algorithm->set_name("PBKDF2"_string);
  70. // 9. Set the [[algorithm]] internal slot of key to algorithm.
  71. key->set_algorithm(algorithm);
  72. // 10. Return key.
  73. return key;
  74. }
  75. WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::ArrayBuffer>> SHA::digest(AlgorithmParams const& algorithm, ByteBuffer const& data)
  76. {
  77. auto& algorithm_name = algorithm.name;
  78. ::Crypto::Hash::HashKind hash_kind;
  79. if (algorithm_name.equals_ignoring_ascii_case("SHA-1"sv)) {
  80. hash_kind = ::Crypto::Hash::HashKind::SHA1;
  81. } else if (algorithm_name.equals_ignoring_ascii_case("SHA-256"sv)) {
  82. hash_kind = ::Crypto::Hash::HashKind::SHA256;
  83. } else if (algorithm_name.equals_ignoring_ascii_case("SHA-384"sv)) {
  84. hash_kind = ::Crypto::Hash::HashKind::SHA384;
  85. } else if (algorithm_name.equals_ignoring_ascii_case("SHA-512"sv)) {
  86. hash_kind = ::Crypto::Hash::HashKind::SHA512;
  87. } else {
  88. return WebIDL::NotSupportedError::create(m_realm, MUST(String::formatted("Invalid hash function '{}'", algorithm_name)));
  89. }
  90. ::Crypto::Hash::Manager hash { hash_kind };
  91. hash.update(data);
  92. auto digest = hash.digest();
  93. auto result_buffer = ByteBuffer::copy(digest.immutable_data(), hash.digest_size());
  94. if (result_buffer.is_error())
  95. return WebIDL::OperationError::create(m_realm, "Failed to create result buffer"_fly_string);
  96. return JS::ArrayBuffer::create(m_realm, result_buffer.release_value());
  97. }
  98. }