diff options
author | polwex <polwex@sortug.com> | 2025-10-05 21:56:51 +0700 |
---|---|---|
committer | polwex <polwex@sortug.com> | 2025-10-05 21:56:51 +0700 |
commit | fcedfddf00b3f994e4f4e40332ac7fc192c63244 (patch) | |
tree | 51d38e62c7bdfcc5f9a5e9435fe820c93cfc9a3d /vere/pkg/ent |
claude is gud
Diffstat (limited to 'vere/pkg/ent')
-rw-r--r-- | vere/pkg/ent/.gitignore | 4 | ||||
-rw-r--r-- | vere/pkg/ent/LICENSE | 20 | ||||
-rw-r--r-- | vere/pkg/ent/README.md | 36 | ||||
-rw-r--r-- | vere/pkg/ent/build.zig | 43 | ||||
-rw-r--r-- | vere/pkg/ent/ent.c | 74 | ||||
-rw-r--r-- | vere/pkg/ent/ent.h | 13 | ||||
-rw-r--r-- | vere/pkg/ent/tests.c | 20 |
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(""); +} |