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
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef mozilla_dom_GeneratePlaceholderCanvasData_h
8 #define mozilla_dom_GeneratePlaceholderCanvasData_h
9 
10 #include "mozilla/StaticPrefs_privacy.h"
11 #include "nsCOMPtr.h"
12 #include "nsIRandomGenerator.h"
13 #include "nsServiceManagerUtils.h"
14 
15 #define RANDOM_BYTES_TO_SAMPLE 32
16 
17 namespace mozilla {
18 namespace dom {
19 
20 /**
21  * When privacy.resistFingerprinting.randomDataOnCanvasExtract is true, tries
22  * to generate random data for placeholder canvas by sampling
23  * RANDOM_BYTES_TO_SAMPLE bytes and then returning it. If this fails or if
24  * privacy.resistFingerprinting.randomDataOnCanvasExtract is false, returns
25  * nullptr.
26  *
27  * @return uint8_t*  output buffer
28  */
TryToGenerateRandomDataForPlaceholderCanvasData()29 inline uint8_t* TryToGenerateRandomDataForPlaceholderCanvasData() {
30   if (!StaticPrefs::privacy_resistFingerprinting_randomDataOnCanvasExtract()) {
31     return nullptr;
32   }
33   nsresult rv;
34   nsCOMPtr<nsIRandomGenerator> rg =
35       do_GetService("@mozilla.org/security/random-generator;1", &rv);
36   if (NS_FAILED(rv)) {
37     return nullptr;
38   }
39   uint8_t* randomData;
40   rv = rg->GenerateRandomBytes(RANDOM_BYTES_TO_SAMPLE, &randomData);
41   if (NS_FAILED(rv)) {
42     return nullptr;
43   }
44   return randomData;
45 }
46 
47 /**
48  * If randomData not nullptr, repeats those bytes many times to fill buffer. If
49  * randomData is nullptr, returns all-white pixel data.
50  *
51  * @param[in]   randomData  Buffer of RANDOM_BYTES_TO_SAMPLE bytes of random
52  *                          data, or nullptr
53  * @param[in]   size        Size of output buffer
54  * @param[out]  buffer      Output buffer
55  */
FillPlaceholderCanvas(uint8_t * randomData,uint32_t size,uint8_t * buffer)56 inline void FillPlaceholderCanvas(uint8_t* randomData, uint32_t size,
57                                   uint8_t* buffer) {
58   if (!randomData) {
59     memset(buffer, 0xFF, size);
60     return;
61   }
62   auto remaining_to_fill = size;
63   auto index = 0;
64   while (remaining_to_fill > 0) {
65     auto bytes_to_write = (remaining_to_fill > RANDOM_BYTES_TO_SAMPLE)
66                               ? RANDOM_BYTES_TO_SAMPLE
67                               : remaining_to_fill;
68     memcpy(buffer + (index * RANDOM_BYTES_TO_SAMPLE), randomData,
69            bytes_to_write);
70     remaining_to_fill -= bytes_to_write;
71     index++;
72   }
73   free(randomData);
74 }
75 
76 /**
77  * When privacy.resistFingerprinting.randomDataOnCanvasExtract is true, tries
78  * to generate random canvas data by sampling RANDOM_BYTES_TO_SAMPLE bytes and
79  * then repeating those bytes many times to fill the buffer. If this fails or
80  * if privacy.resistFingerprinting.randomDataOnCanvasExtract is false, returns
81  * all-white, opaque pixel data.
82  *
83  * It is recommended that callers call this function instead of individually
84  * calling TryToGenerateRandomDataForPlaceholderCanvasData and
85  * FillPlaceholderCanvas unless there are requirements, like NoGC, that prevent
86  * them from calling the RNG service inside this function.
87  *
88  * @param[in]   size    Size of output buffer
89  * @param[out]  buffer  Output buffer
90  */
GeneratePlaceholderCanvasData(uint32_t size,uint8_t * buffer)91 inline void GeneratePlaceholderCanvasData(uint32_t size, uint8_t* buffer) {
92   uint8_t* randomData = TryToGenerateRandomDataForPlaceholderCanvasData();
93   FillPlaceholderCanvas(randomData, size, buffer);
94 }
95 
96 }  // namespace dom
97 }  // namespace mozilla
98 
99 #endif  // mozilla_dom_GeneratePlaceholderCanvasData_h
100