tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Crypto.cpp (3341B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "Crypto.h"
      8 
      9 #include "js/ScalarType.h"
     10 #include "js/experimental/TypedData.h"  // JS_GetArrayBufferViewType
     11 #include "mozilla/dom/CryptoBinding.h"
     12 #include "mozilla/dom/SubtleCrypto.h"
     13 #include "nsCOMPtr.h"
     14 #include "nsIRandomGenerator.h"
     15 #include "nsReadableUtils.h"
     16 #include "nsServiceManagerUtils.h"
     17 
     18 namespace mozilla::dom {
     19 
     20 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Crypto)
     21  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     22  NS_INTERFACE_MAP_ENTRY(nsISupports)
     23 NS_INTERFACE_MAP_END
     24 
     25 NS_IMPL_CYCLE_COLLECTING_ADDREF(Crypto)
     26 NS_IMPL_CYCLE_COLLECTING_RELEASE(Crypto)
     27 
     28 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Crypto, mParent, mSubtle)
     29 
     30 Crypto::Crypto(nsIGlobalObject* aParent) : mParent(aParent) {}
     31 
     32 Crypto::~Crypto() = default;
     33 
     34 /* virtual */
     35 JSObject* Crypto::WrapObject(JSContext* aCx,
     36                             JS::Handle<JSObject*> aGivenProto) {
     37  return Crypto_Binding::Wrap(aCx, this, aGivenProto);
     38 }
     39 
     40 void Crypto::GetRandomValues(JSContext* aCx, const ArrayBufferView& aArray,
     41                             JS::MutableHandle<JSObject*> aRetval,
     42                             ErrorResult& aRv) {
     43  // Throw if the wrong type of ArrayBufferView is passed in
     44  // (Part of the Web Crypto API spec)
     45  switch (aArray.Type()) {
     46    case js::Scalar::Int8:
     47    case js::Scalar::Uint8:
     48    case js::Scalar::Uint8Clamped:
     49    case js::Scalar::Int16:
     50    case js::Scalar::Uint16:
     51    case js::Scalar::Int32:
     52    case js::Scalar::Uint32:
     53    case js::Scalar::BigInt64:
     54    case js::Scalar::BigUint64:
     55      break;
     56    default:
     57      aRv.Throw(NS_ERROR_DOM_TYPE_MISMATCH_ERR);
     58      return;
     59  }
     60 
     61  nsCOMPtr<nsIRandomGenerator> randomGenerator =
     62      do_GetService("@mozilla.org/security/random-generator;1");
     63  if (!randomGenerator) {
     64    aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
     65    return;
     66  }
     67 
     68  aArray.ProcessFixedData([&](const Span<uint8_t>& aData) {
     69    if (aData.Length() == 0) {
     70      NS_WARNING("ArrayBufferView length is 0, cannot continue");
     71      aRetval.set(aArray.Obj());
     72      return;
     73    }
     74 
     75    if (aData.Length() > 65536) {
     76      aRv.ThrowQuotaExceededError(
     77          "getRandomValues can only generate maximum 65536 bytes");
     78      return;
     79    }
     80 
     81    nsresult rv = randomGenerator->GenerateRandomBytesInto(aData.Elements(),
     82                                                           aData.Length());
     83    if (NS_FAILED(rv)) {
     84      aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
     85      return;
     86    }
     87 
     88    aRetval.set(aArray.Obj());
     89  });
     90 }
     91 
     92 void Crypto::RandomUUID(nsACString& aRetVal) {
     93  // NSID_LENGTH == 39 == 36 UUID chars + 2 curly braces + 1 NUL byte
     94  static_assert(NSID_LENGTH == 39);
     95 
     96  nsIDToCString uuidString(nsID::GenerateUUID());
     97  MOZ_ASSERT(strlen(uuidString.get()) == NSID_LENGTH - 1);
     98 
     99  // Omit the curly braces and NUL.
    100  aRetVal = Substring(uuidString.get() + 1, NSID_LENGTH - 3);
    101  MOZ_ASSERT(aRetVal.Length() == NSID_LENGTH - 3);
    102 }
    103 
    104 SubtleCrypto* Crypto::Subtle() {
    105  if (!mSubtle) {
    106    mSubtle = new SubtleCrypto(GetParentObject());
    107  }
    108  return mSubtle;
    109 }
    110 
    111 }  // namespace mozilla::dom