shithub: mc

Download patch

ref: 9f26b5a77063d222e3c62cfdcc77f221991b5c4a
parent: 9d6574afc35fe96fbd8f2172fc62f9037df0efb1
author: Ori Bernstein <ori@eigenstate.org>
date: Thu Dec 1 19:11:30 EST 2016

Add CSPRNG based on arc4random.

--- a/lib/crypto/bld.sub
+++ b/lib/crypto/bld.sub
@@ -13,6 +13,7 @@
 
 	# randomness
 	entropy.myr	# currently assumes a /dev/random
+	rand.myr
 
 	lib ../std:std
 	lib ../sys:sys
--- /dev/null
+++ b/lib/crypto/rand.myr
@@ -1,0 +1,100 @@
+use std
+
+use "entropy"
+use "sha256"
+use "chacha20"
+
+pkg crypto =
+	/* designed to mirror std.rand() */
+	const randbytes	: (buf : byte[:] -> void)
+	generic rand	: (lo : @a::(integral,numeric), hi : @a::(integral,numeric) -> @a::(numeric,integral))
+	generic randnum	: (-> @a::(numeric,integral))
+
+	pkglocal const rekey : (entropy : byte[:] -> void)
+;;
+
+const Stirinterval = 16*std.MiB
+const Secretsz = 40
+var buf : byte[4096]	/* let's not encrypt too often */
+var rem	: std.size	/* size remaining in buffer */
+var cnt	: std.size	/* count we've read since last stirring of entropy */
+var ctx	: chacha20ctx	/* the generator */
+var pid	: std.pid	/* for rekeying on fork and exec */
+
+generic rand = {lo, hi
+	var span, lim, val, max
+	
+	span = std.abs(hi - lo)
+	max = ~0
+	/* if ~0 is negative, we have a signed value with a different max */
+	if max < 0
+	        max = (1 << (8*sizeof(@a)-1)) - 1
+	;;
+	
+	lim = (max/span)*span
+	val = (randnum() & max)
+	while val > lim
+	        val = (randnum() & max)
+	;;
+	-> val % span + lo
+}
+
+generic randnum	= {
+	var buf : byte[8]
+
+	randbytes(buf[:])
+	-> std.getle64(buf[:])
+}
+
+const randbytes	 = {dst
+	var n, off, rdlen
+
+	/* costly? */
+	if pid != std.getpid()
+		stir()
+		pid = std.getpid()
+	;;
+	n = 0
+	while n < dst.len
+		if cnt + buf.len >= Stirinterval
+			stir()
+		;;
+		off = buf.len - rem
+		rdlen = std.min(dst.len - n, rem)
+		std.slcp(dst[n:n+rdlen], buf[off:off+rdlen])
+		std.slfill(buf[off:off+rdlen], 0)
+		cnt += rdlen
+		rem -= rdlen
+		n += rdlen
+		if rem == 0
+			rekey([][:])
+		;;
+	;;
+}
+
+const stir = {
+	var entropy : byte[40]
+	rekey(entropy[:])
+	std.slfill(entropy[:], 0)
+	std.slfill(buf[:], 0)
+	rem = 0
+	cnt = 0
+}
+
+const rekey = {entropy
+	var len
+
+	chacha20encrypt(&ctx, buf[:], buf[:])
+	len = std.min(buf.len, entropy.len)
+	for var i = 0; i < len; i++
+		buf[i] ^= entropy[i]
+	;;
+	init(buf[:])
+	std.slfill(buf[:40], 0)
+	rem = buf.len - 40
+}
+
+const init = {buf
+	chacha20keysetup(&ctx, buf[:32])
+	chacha20ivsetup(&ctx, buf[32:40])
+}