aboutsummaryrefslogtreecommitdiff
path: root/v_windows/v/vlib/crypto/rand
diff options
context:
space:
mode:
authorIndrajith K L2022-12-03 17:00:20 +0530
committerIndrajith K L2022-12-03 17:00:20 +0530
commitf5c4671bfbad96bf346bd7e9a21fc4317b4959df (patch)
tree2764fc62da58f2ba8da7ed341643fc359873142f /v_windows/v/vlib/crypto/rand
downloadcli-tools-windows-f5c4671bfbad96bf346bd7e9a21fc4317b4959df.tar.gz
cli-tools-windows-f5c4671bfbad96bf346bd7e9a21fc4317b4959df.tar.bz2
cli-tools-windows-f5c4671bfbad96bf346bd7e9a21fc4317b4959df.zip
Adds most of the toolsHEADmaster
Diffstat (limited to 'v_windows/v/vlib/crypto/rand')
-rw-r--r--v_windows/v/vlib/crypto/rand/crypto_rand_read_test.v15
-rw-r--r--v_windows/v/vlib/crypto/rand/rand.v10
-rw-r--r--v_windows/v/vlib/crypto/rand/rand_darwin.c.v21
-rw-r--r--v_windows/v/vlib/crypto/rand/rand_default.c.v9
-rw-r--r--v_windows/v/vlib/crypto/rand/rand_linux.c.v39
-rw-r--r--v_windows/v/vlib/crypto/rand/rand_solaris.c.v42
-rw-r--r--v_windows/v/vlib/crypto/rand/rand_windows.c.v25
-rw-r--r--v_windows/v/vlib/crypto/rand/utils.v55
8 files changed, 216 insertions, 0 deletions
diff --git a/v_windows/v/vlib/crypto/rand/crypto_rand_read_test.v b/v_windows/v/vlib/crypto/rand/crypto_rand_read_test.v
new file mode 100644
index 0000000..824923d
--- /dev/null
+++ b/v_windows/v/vlib/crypto/rand/crypto_rand_read_test.v
@@ -0,0 +1,15 @@
+import crypto.rand
+
+fn test_reading() ? {
+ a := rand.read(32) ?
+ // dump(a.hex())
+ assert a.len == 32
+ mut histogram := [256]int{}
+ for b in a {
+ histogram[b]++
+ }
+ // dump(histogram)
+ for h in histogram {
+ assert h < 10
+ }
+}
diff --git a/v_windows/v/vlib/crypto/rand/rand.v b/v_windows/v/vlib/crypto/rand/rand.v
new file mode 100644
index 0000000..0703558
--- /dev/null
+++ b/v_windows/v/vlib/crypto/rand/rand.v
@@ -0,0 +1,10 @@
+// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved.
+// Use of this source code is governed by an MIT license
+// that can be found in the LICENSE file.
+
+module rand
+
+struct ReadError {
+ msg string = 'crypto.rand.read() error reading random bytes'
+ code int
+}
diff --git a/v_windows/v/vlib/crypto/rand/rand_darwin.c.v b/v_windows/v/vlib/crypto/rand/rand_darwin.c.v
new file mode 100644
index 0000000..a53198b
--- /dev/null
+++ b/v_windows/v/vlib/crypto/rand/rand_darwin.c.v
@@ -0,0 +1,21 @@
+// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved.
+// Use of this source code is governed by an MIT license
+// that can be found in the LICENSE file.
+
+module rand
+
+#include <Security/SecRandom.h>
+
+#flag darwin -framework Security
+
+fn C.SecRandomCopyBytes(rnd C.SecRandomRef, count size_t, bytes voidptr) int
+
+// read returns an array of `bytes_needed` random bytes read from the OS.
+pub fn read(bytes_needed int) ?[]byte {
+ mut buffer := []byte{len: bytes_needed}
+ status := C.SecRandomCopyBytes(C.SecRandomRef(0), bytes_needed, buffer.data)
+ if status != 0 {
+ return IError(&ReadError{})
+ }
+ return buffer
+}
diff --git a/v_windows/v/vlib/crypto/rand/rand_default.c.v b/v_windows/v/vlib/crypto/rand/rand_default.c.v
new file mode 100644
index 0000000..2e1e823
--- /dev/null
+++ b/v_windows/v/vlib/crypto/rand/rand_default.c.v
@@ -0,0 +1,9 @@
+// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved.
+// Use of this source code is governed by an MIT license
+// that can be found in the LICENSE file.
+module rand
+
+// read returns an array of `bytes_needed` random bytes read from the OS.
+pub fn read(bytes_needed int) ?[]byte {
+ return error('rand.read is not implemented on this platform')
+}
diff --git a/v_windows/v/vlib/crypto/rand/rand_linux.c.v b/v_windows/v/vlib/crypto/rand/rand_linux.c.v
new file mode 100644
index 0000000..52ff3da
--- /dev/null
+++ b/v_windows/v/vlib/crypto/rand/rand_linux.c.v
@@ -0,0 +1,39 @@
+// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved.
+// Use of this source code is governed by an MIT license
+// that can be found in the LICENSE file.
+module rand
+
+#include <sys/syscall.h>
+
+const (
+ read_batch_size = 256
+)
+
+// read returns an array of `bytes_needed` random bytes read from the OS.
+pub fn read(bytes_needed int) ?[]byte {
+ mut buffer := unsafe { malloc_noscan(bytes_needed) }
+ mut bytes_read := 0
+ mut remaining_bytes := bytes_needed
+ // getrandom syscall wont block if requesting <= 256 bytes
+ for bytes_read < bytes_needed {
+ batch_size := if remaining_bytes > rand.read_batch_size {
+ rand.read_batch_size
+ } else {
+ remaining_bytes
+ }
+ rbytes := unsafe { getrandom(batch_size, buffer + bytes_read) }
+ if rbytes == -1 {
+ unsafe { free(buffer) }
+ return IError(&ReadError{})
+ }
+ bytes_read += rbytes
+ }
+ return unsafe { buffer.vbytes(bytes_needed) }
+}
+
+fn getrandom(bytes_needed int, buffer voidptr) int {
+ if bytes_needed > rand.read_batch_size {
+ panic('getrandom() dont request more than $rand.read_batch_size bytes at once.')
+ }
+ return unsafe { C.syscall(C.SYS_getrandom, buffer, bytes_needed, 0) }
+}
diff --git a/v_windows/v/vlib/crypto/rand/rand_solaris.c.v b/v_windows/v/vlib/crypto/rand/rand_solaris.c.v
new file mode 100644
index 0000000..8d0ba0c
--- /dev/null
+++ b/v_windows/v/vlib/crypto/rand/rand_solaris.c.v
@@ -0,0 +1,42 @@
+// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved.
+// Use of this source code is governed by an MIT license
+// that can be found in the LICENSE file.
+
+module rand
+
+#include <sys/random.h>
+
+fn C.getrandom(p &byte, n size_t, flags u32) int
+
+const (
+ read_batch_size = 256
+)
+
+// read returns an array of `bytes_needed` random bytes read from the OS.
+pub fn read(bytes_needed int) ?[]byte {
+ mut buffer := unsafe { malloc_noscan(bytes_needed) }
+ mut bytes_read := 0
+ mut remaining_bytes := bytes_needed
+ // getrandom syscall wont block if requesting <= 256 bytes
+ for bytes_read < bytes_needed {
+ batch_size := if remaining_bytes > rand.read_batch_size {
+ rand.read_batch_size
+ } else {
+ remaining_bytes
+ }
+ rbytes := unsafe { getrandom(batch_size, buffer + bytes_read) }
+ if rbytes == -1 {
+ unsafe { free(buffer) }
+ return IError(&ReadError{})
+ }
+ bytes_read += rbytes
+ }
+ return unsafe { buffer.vbytes(bytes_needed) }
+}
+
+fn v_getrandom(bytes_needed int, buffer voidptr) int {
+ if bytes_needed > rand.read_batch_size {
+ panic('getrandom() dont request more than $rand.read_batch_size bytes at once.')
+ }
+ return C.getrandom(buffer, bytes_needed, 0)
+}
diff --git a/v_windows/v/vlib/crypto/rand/rand_windows.c.v b/v_windows/v/vlib/crypto/rand/rand_windows.c.v
new file mode 100644
index 0000000..075a3ed
--- /dev/null
+++ b/v_windows/v/vlib/crypto/rand/rand_windows.c.v
@@ -0,0 +1,25 @@
+// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved.
+// Use of this source code is governed by an MIT license
+// that can be found in the LICENSE file.
+
+module rand
+
+#flag windows -Llibraries/bcrypt
+#flag windows -lbcrypt
+#include <bcrypt.h>
+
+const (
+ status_success = 0x00000000
+ bcrypt_use_system_preferred_rng = 0x00000002
+)
+
+// read returns an array of `bytes_needed` random bytes read from the OS.
+pub fn read(bytes_needed int) ?[]byte {
+ mut buffer := []byte{len: bytes_needed}
+ // use bcrypt_use_system_preferred_rng because we passed null as algo
+ status := C.BCryptGenRandom(0, buffer.data, bytes_needed, rand.bcrypt_use_system_preferred_rng)
+ if status != rand.status_success {
+ return IError(&ReadError{})
+ }
+ return buffer
+}
diff --git a/v_windows/v/vlib/crypto/rand/utils.v b/v_windows/v/vlib/crypto/rand/utils.v
new file mode 100644
index 0000000..31eaf2d
--- /dev/null
+++ b/v_windows/v/vlib/crypto/rand/utils.v
@@ -0,0 +1,55 @@
+// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved.
+// Use of this source code is governed by an MIT license
+// that can be found in the LICENSE file.
+
+module rand
+
+import math.bits
+import encoding.binary
+
+// int_u64 returns a random unsigned 64-bit integer `u64` read from a real OS source of entropy.
+pub fn int_u64(max u64) ?u64 {
+ bitlen := bits.len_64(max)
+ if bitlen == 0 {
+ return u64(0)
+ }
+ k := (bitlen + 7) / 8
+ mut b := u64(bitlen % 8)
+ if b == u64(0) {
+ b = u64(8)
+ }
+ mut n := u64(0)
+ for {
+ mut bytes := read(k) ?
+ bytes[0] &= byte(int(u64(1) << b) - 1)
+ x := bytes_to_u64(bytes)
+ n = x[0]
+ // NOTE: maybe until we have bigint could do it another way?
+ // if x.len > 1 {
+ // n = u64(u32(x[1])<<u32(32)) | n
+ // }
+ if n < max {
+ return n
+ }
+ }
+ return n
+}
+
+fn bytes_to_u64(b []byte) []u64 {
+ ws := 64 / 8
+ mut z := []u64{len: ((b.len + ws - 1) / ws)}
+ mut i := b.len
+ for k := 0; i >= ws; k++ {
+ z[k] = binary.big_endian_u64(b[i - ws..i])
+ i -= ws
+ }
+ if i > 0 {
+ mut d := u64(0)
+ for s := u64(0); i > 0; s += u64(8) {
+ d |= u64(b[i - 1]) << s
+ i--
+ }
+ z[z.len - 1] = d
+ }
+ return z
+}