summaryrefslogtreecommitdiff
path: root/vere/pkg/ent
diff options
context:
space:
mode:
authorpolwex <polwex@sortug.com>2025-10-05 21:56:51 +0700
committerpolwex <polwex@sortug.com>2025-10-05 21:56:51 +0700
commitfcedfddf00b3f994e4f4e40332ac7fc192c63244 (patch)
tree51d38e62c7bdfcc5f9a5e9435fe820c93cfc9a3d /vere/pkg/ent
claude is gud
Diffstat (limited to 'vere/pkg/ent')
-rw-r--r--vere/pkg/ent/.gitignore4
-rw-r--r--vere/pkg/ent/LICENSE20
-rw-r--r--vere/pkg/ent/README.md36
-rw-r--r--vere/pkg/ent/build.zig43
-rw-r--r--vere/pkg/ent/ent.c74
-rw-r--r--vere/pkg/ent/ent.h13
-rw-r--r--vere/pkg/ent/tests.c20
7 files changed, 210 insertions, 0 deletions
diff --git a/vere/pkg/ent/.gitignore b/vere/pkg/ent/.gitignore
new file mode 100644
index 0000000..97b75b0
--- /dev/null
+++ b/vere/pkg/ent/.gitignore
@@ -0,0 +1,4 @@
+/*.a
+/*.o
+/out
+/test
diff --git a/vere/pkg/ent/LICENSE b/vere/pkg/ent/LICENSE
new file mode 100644
index 0000000..6cbc428
--- /dev/null
+++ b/vere/pkg/ent/LICENSE
@@ -0,0 +1,20 @@
+Copyright 2019 Steven Dee
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vere/pkg/ent/README.md b/vere/pkg/ent/README.md
new file mode 100644
index 0000000..f1205fa
--- /dev/null
+++ b/vere/pkg/ent/README.md
@@ -0,0 +1,36 @@
+## `libent`
+
+`libent` is a cross-platform wrapper around `getentropy(2)`. It exports
+one symbol, `ent_getentropy`. If getentropy is available, then it's just
+a shim around that. Otherwise, it uses `getrandom(2)` (available since
+kernel 3.17) on Linux, or `/dev/urandom` on other \*nix.
+
+
+### Building and Testing
+
+```bash
+bazel build ...
+bazel test ...
+```
+
+### Why?
+
+`getentropy` is the wave of the future. It's the correct API for
+generating small amounts of entropy to create cryptographic keys or seed
+PRNGs. It's good and reasonable and true, it's on Linux, \*BSD, and OS
+X, and it only took us fifty years of UNIX to get here.
+
+Sadly, it only just arrived, so nobody has it yet. It didn't land in
+Linux until glibc 2.25, which seems to only have made it into Debian 10.
+
+Once `getentropy` is everywhere you care about, you can just do a
+s/ent\_//g on all the call sites and discard this shim.
+
+This project began because [Urbit](https://github.com/urbit/urbit)'s
+entropy-generation function was bothering me. Then it got out of hand.
+
+
+### References
+
+* [OpenBSD getentropy](https://man.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man2/getentropy.2)
+* [djb on entropy gathering](https://blog.cr.yp.to/20140205-entropy.html)
diff --git a/vere/pkg/ent/build.zig b/vere/pkg/ent/build.zig
new file mode 100644
index 0000000..97b3c4e
--- /dev/null
+++ b/vere/pkg/ent/build.zig
@@ -0,0 +1,43 @@
+const std = @import("std");
+
+pub fn build(b: *std.Build) !void {
+ const target = b.standardTargetOptions(.{});
+ const optimize = b.standardOptimizeOption(.{});
+
+ const t = target.result;
+
+ const copts: []const []const u8 =
+ b.option([]const []const u8, "copt", "") orelse &.{};
+
+ var flags = std.ArrayList([]const u8).init(b.allocator);
+ defer flags.deinit();
+ try flags.appendSlice(&.{
+ "-pedantic",
+ "-std=gnu99",
+ });
+ try flags.appendSlice(copts);
+
+ const pkg_ent = b.addStaticLibrary(.{
+ .name = "ent",
+ .target = target,
+ .optimize = optimize,
+ });
+
+ pkg_ent.linkLibC();
+
+ pkg_ent.addIncludePath(b.path(""));
+
+ pkg_ent.addCSourceFiles(.{
+ .root = b.path(""),
+ .files = &.{"ent.c"},
+ .flags = flags.items,
+ });
+
+ pkg_ent.installHeader(b.path("ent.h"), "ent/ent.h");
+
+ if (t.os.tag == .windows) {
+ pkg_ent.linkSystemLibrary("bcrypt");
+ }
+
+ b.installArtifact(pkg_ent);
+}
diff --git a/vere/pkg/ent/ent.c b/vere/pkg/ent/ent.c
new file mode 100644
index 0000000..0375774
--- /dev/null
+++ b/vere/pkg/ent/ent.c
@@ -0,0 +1,74 @@
+// Use `getentropy` from unistd.h //////////////////////////////////////////////
+
+#if defined(ENT_GETENTROPY_UNISTD)
+#include <stddef.h>
+#include <unistd.h>
+int ent_getentropy(void* buf, size_t len) {
+ return getentropy(buf, len);
+}
+
+
+// Use `getentropy` from sys/random.h //////////////////////////////////////////
+
+#elif defined(ENT_GETENTROPY_SYSRANDOM)
+#include <stddef.h>
+// See https://www.mail-archive.com/bug-gnulib@gnu.org/msg38583.html.
+#include <stdlib.h>
+#include <sys/random.h>
+int ent_getentropy(void* buf, size_t len) {
+ return getentropy(buf, len);
+}
+
+
+// Use the `getrandom` syscall /////////////////////////////////////////////////
+
+#elif defined(ENT_GETRANDOM_SYSCALL)
+#include <stddef.h>
+#include <errno.h>
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#define ENTFAIL { errno=EIO; return -1; }
+
+int ent_getentropy(void* buf, size_t len) {
+ if (len > 256) ENTFAIL
+ int r = syscall(SYS_getrandom, buf, len, 0);
+ if (r < 0) return r;
+ if (r != len) ENTFAIL
+ return 0;
+}
+
+
+// Use `/dev/urandom` //////////////////////////////////////////////////////////
+
+#elif defined(ENT_DEV_URANDOM)
+#include <stddef.h>
+#include <errno.h>
+#include <stdio.h>
+
+#define ENTFAIL { errno=EIO; return -1; }
+
+int ent_getentropy(void* buf, size_t len) {
+ if (len > 256) ENTFAIL;
+ FILE *f = fopen("/dev/urandom", "re");
+ if (!f) return -1;
+ int r = fread(buf, 1, len, f);
+ (void) fclose(f);
+ if (r != len) ENTFAIL
+ return 0;
+}
+
+
+// Use `BCryptGenRandom` on Windows ////////////////////////////////////////////
+
+#elif defined(ENT_GETENTROPY_BCRYPTGENRANDOM)
+#include <windows.h>
+#include <bcrypt.h>
+int ent_getentropy(void* buf, size_t len) {
+ return BCryptGenRandom(NULL, (PUCHAR)buf, len, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
+}
+
+#else
+#error "One of these must be set: ENT_GETENTROPY_BCRYPTGENRANDOM, ENT_DEV_URANDOM, ENT_GETENTROPY_UNISTD, ENT_GETENTROPY_SYSRANDOM, ENT_GETRANDOM_SYSCALL"
+#endif
diff --git a/vere/pkg/ent/ent.h b/vere/pkg/ent/ent.h
new file mode 100644
index 0000000..e838d61
--- /dev/null
+++ b/vere/pkg/ent/ent.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <stddef.h>
+
+/*
+ Fills buf with high-quality entropy.
+
+ buflen is the number of bytes, no greater than 256.
+
+ Returns 0 on success. On failure, returns -1 and sets errno to
+ indicate the error.
+*/
+int ent_getentropy(void* buf, size_t buflen);
diff --git a/vere/pkg/ent/tests.c b/vere/pkg/ent/tests.c
new file mode 100644
index 0000000..90b6ca0
--- /dev/null
+++ b/vere/pkg/ent/tests.c
@@ -0,0 +1,20 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ent.h"
+
+int main(void) {
+ char buf[256] = {0};
+
+ if (0 != ent_getentropy(buf, sizeof(buf))) {
+ perror("getentropy");
+ exit(1);
+ }
+
+ for (int i = 0; i < sizeof buf; i++) {
+ printf("%02hhx", buf[i]);
+ }
+
+ puts("");
+}