Crypto.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. /*
  2. * Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
  3. * Copyright (c) 2022, stelar7 <dudedbz@gmail.com>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <AK/Random.h>
  8. #include <AK/StringBuilder.h>
  9. #include <LibJS/Runtime/TypedArray.h>
  10. #include <LibWeb/Crypto/Crypto.h>
  11. #include <LibWeb/Crypto/SubtleCrypto.h>
  12. #include <LibWeb/HTML/Window.h>
  13. namespace Web::Crypto {
  14. JS::NonnullGCPtr<Crypto> Crypto::create(HTML::Window& window)
  15. {
  16. return *window.heap().allocate<Crypto>(window.realm(), window);
  17. }
  18. Crypto::Crypto(HTML::Window& window)
  19. : PlatformObject(window.realm())
  20. {
  21. set_prototype(&window.cached_web_prototype("Crypto"));
  22. }
  23. Crypto::~Crypto() = default;
  24. void Crypto::initialize(JS::Realm& realm)
  25. {
  26. Base::initialize(realm);
  27. m_subtle = SubtleCrypto::create(global_object());
  28. }
  29. JS::NonnullGCPtr<SubtleCrypto> Crypto::subtle() const
  30. {
  31. return *m_subtle;
  32. }
  33. // https://w3c.github.io/webcrypto/#dfn-Crypto-method-getRandomValues
  34. WebIDL::ExceptionOr<JS::Value> Crypto::get_random_values(JS::Value array) const
  35. {
  36. // 1. If array is not an Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, BigInt64Array, or BigUint64Array, then throw a TypeMismatchError and terminate the algorithm.
  37. if (!array.is_object() || !(is<JS::Int8Array>(array.as_object()) || is<JS::Uint8Array>(array.as_object()) || is<JS::Uint8ClampedArray>(array.as_object()) || is<JS::Int16Array>(array.as_object()) || is<JS::Uint16Array>(array.as_object()) || is<JS::Int32Array>(array.as_object()) || is<JS::Uint32Array>(array.as_object()) || is<JS::BigInt64Array>(array.as_object()) || is<JS::BigUint64Array>(array.as_object())))
  38. return DOM::TypeMismatchError::create(global_object(), "array must be one of Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, BigInt64Array, or BigUint64Array");
  39. auto& typed_array = static_cast<JS::TypedArrayBase&>(array.as_object());
  40. // 2. If the byteLength of array is greater than 65536, throw a QuotaExceededError and terminate the algorithm.
  41. if (typed_array.byte_length() > 65536)
  42. return DOM::QuotaExceededError::create(global_object(), "array's byteLength may not be greater than 65536");
  43. // IMPLEMENTATION DEFINED: If the viewed array buffer is detached, throw a InvalidStateError and terminate the algorithm.
  44. if (typed_array.viewed_array_buffer()->is_detached())
  45. return DOM::InvalidStateError::create(global_object(), "array is detached");
  46. // FIXME: Handle SharedArrayBuffers
  47. // 3. Overwrite all elements of array with cryptographically strong random values of the appropriate type.
  48. fill_with_random(typed_array.viewed_array_buffer()->buffer().data(), typed_array.viewed_array_buffer()->buffer().size());
  49. // 4. Return array.
  50. return array;
  51. }
  52. // https://w3c.github.io/webcrypto/#dfn-Crypto-method-randomUUID
  53. String Crypto::random_uuid() const
  54. {
  55. // 1. Let bytes be a byte sequence of length 16.
  56. u8 bytes[16];
  57. // 2. Fill bytes with cryptographically secure random bytes.
  58. fill_with_random(bytes, 16);
  59. // 3. Set the 4 most significant bits of bytes[6], which represent the UUID version, to 0100.
  60. bytes[6] &= ~(1 << 7);
  61. bytes[6] |= 1 << 6;
  62. bytes[6] &= ~(1 << 5);
  63. bytes[6] &= ~(1 << 4);
  64. // 4. Set the 2 most significant bits of bytes[8], which represent the UUID variant, to 10.
  65. bytes[8] |= 1 << 7;
  66. bytes[8] &= ~(1 << 6);
  67. /* 5. Return the string concatenation of
  68. «
  69. hexadecimal representation of bytes[0],
  70. hexadecimal representation of bytes[1],
  71. hexadecimal representation of bytes[2],
  72. hexadecimal representation of bytes[3],
  73. "-",
  74. hexadecimal representation of bytes[4],
  75. hexadecimal representation of bytes[5],
  76. "-",
  77. hexadecimal representation of bytes[6],
  78. hexadecimal representation of bytes[7],
  79. "-",
  80. hexadecimal representation of bytes[8],
  81. hexadecimal representation of bytes[9],
  82. "-",
  83. hexadecimal representation of bytes[10],
  84. hexadecimal representation of bytes[11],
  85. hexadecimal representation of bytes[12],
  86. hexadecimal representation of bytes[13],
  87. hexadecimal representation of bytes[14],
  88. hexadecimal representation of bytes[15]
  89. ».
  90. */
  91. StringBuilder builder;
  92. builder.appendff("{:02x}{:02x}{:02x}{:02x}-", bytes[0], bytes[1], bytes[2], bytes[3]);
  93. builder.appendff("{:02x}{:02x}-", bytes[4], bytes[5]);
  94. builder.appendff("{:02x}{:02x}-", bytes[6], bytes[7]);
  95. builder.appendff("{:02x}{:02x}-", bytes[8], bytes[9]);
  96. builder.appendff("{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}", bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]);
  97. return builder.to_string();
  98. }
  99. void Crypto::visit_edges(Cell::Visitor& visitor)
  100. {
  101. Base::visit_edges(visitor);
  102. visitor.visit(m_subtle.ptr());
  103. }
  104. }