From cc4fd66701c7e0a5c72614d695565ba15f2e9212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?T=C3=B6r=C3=B6k=20Edwin?= Date: Thu, 14 Nov 2013 11:13:50 +0200 Subject: [PATCH 1/2] Do not use buffered reads on /dev/urandom in_channel has a 64k buffer, so one make_random_password () call removes a lot of the system's entropy (for example /proc/sys/kernel/random/entropy_avail goes from ~3000 to 128) --- builder/builder.ml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/builder/builder.ml b/builder/builder.ml index 874dc8d346..55e639e3ac 100644 --- a/builder/builder.ml +++ b/builder/builder.ml @@ -448,6 +448,14 @@ let main () = * Note 'None' means that we randomize the root password. *) let () = + let read_byte fd = + let s = String.make 1 ' ' in + fun () -> + if read fd s 0 1 = 0 then + raise End_of_file; + Char.code s.[0] + in + let make_random_password () = (* Get random characters from the set [A-Za-z0-9] with some * homoglyphs removed. @@ -456,12 +464,12 @@ let main () = "ABCDEFGHIJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz0123456789" in let nr_chars = String.length chars in - let chan = open_in "/dev/urandom" in + let fd = openfile "/dev/urandom" [O_RDONLY] 0 in let buf = String.create 16 in for i = 0 to 15 do - buf.[i] <- chars.[Char.code (input_char chan) mod nr_chars] + buf.[i] <- chars.[read_byte fd () mod nr_chars] done; - close_in chan; + close fd; buf in From 4cd1763d1313c102234f8b5fb40f7124795035ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?T=C3=B6r=C3=B6k=20Edwin?= Date: Thu, 14 Nov 2013 11:20:07 +0200 Subject: [PATCH 2/2] Avoid modulo bias in random password generation Char.code (input_char chan) mod nr_chars has modulo bias because the original interval is not a multiple of the destination interval, i.e. 256 mod nr_chars != 0. One way to fix this is to keep generating random numbers until they fall outside the interval where modulo bias occurs, that is accept only c=[256 % nr_chars, 256). That interval maps back to [0, nr_chars), and has a length of (256 - 256 % nr_chars), which is a multiple of nr_chars. --- builder/builder.ml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/builder/builder.ml b/builder/builder.ml index 55e639e3ac..fd335df431 100644 --- a/builder/builder.ml +++ b/builder/builder.ml @@ -456,6 +456,14 @@ let main () = Char.code s.[0] in + (* return a random number uniformly distributed in [0, upper_bound) + * avoiding modulo bias *) + let rec uniform_random read upper_bound = + let c = read () in + if c >= 256 mod upper_bound then c mod upper_bound + else uniform_random read upper_bound + in + let make_random_password () = (* Get random characters from the set [A-Za-z0-9] with some * homoglyphs removed. @@ -467,7 +475,7 @@ let main () = let fd = openfile "/dev/urandom" [O_RDONLY] 0 in let buf = String.create 16 in for i = 0 to 15 do - buf.[i] <- chars.[read_byte fd () mod nr_chars] + buf.[i] <- chars.[uniform_random (read_byte fd) nr_chars] done; close fd;