From 67aa9d138c9f8b966015d480fc77351c6fd77b68 Mon Sep 17 00:00:00 2001 From: Benjamin Barenblat Date: Tue, 23 Jun 2015 15:42:22 -0400 Subject: Initial commit --- src/random.cc | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 src/random.cc (limited to 'src/random.cc') diff --git a/src/random.cc b/src/random.cc new file mode 100644 index 0000000..12deaf0 --- /dev/null +++ b/src/random.cc @@ -0,0 +1,91 @@ +// Copyright (C) 2015 the Massachusetts Institute of Technology +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#include "random.h" + +#include +#include + +#include +extern "C" { +#include +} + +static_assert(sizeof(char) == 1, "char is not a single byte"); +static_assert(sizeof(unsigned char) == 1, "unsigned char is not a single byte"); + +namespace { + +// Asserts a condition without crashing or releasing information about where the +// error occurred. This function is essential for web programming, where an +// attacker should not be able to bring down the app by causing an assertion +// failure. +void Assert(uw_context* const context, const bool condition, + const failure_kind action, const char* const message) { + if (!condition) { + uw_error(context, action, message); + } +} + +void Assert(uw_context* const context, + const bool condition, const char* const message) { + Assert(context, condition, FATAL, message); +} + +char* RandomBytes(struct uw_context* const context, const int n_bytes) { + Assert(context, 0 <= n_bytes, + "cannot produce a negative number of random bytes"); + // Allocate for the result. Ensure that no precision gets lost when casting + // from int to std::size_t. + static_assert(std::numeric_limits::max() + <= std::numeric_limits::max(), + "int is larger than expected"); + unsigned char* const result_bytes = + static_cast(uw_malloc(context, + static_cast(n_bytes))); + // Fill it with random data. + Assert(context, RAND_bytes(result_bytes, n_bytes) == 1, BOUNDED_RETRY, + "cannot generate random data"); + return reinterpret_cast(result_bytes); +} + +} // namespace + +uw_Basis_int uw_Random_int(struct uw_context* const context) { + return *reinterpret_cast(RandomBytes(context, + sizeof(uw_Basis_int))); +} + +uw_Basis_blob uw_Random_bytes(struct uw_context* const context, + const uw_Basis_int ur_n_bytes) { + // We need to use ur_n_bytes as a number of different types in this function. + // The smallest one, however, is almost certainly int. Ensure that that's the + // case. + static_assert(std::numeric_limits::max() + <= std::numeric_limits::max(), + "int is larger than expected"); + static_assert(std::numeric_limits::max() + <= std::numeric_limits::max(), + "int is larger than expected"); + // Ensure that we don't lose precision when converting ur_n_bytes to int, and + // do so. + Assert(context, 0 <= ur_n_bytes, + "cannot produce a negative number of random bytes"); + Assert(context, ur_n_bytes < std::numeric_limits::max(), + "requested number of bytes is larger than supported"); + const int n_bytes = static_cast(ur_n_bytes); + // Generate random data. + return uw_Basis_blob{static_cast(n_bytes), + RandomBytes(context, n_bytes)}; +} -- cgit v1.2.3