1*e7b1675dSTing-Kang Chang // Copyright 2017 Google Inc.
2*e7b1675dSTing-Kang Chang //
3*e7b1675dSTing-Kang Chang // Licensed under the Apache License, Version 2.0 (the "License");
4*e7b1675dSTing-Kang Chang // you may not use this file except in compliance with the License.
5*e7b1675dSTing-Kang Chang // You may obtain a copy of the License at
6*e7b1675dSTing-Kang Chang //
7*e7b1675dSTing-Kang Chang // http://www.apache.org/licenses/LICENSE-2.0
8*e7b1675dSTing-Kang Chang //
9*e7b1675dSTing-Kang Chang // Unless required by applicable law or agreed to in writing, software
10*e7b1675dSTing-Kang Chang // distributed under the License is distributed on an "AS IS" BASIS,
11*e7b1675dSTing-Kang Chang // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*e7b1675dSTing-Kang Chang // See the License for the specific language governing permissions and
13*e7b1675dSTing-Kang Chang // limitations under the License.
14*e7b1675dSTing-Kang Chang //
15*e7b1675dSTing-Kang Chang ///////////////////////////////////////////////////////////////////////////////
16*e7b1675dSTing-Kang Chang
17*e7b1675dSTing-Kang Chang #include "tink/subtle/random.h"
18*e7b1675dSTing-Kang Chang
19*e7b1675dSTing-Kang Chang #include <cstdint>
20*e7b1675dSTing-Kang Chang #include <string>
21*e7b1675dSTing-Kang Chang
22*e7b1675dSTing-Kang Chang #include "absl/status/status.h"
23*e7b1675dSTing-Kang Chang #include "absl/strings/str_cat.h"
24*e7b1675dSTing-Kang Chang #include "absl/types/span.h"
25*e7b1675dSTing-Kang Chang #include "openssl/rand.h"
26*e7b1675dSTing-Kang Chang #include "tink/subtle/subtle_util.h"
27*e7b1675dSTing-Kang Chang #include "tink/util/status.h"
28*e7b1675dSTing-Kang Chang
29*e7b1675dSTing-Kang Chang namespace crypto {
30*e7b1675dSTing-Kang Chang namespace tink {
31*e7b1675dSTing-Kang Chang namespace subtle {
32*e7b1675dSTing-Kang Chang
33*e7b1675dSTing-Kang Chang namespace {
34*e7b1675dSTing-Kang Chang
35*e7b1675dSTing-Kang Chang template <typename UintType>
GetRandomUint()36*e7b1675dSTing-Kang Chang UintType GetRandomUint() {
37*e7b1675dSTing-Kang Chang UintType result;
38*e7b1675dSTing-Kang Chang Random::GetRandomBytes(
39*e7b1675dSTing-Kang Chang absl::MakeSpan(reinterpret_cast<char *>(&result), sizeof(result)))
40*e7b1675dSTing-Kang Chang .IgnoreError();
41*e7b1675dSTing-Kang Chang return result;
42*e7b1675dSTing-Kang Chang }
43*e7b1675dSTing-Kang Chang
44*e7b1675dSTing-Kang Chang } // namespace
45*e7b1675dSTing-Kang Chang
46*e7b1675dSTing-Kang Chang // BoringSSL documentation says that it always returns 1; while
47*e7b1675dSTing-Kang Chang // OpenSSL documentation says that it returns "1 on success, -1 if not supported
48*e7b1675dSTing-Kang Chang // by the current RAND method, or 0 on other failure"
49*e7b1675dSTing-Kang Chang // (https://www.openssl.org/docs/man1.1.1/man3/RAND_bytes.html).
50*e7b1675dSTing-Kang Chang //
51*e7b1675dSTing-Kang Chang // In case of insufficient entropy at the time of the call, BoringSSL's
52*e7b1675dSTing-Kang Chang // RAND_bytes will behave in different ways depending on the operating system,
53*e7b1675dSTing-Kang Chang // version, and FIPS mode. For Linux with a semi-recent kernel, it will block
54*e7b1675dSTing-Kang Chang // until the system has collected at least 128 bits since boot. For old
55*e7b1675dSTing-Kang Chang // kernels without getrandom support (and not in FIPS mode), it will resort to
56*e7b1675dSTing-Kang Chang // /dev/urandom.
GetRandomBytes(absl::Span<char> buffer)57*e7b1675dSTing-Kang Chang util::Status Random::GetRandomBytes(absl::Span<char> buffer) {
58*e7b1675dSTing-Kang Chang auto buffer_ptr = reinterpret_cast<uint8_t *>(buffer.data());
59*e7b1675dSTing-Kang Chang if (RAND_bytes(buffer_ptr, buffer.size()) <= 0) {
60*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInternal,
61*e7b1675dSTing-Kang Chang absl::StrCat("RAND_bytes failed to generate ",
62*e7b1675dSTing-Kang Chang buffer.size(), " bytes"));
63*e7b1675dSTing-Kang Chang }
64*e7b1675dSTing-Kang Chang return util::OkStatus();
65*e7b1675dSTing-Kang Chang }
66*e7b1675dSTing-Kang Chang
GetRandomBytes(size_t length)67*e7b1675dSTing-Kang Chang std::string Random::GetRandomBytes(size_t length) {
68*e7b1675dSTing-Kang Chang std::string buffer;
69*e7b1675dSTing-Kang Chang ResizeStringUninitialized(&buffer, length);
70*e7b1675dSTing-Kang Chang // TODO(b/207466225): Modify the return to be a StatusOr<std::string> as
71*e7b1675dSTing-Kang Chang // OpenSSL can return an error.
72*e7b1675dSTing-Kang Chang GetRandomBytes(absl::MakeSpan(buffer)).IgnoreError();
73*e7b1675dSTing-Kang Chang return buffer;
74*e7b1675dSTing-Kang Chang }
75*e7b1675dSTing-Kang Chang
GetRandomUInt32()76*e7b1675dSTing-Kang Chang uint32_t Random::GetRandomUInt32() { return GetRandomUint<uint32_t>(); }
GetRandomUInt16()77*e7b1675dSTing-Kang Chang uint16_t Random::GetRandomUInt16() { return GetRandomUint<uint16_t>(); }
GetRandomUInt8()78*e7b1675dSTing-Kang Chang uint8_t Random::GetRandomUInt8() { return GetRandomUint<uint8_t>(); }
79*e7b1675dSTing-Kang Chang
GetRandomKeyBytes(size_t length)80*e7b1675dSTing-Kang Chang util::SecretData Random::GetRandomKeyBytes(size_t length) {
81*e7b1675dSTing-Kang Chang util::SecretData buf(length, 0);
82*e7b1675dSTing-Kang Chang GetRandomBytes(
83*e7b1675dSTing-Kang Chang absl::MakeSpan(reinterpret_cast<char *>(buf.data()), buf.size()))
84*e7b1675dSTing-Kang Chang .IgnoreError();
85*e7b1675dSTing-Kang Chang return buf;
86*e7b1675dSTing-Kang Chang }
87*e7b1675dSTing-Kang Chang
88*e7b1675dSTing-Kang Chang } // namespace subtle
89*e7b1675dSTing-Kang Chang } // namespace tink
90*e7b1675dSTing-Kang Chang } // namespace crypto
91