aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib.urp5
-rw-r--r--src/random.cc91
-rw-r--r--src/random.h32
-rw-r--r--src/random.urs21
4 files changed, 149 insertions, 0 deletions
diff --git a/src/lib.urp b/src/lib.urp
new file mode 100644
index 0000000..62b02ba
--- /dev/null
+++ b/src/lib.urp
@@ -0,0 +1,5 @@
+ffi random
+benignEffectful Random.bytes
+benignEffectful Random.int
+include random.h
+link -lurweb_crypto_random_openssl -lcrypto
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 <cstddef>
+#include <limits>
+
+#include <openssl/rand.h>
+extern "C" {
+#include <urweb/urweb_cpp.h>
+}
+
+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<int>::max()
+ <= std::numeric_limits<std::size_t>::max(),
+ "int is larger than expected");
+ unsigned char* const result_bytes =
+ static_cast<unsigned char*>(uw_malloc(context,
+ static_cast<std::size_t>(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<char*>(result_bytes);
+}
+
+} // namespace
+
+uw_Basis_int uw_Random_int(struct uw_context* const context) {
+ return *reinterpret_cast<uw_Basis_int*>(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<int>::max()
+ <= std::numeric_limits<std::size_t>::max(),
+ "int is larger than expected");
+ static_assert(std::numeric_limits<int>::max()
+ <= std::numeric_limits<uw_Basis_int>::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<int>::max(),
+ "requested number of bytes is larger than supported");
+ const int n_bytes = static_cast<int>(ur_n_bytes);
+ // Generate random data.
+ return uw_Basis_blob{static_cast<std::size_t>(n_bytes),
+ RandomBytes(context, n_bytes)};
+}
diff --git a/src/random.h b/src/random.h
new file mode 100644
index 0000000..4d05ac3
--- /dev/null
+++ b/src/random.h
@@ -0,0 +1,32 @@
+// 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.
+
+#ifndef URWEB_CRYPTO_RANDOM_OPENSSL_RANDOM_H
+#define URWEB_CRYPTO_RANDOM_OPENSSL_RANDOM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <urweb/urweb_cpp.h>
+
+uw_Basis_int uw_Random_int(struct uw_context*);
+
+uw_Basis_blob uw_Random_bytes(struct uw_context*, const uw_Basis_int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // URWEB_CRYPTO_RANDOM_OPENSSL_RANDOM_H
diff --git a/src/random.urs b/src/random.urs
new file mode 100644
index 0000000..284336b
--- /dev/null
+++ b/src/random.urs
@@ -0,0 +1,21 @@
+(* Copyright 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. *)
+
+(* Generates a random int, chosen uniformly using a cryptographically secure
+entropy pool. *)
+val int : transaction int
+
+(* Returns a blob containing the specified number of cryptographically secure
+pseudorandom bytes. You must specify a nonnegative number equal or less than
+INT_MAX as defined by your platform. *)
+val bytes : int -> transaction blob