mirror of
https://github.com/janet-lang/janet
synced 2024-11-24 09:17:17 +00:00
Add os/cryptorand.
This commit is contained in:
parent
fc53445d08
commit
0ac5b243c7
@ -25,8 +25,6 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#ifndef JANET_REDUCED_OS
|
#ifndef JANET_REDUCED_OS
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
@ -36,6 +34,8 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#define RETRY_EINTR(RC, CALL) do { (RC) = CALL; } while((RC) < 0 && errno == EINTR)
|
||||||
|
|
||||||
#ifdef JANET_WINDOWS
|
#ifdef JANET_WINDOWS
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <direct.h>
|
#include <direct.h>
|
||||||
@ -473,12 +473,13 @@ static Janet os_sleep(int32_t argc, Janet *argv) {
|
|||||||
#ifdef JANET_WINDOWS
|
#ifdef JANET_WINDOWS
|
||||||
Sleep((DWORD)(delay * 1000));
|
Sleep((DWORD)(delay * 1000));
|
||||||
#else
|
#else
|
||||||
|
int rc;
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
ts.tv_sec = (time_t) delay;
|
ts.tv_sec = (time_t) delay;
|
||||||
ts.tv_nsec = (delay <= UINT32_MAX)
|
ts.tv_nsec = (delay <= UINT32_MAX)
|
||||||
? (long)((delay - ((uint32_t)delay)) * 1000000000)
|
? (long)((delay - ((uint32_t)delay)) * 1000000000)
|
||||||
: 0;
|
: 0;
|
||||||
nanosleep(&ts, NULL);
|
RETRY_EINTR(rc, nanosleep(&ts, &ts));
|
||||||
#endif
|
#endif
|
||||||
return janet_wrap_nil();
|
return janet_wrap_nil();
|
||||||
}
|
}
|
||||||
@ -497,6 +498,64 @@ static Janet os_cwd(int32_t argc, Janet *argv) {
|
|||||||
return janet_cstringv(ptr);
|
return janet_cstringv(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Janet os_cryptorand(int32_t argc, Janet *argv) {
|
||||||
|
JanetBuffer *buffer;
|
||||||
|
const char *genericerr = "unable to get sufficient random data";
|
||||||
|
janet_arity(argc, 1, 2);
|
||||||
|
int32_t offset;
|
||||||
|
int32_t n = janet_getinteger(argv, 0);
|
||||||
|
if (n < 0) janet_panic("expected positive integer");
|
||||||
|
if (argc == 2) {
|
||||||
|
buffer = janet_getbuffer(argv, 1);
|
||||||
|
offset = buffer->count;
|
||||||
|
} else {
|
||||||
|
offset = 0;
|
||||||
|
buffer = janet_buffer(n);
|
||||||
|
}
|
||||||
|
/* We could optimize here by adding setcount_uninit */
|
||||||
|
janet_buffer_setcount(buffer, offset + n);
|
||||||
|
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
for (int32_t i = offset; i < buffer->count; i += sizeof(unsigned int)) {
|
||||||
|
unsigned int v;
|
||||||
|
if (rand_s(&v))
|
||||||
|
janet_panic(genericerr);
|
||||||
|
for (int32_t j = 0; (j < sizeof(unsigned int)) && (i + j < buffer->count); j++) {
|
||||||
|
buffer->data[i + j] = v & 0xff;
|
||||||
|
v = v >> 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#elif defined(__linux__) || defined(__APPLE__)
|
||||||
|
/* We should be able to call getrandom on linux, but it doesn't seem
|
||||||
|
to be uniformly supported on linux distros. Macos may support
|
||||||
|
arc4random_buf, but it needs investigation.
|
||||||
|
|
||||||
|
In both cases, use this fallback path for now... */
|
||||||
|
int rc;
|
||||||
|
int randfd;
|
||||||
|
RETRY_EINTR(randfd, open("/dev/urandom", O_RDONLY));
|
||||||
|
if (randfd < 0)
|
||||||
|
janet_panic(genericerr);
|
||||||
|
while (n > 0) {
|
||||||
|
ssize_t nread;
|
||||||
|
RETRY_EINTR(nread, read(randfd, buffer->data + offset, n));
|
||||||
|
if (nread <= 0) {
|
||||||
|
RETRY_EINTR(rc, close(randfd));
|
||||||
|
janet_panic(genericerr);
|
||||||
|
}
|
||||||
|
offset += nread;
|
||||||
|
n -= nread;
|
||||||
|
}
|
||||||
|
RETRY_EINTR(rc, close(randfd));
|
||||||
|
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
|
||||||
|
(void) errmsg;
|
||||||
|
arc4random_buf(buffer->data + offset, n);
|
||||||
|
#else
|
||||||
|
janet_panic("cryptorand currently unsupported on this platform");
|
||||||
|
#endif
|
||||||
|
return janet_wrap_buffer(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
static Janet os_date(int32_t argc, Janet *argv) {
|
static Janet os_date(int32_t argc, Janet *argv) {
|
||||||
janet_arity(argc, 0, 2);
|
janet_arity(argc, 0, 2);
|
||||||
(void) argv;
|
(void) argv;
|
||||||
@ -981,6 +1040,11 @@ static const JanetReg os_cfuns[] = {
|
|||||||
JDOC("(os/cwd)\n\n"
|
JDOC("(os/cwd)\n\n"
|
||||||
"Returns the current working directory.")
|
"Returns the current working directory.")
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"os/cryptorand", os_cryptorand,
|
||||||
|
JDOC("(os/cryptorand n &opt buf)\n\n"
|
||||||
|
"Get or append n bytes of good quality random data provided by the os. Returns a new buffer or buf.")
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"os/date", os_date,
|
"os/date", os_date,
|
||||||
JDOC("(os/date &opt time local)\n\n"
|
JDOC("(os/date &opt time local)\n\n"
|
||||||
|
@ -228,9 +228,13 @@ typedef struct {
|
|||||||
|
|
||||||
/***** START SECTION TYPES *****/
|
/***** START SECTION TYPES *****/
|
||||||
|
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
// Must be defined before including stdlib.h
|
||||||
|
#define _CRT_RAND_S
|
||||||
|
#endif
|
||||||
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
@ -238,4 +238,26 @@
|
|||||||
# Issue #183 - just parse it :)
|
# Issue #183 - just parse it :)
|
||||||
1e-4000000000000000000000
|
1e-4000000000000000000000
|
||||||
|
|
||||||
|
# Ensure randomness puts n of pred into our buffer eventually
|
||||||
|
(defn cryptorand-check
|
||||||
|
[n pred]
|
||||||
|
(def max-attempts 10000)
|
||||||
|
(var attempts 0)
|
||||||
|
(while (not= attempts max-attempts)
|
||||||
|
(def cryptobuf (os/cryptorand 10))
|
||||||
|
(when (= n (count pred cryptobuf))
|
||||||
|
(break))
|
||||||
|
(++ attempts))
|
||||||
|
(not= attempts max-attempts))
|
||||||
|
|
||||||
|
(def v (math/rng-int (math/rng (os/time)) 100))
|
||||||
|
(assert (cryptorand-check 0 |(= $ v)) "cryptorand skips value sometimes")
|
||||||
|
(assert (cryptorand-check 1 |(= $ v)) "cryptorand has value sometimes")
|
||||||
|
|
||||||
|
(do
|
||||||
|
(def buf (buffer/new-filled 1))
|
||||||
|
(os/cryptorand 1 buf)
|
||||||
|
(assert (= (in buf 0) 0) "cryptorand doesn't overwrite buffer")
|
||||||
|
(assert (= (length buf) 2) "cryptorand appends to buffer"))
|
||||||
|
|
||||||
(end-suite)
|
(end-suite)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# Format all code with astyle
|
# Format all code with astyle
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user