Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

initial commit. code mostly forked off tls srandomgen

  • Loading branch information...
commit 95686df7f08874d5096365b8507001e97fedd7c7 0 parents
@vincenthz authored
Showing with 200 additions and 0 deletions.
  1. +114 −0 Crypto/Random/AESCtr.hs
  2. +27 −0 LICENSE
  3. +15 −0 README.md
  4. +44 −0 cprng-aes.cabal
114 Crypto/Random/AESCtr.hs
@@ -0,0 +1,114 @@
+-- |
+-- Module : Crypto.Random.AESCtr
+-- License : BSD-style
+-- Maintainer : Vincent Hanquez <vincent@snarc.org>
+-- Stability : stable
+-- Portability : unknown
+--
+-- this CPRNG is an AES cbc based counter system.
+--
+-- the internal size of fields are: 16 bytes IV, 16 bytes counter, 32 bytes key
+--
+-- each block are generated the following way:
+-- (IV `xor` counter) `aes` key -> 16 bytes output
+--
+
+module Crypto.Random.AESCtr
+ ( AESRNG
+ , make
+ , makeSystem
+ , getRandomBytes
+ ) where
+
+import Control.Applicative ((<$>))
+
+import Crypto.Random
+import System.Crypto.Random (getEntropy)
+import qualified Crypto.Cipher.AES as AES
+
+import Data.ByteString (ByteString)
+import qualified Data.ByteString as B
+
+import Data.Word
+import Data.Bits (xor)
+import Data.Serialize
+
+data Word128 = Word128 !Word64 !Word64
+
+{-| An opaque object containing an AES CPRNG -}
+data AESRNG = RNG !ByteString !Word128 !AES.Key
+
+instance Show AESRNG where
+ show _ = "aesrng[..]"
+
+put128 :: Word128 -> ByteString
+put128 (Word128 a b) = runPut (putWord64host a >> putWord64host b)
+
+get128 :: ByteString -> Word128
+get128 = either (\_ -> Word128 0 0) id . runGet (getWord64host >>= \a -> (getWord64host >>= \b -> return $ Word128 a b))
+
+add1 :: Word128 -> Word128
+add1 (Word128 a b) = if b == 0xffffffffffffffff then Word128 (a+1) 0 else Word128 a (b+1)
+
+makeParams :: ByteString -> (AES.Key, ByteString, ByteString)
+makeParams b = (key, cnt, iv)
+ where
+ (Right key) = AES.initKey256 $ B.take 32 left2
+ (cnt, left2) = B.splitAt 16 left1
+ (iv, left1) = B.splitAt 16 b
+
+-- | make an AESRNG from a bytestring. the bytestring need to be at least 64 bytes.
+-- if the bytestring is longer, the extra bytes will be ignored and will not take part in
+-- the initialization.
+make :: B.ByteString -> Either GenError AESRNG
+make b
+ | B.length b < 64 = Left NotEnoughEntropy
+ | otherwise = Right $ RNG iv (get128 cnt) key
+ where
+ (key, cnt, iv) = makeParams b
+
+chunkSize :: Int
+chunkSize = 16
+
+bxor :: ByteString -> ByteString -> ByteString
+bxor a b = B.pack $ B.zipWith xor a b
+
+nextChunk :: AESRNG -> (ByteString, AESRNG)
+nextChunk (RNG iv counter key) = (chunk, newrng)
+ where
+ newrng = RNG chunk (add1 counter) key
+ chunk = AES.encryptCBC key iv bytes
+ bytes = iv `bxor` (put128 counter)
+
+-- | Initialize a new AESRng using the system entropy.
+makeSystem :: IO AESRNG
+makeSystem = ofRight . make <$> getEntropy 64
+ where
+ ofRight (Left _) = error "ofRight on a Left value"
+ ofRight (Right x) = x
+
+-- | get a Random number of bytes from the RNG.
+-- for efficienty and not wasted any randomness, it's better to generate
+-- bytes on multiple of 16, however it will works for any size.
+getRandomBytes :: AESRNG -> Int -> (ByteString, AESRNG)
+getRandomBytes rng n =
+ let list = helper rng n in
+ (B.concat $ map fst list, snd $ last list)
+ where
+ helper _ 0 = []
+ helper g i =
+ let (b, g') = nextChunk g in
+ if chunkSize >= i
+ then [ (B.take i b, g') ]
+ else (b, g') : helper g' (i-chunkSize)
+
+instance CryptoRandomGen AESRNG where
+ newGen = make
+ genSeedLength = 64
+ genBytes len rng = Right $ getRandomBytes rng len
+ reseed b rng@(RNG _ cnt1 _)
+ | B.length b < 64 = Left NotEnoughEntropy
+ | otherwise = Right $ RNG (r16 `bxor` iv2) (get128 (put128 cnt1 `bxor` cnt2)) key2
+ where
+ (r16, _) = nextChunk rng
+ (key2, cnt2, iv2) = makeParams b
27 LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2010-2011 Vincent Hanquez <vincent@snarc.org>
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. Neither the name of the author nor the names of his contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
15 README.md
@@ -0,0 +1,15 @@
+CPRNG-AES
+=========
+
+This module provides a crypto pseudo random number generator using AES in counter mode.
+
+to import:
+
+ import Crypto.Random.AESCtr
+
+to use:
+
+ rng <- makeSystem
+ let (ran, rng') = getRandomBytes rng 1024
+
+it's also an instance of CryptoRandomGen from the crypto-api package.
44 cprng-aes.cabal
@@ -0,0 +1,44 @@
+Name: cprng-aes
+Version: 0.1.0
+Description:
+ Simple crypto pseudo-random-number-generator with really good randomness property.
+ .
+ Using ent, a randomness property maker on one 1Mb sample:
+ Entropy = 7.999837 bits per byte.
+ Optimum compression would reduce the size of this 1048576 byte file by 0 percent.
+ Chi square distribution for 1048576 samples is 237.02
+ Arithmetic mean value of data bytes is 127.3422 (127.5 = random)
+ Monte Carlo value for Pi is 3.143589568 (error 0.06 percent)
+ .
+ Compared to urandom with the same sampling:
+ Entropy = 7.999831 bits per byte.
+ Optimum compression would reduce the size of this 1048576 byte file by 0 percent.
+ Chi square distribution for 1048576 samples is 246.63
+ Arithmetic mean value of data bytes is 127.6347 (127.5 = random).
+ Monte Carlo value for Pi is 3.132465868 (error 0.29 percent).
+
+License: BSD3
+License-file: LICENSE
+Copyright: Vincent Hanquez <vincent@snarc.org>
+Author: Vincent Hanquez <vincent@snarc.org>
+Maintainer: Vincent Hanquez <vincent@snarc.org>
+Synopsis: Crypto Pseudo Random Number Generator using AES in counter mode.
+Build-Type: Simple
+Category: Cryptography
+stability: experimental
+Cabal-Version: >=1.6
+Homepage: http://github.com/vincenthz/hs-cprng-aes
+data-files: README.md
+
+Library
+ Build-Depends: base >= 3 && < 5
+ , bytestring
+ , crypto-api >= 0.5
+ , cryptocipher >= 0.2.5 && < 0.3.0
+ , cereal >= 0.3.0 && < 0.4.0
+ Exposed-modules: Crypto.Random.AESCtr
+ ghc-options: -Wall
+
+source-repository head
+ type: git
+ location: git://github.com/vincenthz/hs-cprng-aes
Please sign in to comment.
Something went wrong with that request. Please try again.