1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
|
module KeyGen(mkkey) where
import Char
import System.Random
import System.Directory
import System.IO
import Control.Monad.State
-- Read from /dev/random if available, or just use the built in rng if not
getRandom :: Int -> IO [Int]
getRandom n = do devrnd <- doesFileExist "/dev/urandom"
if devrnd
then do
h <- openFile "/dev/urandom" ReadMode
ns <- readInts n h
hClose h
return ns
else (rndlist n)
where rndlist 0 = return []
rndlist n = do ns <- rndlist (n-1)
x <- randomIO
return (x:ns)
readInts 0 h = return []
readInts n h = do ns <- readInts (n-1) h
x <- hGetChar h
return (fromEnum x : ns)
-- Generate bad random numbers for when a deterministic key is required.
-- (eg testing)
dornd seed = seed*1103515245+12345
mkkey :: Bool -> Int -> Int -> IO String
mkkey det n seed = evalStateT (mkkeyST det n) seed
mkkeyST :: Bool -- Determinism required
-> Int -- Number of bytes required
-> StateT Int IO String
mkkeyST False n = do ns <- lift $ getRandom n
return $ concat $ map (('\\':).show3dm) ns
mkkeyST True 0 = return ""
mkkeyST True n = do seed <- get
let seed' = dornd seed
put seed'
rest <- mkkeyST True (n-1)
return $ "\\" ++ show3d (seed' `mod` 256) ++ rest
show3d n | n < 8 = "00"++ toOct n
| n < 64 = "0"++ toOct n
| otherwise = toOct n
show3dm n = show3d(n `mod` 256)
toOct :: Int -> String
toOct i =
let (q,r) = divMod i 8
e = [intToDigit r]
in
if q==0 then e else toOct q++e
|