DRBG 0.1.0 → 0.1.1
raw patch · 5 files changed
+73/−30 lines, 5 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Crypto.Random.DRBG: instance (CryptoRandomGen g) => CryptoRandomGen (GenBuffered g)
+ Crypto.Random.DRBG: instance CryptoRandomGen g => CryptoRandomGen (GenBuffered g)
+ Crypto.Random.DRBG: type HashDRBGWith = State
+ Crypto.Random.DRBG: type HmacDRBGWith = State
- Crypto.Random.DRBG.HMAC: generate :: (Hash c d) => State d -> BitLength -> AdditionalInput -> Maybe (RandomBits, State d)
+ Crypto.Random.DRBG.HMAC: generate :: Hash c d => State d -> BitLength -> AdditionalInput -> Maybe (RandomBits, State d)
- Crypto.Random.DRBG.HMAC: instantiate :: (Hash c d) => Entropy -> Nonce -> PersonalizationString -> State d
+ Crypto.Random.DRBG.HMAC: instantiate :: Hash c d => Entropy -> Nonce -> PersonalizationString -> State d
- Crypto.Random.DRBG.HMAC: reseed :: (Hash c d) => State d -> Entropy -> AdditionalInput -> State d
+ Crypto.Random.DRBG.HMAC: reseed :: Hash c d => State d -> Entropy -> AdditionalInput -> State d
- Crypto.Random.DRBG.Hash: seedlen :: (SeedLength h) => Tagged h Int
+ Crypto.Random.DRBG.Hash: seedlen :: SeedLength h => Tagged h Int
Files
- CHANGELOG +6/−0
- Crypto/Random/DRBG.hs +64/−24
- Crypto/Random/DRBG/HMAC.hs +0/−1
- Crypto/Random/DRBG/Hash.hs +0/−1
- DRBG.cabal +3/−4
+ CHANGELOG view
@@ -0,0 +1,6 @@+New in 0.1.1++* Add HashDRBGWith and HmacDRBGWith+* Allow reseeding of AutoReseed when the second generator to be SystemRandomGen (zero byte reseed of 2nd generator)+* Allow reseeding GenBuffered after an error by tracking the error-inducing generator (and not just the error)+* Fix GenBuffered to buffer properly
Crypto/Random/DRBG.hs view
@@ -11,14 +11,31 @@ and generate some bytes (stepping the generator along the way) one would do: @- gen <- newGenIO :: IO HmacDRBG- let Right (randomBytes, newGen) = genBytes gen 1024+ gen <- newGenIO :: IO HashDRBG+ let Right (randomBytes, newGen) = genBytes 1024 gen @++Selecting the underlying hash algorithm is supporting using *DRBGWith types:++@+ gen <- newGenIO :: IO (HmacDRBGWith SHA224)+@++Composition of generators is supported using two trivial compositions, 'GenXor'+and 'GenAutoReseed'. Additional compositions can be built by instanciating+a 'CryptoRandomGen' as desired.++@+ sysGen <- getGenSystemRandom+ gen <- newGenIO :: IO (GenBuffered (GenAutoReseed (GenXor AesCntDRBG (HashDRBGWith SHA384)) HmacDRBG))+@+ -} module Crypto.Random.DRBG ( HmacDRBG, HashDRBG+ , HmacDRBGWith, HashDRBGWith , GenXor , GenAutoReseed , GenBuffered@@ -41,7 +58,7 @@ import qualified Data.ByteString.Lazy as L import Data.Tagged import Data.Bits (xor)-import Control.Parallel (par)+import Control.Parallel import Control.Monad (liftM) import Control.Monad.Error () -- Either instance import System.IO.Unsafe (unsafeInterleaveIO)@@ -61,10 +78,18 @@ instance H.SeedLength SHA1 where seedlen = Tagged 440 --- |An alias for an HmacDRBG generator using SHA512. This is the recommended generator.+-- |The HMAC DRBG state (of kind * -> *) allowing selection+-- of the underlying hash algorithm (SHA1, SHA224 ... SHA512)+type HmacDRBGWith = M.State++-- |The Hash DRBG state (of kind * -> *) allowing selection+-- of the underlying hash algorithm.+type HashDRBGWith = H.State++-- |An alias for an HMAC DRBG generator using SHA512. type HmacDRBG = M.State SHA512 --- |An Alias for a HashDRBG generator using SHA512.+-- |An Alias for a Hash DRBG generator using SHA512. type HashDRBG = H.State SHA512 newGenAutoReseed :: (CryptoRandomGen a, CryptoRandomGen b) => B.ByteString -> Int -> Either GenError (GenAutoReseed a b)@@ -157,10 +182,14 @@ return (GenAutoReseed a' b' rs 0) else return $ GenAutoReseed aNew b rs (cnt + req) return (res, gNew)- reseed ent (GenAutoReseed a b rs _) = do- let (b1,b2) = B.splitAt (genSeedLength `for` a) ent- a' <- reseed b1 a- b' <- reseed b2 b+ reseed ent gen@(GenAutoReseed a b rs _) + | genSeedLength `for` gen > B.length ent = Left NotEnoughEntropy+ | otherwise = do+ let (e1,e2) = B.splitAt (genSeedLength `for` a) ent+ a' <- reseed e1 a+ b' <- if B.length e2 /= 0+ then reseed e2 b+ else return b return $ GenAutoReseed a' b' rs 0 -- |@g :: GenXor a b@ generates bytes with sub-generators a and b @@ -205,12 +234,8 @@ return (GenXor a' b') -- |@g :: GenBuffered a@ is a generator of type @a@ that attempts to--- maintain a buffer of random values size > 1MB and < 5MB at any time.------ Because of the way in which the buffer is computed (at idle times) and--- information on the previous generator is lost, it basically is not possible--- to reseed this generator after a GenError.-data GenBuffered g = GenBuffered (Either GenError (B.ByteString, g)) {-# UNPACK #-} !B.ByteString+-- maintain a buffer of random values size >= 1MB and <= 5MB at any time.+data GenBuffered g = GenBuffered (Either (GenError, g) (B.ByteString, g)) {-# UNPACK #-} !B.ByteString proxyToGenBuffered :: Proxy g -> Proxy (Either GenError (GenBuffered g)) proxyToGenBuffered = const Proxy@@ -224,8 +249,8 @@ newGen bs = do g <- newGen bs (rs,g') <- genBytes bufferMinSize g- let new = genBytes bufferMinSize g'- return (GenBuffered new rs)+ let new = wrapErr (genBytes bufferMinSize g') g'+ (let !_ = rs in ()) `par` return (GenBuffered new rs) genSeedLength = let a = help res res = Tagged $ genSeedLength `for` a@@ -237,26 +262,35 @@ | remSize >= bufferMinSize = Right (B.take req bs, GenBuffered g (B.drop req bs)) | B.length bs < bufferMinSize = case g of- Left err -> Left err+ Left (err,_) -> Left err Right g -> Left (GenErrorOther "Buffering generator failed to buffer properly - unknown reason") | req > B.length bs = Left RequestedTooManyBytes | remSize < bufferMinSize = case g of- Left err -> Left err -- We could satisfy _this_ request and fail after the buffer runs out, but why bother?+ Left (err,_) -> Left err Right (rnd, gen) ->- let new = genBytes bufferMinSize gen- in (eval new) `par` (genBytes req (GenBuffered new (B.append bs rnd)))+ let new = wrapErr (genBytes bufferMinSize gen) gen+ (rs,rem) = B.splitAt req bs+ in (eval new) `par` Right (rs, GenBuffered new (B.append rem rnd)) | otherwise = Left $ GenErrorOther "Buffering generator hit an impossible case. Please inform DRBG maintainer" where remSize = B.length bs - req genBytesWithEntropy req ent g = reseed ent g >>= \gen -> genBytes req gen reseed ent (GenBuffered g bs) = do- (rs, g') <- g+ let (rs, g') =+ case g of+ Left (_,g') -> (B.empty, g')+ Right (rs, g') -> (rs, g') g'' <- reseed ent g'- let new = genBytes bufferMinSize g''+ let new = wrapErr (genBytes bufferMinSize g'') g'' bs' = B.take bufferMaxSize (B.append bs rs) return (GenBuffered new bs') +wrapErr :: Either x y -> g -> Either (x,g) y+wrapErr (Left x) g = Left (x,g)+wrapErr (Right r) _ = Right r++-- |Force evaluation for use by GenBuffered. eval :: Either x (B.ByteString, g) -> Either x (B.ByteString, g) eval (Left x) = Left x eval (Right (g,bs)) = bs `seq` (g `seq` (Right (g, bs)))@@ -283,7 +317,7 @@ liftM (GenSysRandom . L.fromChunks) getBS instance CryptoRandomGen GenSystemRandom where- newGen _ = Left $ GenErrorOther "SystemRandomGen isn't a semantically correct generator. Tell your developer to use 'Crypto.Random.DRBG.getGenSystemRandom' instead of 'Crypto.Random.newGen'"+ newGen _ = Left $ GenErrorOther "SystemRandomGen isn't a semanticly correct generator. Tell your developer to use 'Crypto.Random.DRBG.getGenSystemRandom' instead of 'Crypto.Random.newGen'" genSeedLength = Tagged 0 genBytes req (GenSysRandom bs) = let reqI = fromIntegral req@@ -293,6 +327,12 @@ then Right (B.concat $ L.toChunks rnd, GenSysRandom rest) else Left $ GenErrorOther "Error obtaining enough bytes from system random for given request" reseed _ _ = Left $ GenErrorOther "SystemRandomGen isn't a semantically correct generator. Don't use 'WithEntropy'."++split :: CryptoRandomGen g => g -> Either GenError (g,g)+split g = do+ (ent,g') <- genBytes (genSeedLength `for` g) g+ new <- newGen ent+ return (g', new) -- |zipWith xor + Pack -- As a result of rewrite rules, this should automatically be optimized (at compile time)
Crypto/Random/DRBG/HMAC.hs view
@@ -15,7 +15,6 @@ import Crypto.HMAC import Crypto.Types import Crypto.Random.DRBG.Types-import qualified Data.Binary as Bin type Key = B.ByteString type Value = B.ByteString
Crypto/Random/DRBG/Hash.hs view
@@ -15,7 +15,6 @@ import Crypto.Random.DRBG.HashDF import Crypto.Classes import Data.Serialize (encode)-import qualified Data.Binary as Bin import Data.Bits (shiftR, shiftL) import Data.Tagged
DRBG.cabal view
@@ -1,5 +1,5 @@ name: DRBG-version: 0.1.0+version: 0.1.1 license: BSD3 license-file: LICENSE author: Thomas DuBuisson <thomas.dubuisson@gmail.com>@@ -11,7 +11,7 @@ build-type: Simple cabal-version: >= 1.6 tested-with: GHC == 6.10.1-Data-Files: Test/HMAC_DRBG.txt Test/Hash_DRBG.txt Test/CTR_DRBG.txt Test/Dual_EC_DRBG.txt+Data-Files: Test/HMAC_DRBG.txt Test/Hash_DRBG.txt Test/CTR_DRBG.txt Test/Dual_EC_DRBG.txt CHANGELOG extra-source-files: Test/HMAC_DRBG.txt Test/Hash_DRBG.txt Test/CTR_DRBG.txt Test/Dual_EC_DRBG.txt @@ -19,10 +19,9 @@ description: Build a program to test the DRBG library default: False - Library Build-Depends: base >= 4.0 && < 4.4, cereal >= 0.2 && <= 0.4,- bytestring, prettyclass, binary, tagged,+ bytestring, prettyclass, tagged, crypto-api >= 0.2, cryptohash >= 0.6.1, parallel, mtl == 2.* ghc-options: -O2 hs-source-dirs: