packages feed

crypto-api 0.6.2 → 0.6.2.1

raw patch · 6 files changed

+144/−107 lines, 6 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

Files

Crypto/Classes.hs view
@@ -132,9 +132,11 @@   buildKey	:: B.ByteString -> Maybe k		-- ^ smart constructor for keys from a bytestring.   keyLength	:: Tagged k BitLength			-- ^ length of the cryptographic key +-- |The number of bytes in a block cipher block blockSizeBytes :: (BlockCipher k) => Tagged k ByteLength blockSizeBytes = fmap (`div` 8) blockSize +-- |Build a symmetric key using the system entropy (see 'System.Crypto.Random') buildKeyIO :: (BlockCipher k) => IO k buildKeyIO = go 0   where@@ -157,6 +159,7 @@   publicKeyLength  :: p -> BitLength   privateKeyLength :: v -> BitLength +-- |Build a pair of asymmetric keys using the system random generator. buildKeyPairIO :: AsymCipher p v => BitLength -> IO (Either GenError (p,v)) buildKeyPairIO bl = do 	g <- newGenIO :: IO SystemRandom@@ -173,6 +176,7 @@   decryptStream 	:: k -> iv -> B.ByteString -> (B.ByteString, iv)   streamKeyLength	:: Tagged k BitLength +-- |Build a stream key using the system random generator buildStreamKeyIO :: StreamCipher k iv => IO k buildStreamKeyIO = go 0   where@@ -196,6 +200,7 @@   signingKeyLength :: v -> BitLength   verifyingKeyLength :: p -> BitLength +-- |Build a signing key using the system random generator buildSigningKeyPairIO :: (Signing p v) => BitLength -> IO (Either GenError (p,v)) buildSigningKeyPairIO bl = do 	g <- newGenIO :: IO SystemRandom
Crypto/Modes.hs view
@@ -5,12 +5,12 @@  Portability: portable   Authors: Thomas DuBuisson, Francisco Blas Izquierdo Riera (klondike) - Generic mode implementations useable by any correct BlockCipher instance - - Be aware there are no tests for CFB mode yet.  See "Test.Crypto".++ Generic mode implementations useable by any correct BlockCipher+instance Be aware there are no tests for CFB mode yet.  See+'Test.Crypto'.  -}-module Crypto.Modes-	(+module Crypto.Modes ( 	-- * Initialization Vector Type, Modifiers (for all ciphers, all modes that use IVs) 	  IV 	, getIV, getIVIO, zeroIV@@ -55,13 +55,14 @@ import Data.Proxy #endif --- |Initilization Vectors for BlockCipher implementations (IV k) are used--- for various modes and guarrenteed to be blockSize bits long.  The common--- ways to obtain an IV are to generate one ('getIV' or 'getIVIO') or to--- use one provided with the ciphertext (using the 'Serialize' instance of IV).+-- |Initilization Vectors for BlockCipher implementations (IV k) are+-- used for various modes and guarrenteed to be blockSize bits long.+-- The common ways to obtain an IV are to generate one ('getIV' or+-- 'getIVIO') or to use one provided with the ciphertext (using the+-- 'Serialize' instance of IV). ----- 'zeroIV' also exists and is of particular use for starting 'ctr' mode with--- a fresh key.+-- 'zeroIV' also exists and is of particular use for starting 'ctr'+-- mode with a fresh key. data IV k = IV { initializationVector :: {-# UNPACK #-} !B.ByteString } deriving (Eq, Ord, Show)  -- gather a specified number of bytes from the list of bytestrings@@ -93,10 +94,11 @@ {-# INLINE chunkFor' #-}  -- |zipWith xor + Pack--- This is written intentionally to take advantage of the bytestring--- libraries 'zipWith'' rewrite rule but at the extra cost of the--- resulting lazy bytestring being more fragmented than either of the--- two inputs.+-- +-- This is written intentionally to take advantage+-- of the bytestring libraries 'zipWith'' rewrite rule but at the+-- extra cost of the resulting lazy bytestring being more fragmented+-- than either of the two inputs. zwp :: L.ByteString -> L.ByteString -> L.ByteString zwp  a b =  	let as = L.toChunks a@@ -115,8 +117,10 @@ {-# INLINEABLE zwp #-}  -- |zipWith xor + Pack--- As a result of rewrite rules, this should automatically be optimized (at compile time) --- to use the bytestring libraries 'zipWith'' function.+--+-- As a result of rewrite rules, this should automatically be+-- optimized (at compile time) to use the bytestring libraries+-- 'zipWith'' function. zwp' :: B.ByteString -> B.ByteString -> B.ByteString zwp' a = B.pack . B.zipWith xor a {-# INLINEABLE zwp' #-}@@ -209,8 +213,8 @@            newIV = head $ genericDrop ((ivLen - 1 + B.length msg) `div` ivLen) ivStr        in (zwp' (B.concat $ collect (B.length msg) (map (encryptBlock k . initializationVector) ivStr)) msg, newIV) --- |Generate cmac subkeys--- |The usage of seq tries to force evaluation of both keys avoiding posible timing attacks+-- |Generate cmac subkeys.  The usage of seq tries to force evaluation+-- of both keys avoiding posible timing attacks cMacSubk :: BlockCipher k => k -> (IV k, IV k) cMacSubk k = (k1, k2) `seq` (k1, k2)   where@@ -218,8 +222,9 @@        k1 = dblIV $ IV $ encryptBlock k $ B.replicate bSize 0        k2 = dblIV $ k1 --- |Pad the string as required by the cmac algorithm. In theory this should work--- | at bit level but since the API works at byte level we do the same+-- |Pad the string as required by the cmac algorithm. In theory this+--  should work at bit level but since the API works at byte level we+--  do the same cMacPad :: ([Word8], Bool, Int) -> Maybe (Word8,([Word8], Bool, Int)) cMacPad (_, _, 0) = Nothing cMacPad ([], False, n) = Just (0,([], False, n-1))@@ -264,7 +269,7 @@ xorend  :: Int -> (Int,[Word8]) -> Maybe (Word8,(Int,[Word8])) xorend bsize (0, []) = Nothing xorend bsize (n, x:xs) | n <= bsize = Just (x,((n-1),xs))-                      | otherwise = Just (0,((n-1),(x:xs)))+                       | otherwise = Just (0,((n-1),(x:xs)))  -- |Obtain the CMAC* on lazy bytestrings cMacStar :: BlockCipher k => k -> [L.ByteString] -> L.ByteString@@ -298,44 +303,41 @@        go 56 w = (64,clearBit w 7)        go n w = (n+8,w) --- |SIV (Synthetic IV) mode for lazy bytestrings--- |First argument is the optional list of bytestrings to be authenticated--- | but not encrypted--- |As required by the specification this algorithm may return nothing when--- | certain constraints aren't met.+-- |SIV (Synthetic IV) mode for lazy bytestrings. First argument is+-- the optional list of bytestrings to be authenticated but not+-- encrypted As required by the specification this algorithm may+-- return nothing when certain constraints aren't met. siv :: BlockCipher k => k -> k -> [L.ByteString] -> L.ByteString -> Maybe L.ByteString siv k1 k2 xs m | length xs > bSizeb - 1 = Nothing-              | otherwise = Just $ L.append iv $ fst $ ctr incIV k2 (IV $ sivMask $ B.concat $ L.toChunks iv) m+               | otherwise = Just $ L.append iv $ fst $ ctr incIV k2 (IV $ sivMask $ B.concat $ L.toChunks iv) m   where        bSize = fromIntegral $ blockSizeBytes `for` k1        bSizeb = fromIntegral $ blockSize `for` k1        iv = cMacStar k1 $ xs ++ [m]  --- |SIV (Synthetic IV) for lazy bytestrings--- |First argument is the optional list of bytestrings to be authenticated--- | but not encrypted--- |As required by the specification this algorithm may return nothing when--- | authentication fails+-- |SIV (Synthetic IV) for lazy bytestrings.  First argument is the+-- optional list of bytestrings to be authenticated but not encrypted.+-- As required by the specification this algorithm may return nothing+-- when authentication fails. unSiv :: BlockCipher k => k -> k -> [L.ByteString] -> L.ByteString -> Maybe L.ByteString unSiv k1 k2 xs c | length xs > bSizeb - 1 = Nothing-                | L.length c < fromIntegral bSize = Nothing-                | iv /= (cMacStar k1 $ xs ++ [dm]) = Nothing-                | otherwise = Just dm+                 | L.length c < fromIntegral bSize = Nothing+                 | iv /= (cMacStar k1 $ xs ++ [dm]) = Nothing+                 | otherwise = Just dm   where        bSize = fromIntegral $ blockSizeBytes `for` k1        bSizeb = fromIntegral $ blockSize `for` k1        (iv,m) = L.splitAt (fromIntegral bSize) c        dm = fst $ unCtr incIV k2 (IV $ sivMask $ B.concat $ L.toChunks iv) m --- |SIV (Synthetic IV) mode for strict bytestrings--- |First argument is the optional list of bytestrings to be authenticated--- | but not encrypted--- |As required by the specification this algorithm may return nothing when--- | certain constraints aren't met.+-- |SIV (Synthetic IV) mode for strict bytestrings.  First argument is+-- the optional list of bytestrings to be authenticated but not+-- encrypted.  As required by the specification this algorithm may+-- return nothing when certain constraints aren't met. siv' :: BlockCipher k => k -> k -> [B.ByteString] -> B.ByteString -> Maybe B.ByteString siv' k1 k2 xs m | length xs > bSizeb - 1 = Nothing-               | otherwise = Just $ B.append iv $ fst $ ctr' incIV k2 (IV $ sivMask iv) m+                | otherwise = Just $ B.append iv $ fst $ ctr' incIV k2 (IV $ sivMask iv) m   where        bSize = fromIntegral $ blockSizeBytes `for` k1        bSizeb = fromIntegral $ blockSize `for` k1@@ -343,24 +345,23 @@   --- |SIV (Synthetic IV) for strict bytestrings--- |First argument is the optional list of bytestrings to be authenticated--- | but not encrypted--- |As required by the specification this algorithm may return nothing when--- | authentication fails+-- |SIV (Synthetic IV) for strict bytestrings First argument is the+-- optional list of bytestrings to be authenticated but not encrypted+-- As required by the specification this algorithm may return nothing+-- when authentication fails. unSiv' :: BlockCipher k => k -> k -> [B.ByteString] -> B.ByteString -> Maybe B.ByteString unSiv' k1 k2 xs c | length xs > bSizeb - 1 = Nothing-                 | B.length c < bSize = Nothing-                 | iv /= (cMacStar' k1 $ xs ++ [dm]) = Nothing-                 | otherwise = Just dm+                  | B.length c < bSize = Nothing+                  | iv /= (cMacStar' k1 $ xs ++ [dm]) = Nothing+                  | otherwise = Just dm   where        bSize = fromIntegral $ blockSizeBytes `for` k1        bSizeb = fromIntegral $ blockSize `for` k1        (iv,m) = B.splitAt bSize c        dm = fst $ unCtr' incIV k2 (IV $ sivMask iv) m --- |Increase an `IV` by one--- |This is way faster than decoding, increasing, encoding +-- |Increase an `IV` by one.  This is way faster than decoding,+-- increasing, encoding incIV :: BlockCipher k => IV k -> IV k incIV (IV b) = IV $ snd $ B.mapAccumR (incw) True b   where@@ -403,9 +404,9 @@ decodeB :: B.ByteString -> Integer decodeB = B.foldl' (\acc w -> (shift acc 8) + toInteger(w)) 0 --- |Cast an Integer into a bigEndian ByteString of size k--- |It will drop the MSBs in case the number is bigger than k and add 00s if it--- |is smaller+-- |Cast an Integer into a bigEndian ByteString of size k.  It will+-- drop the MSBs in case the number is bigger than k and add 00s if it+-- is smaller. encodeB :: (Ord a,Num a) => a -> Integer -> B.ByteString encodeB k n = B.pack $ if lr > k then takel (lr - k) r else pad (k - lr) r   where@@ -422,9 +423,9 @@ decodeL :: L.ByteString -> Integer decodeL = L.foldl' (\acc w -> (shift acc 8) + toInteger(w)) 0 --- |Cast an Integer into a bigEndian ByteString of size k--- |It will drop the MSBs in case the number is bigger than k and add 00s if it--- |is smaller+-- |Cast an Integer into a bigEndian ByteString of size k.  It will+-- drop the MSBs in case the number is bigger than k and add 00s if it+-- is smaller. encodeL :: (Ord a,Num a) => a -> Integer -> L.ByteString encodeL k n = L.pack $ if lr > k then takel (lr - k) r else pad (k - lr) r   where go 0 xs = xs @@ -468,7 +469,8 @@ 	in B.concat $ map (decryptBlock k) chunks {-# INLINEABLE unEcb' #-} --- |Ciphertext feed-back encryption mode for lazy bytestrings (with s == blockSize)+-- |Ciphertext feed-back encryption mode for lazy bytestrings (with s+-- == blockSize) cfb :: BlockCipher k => k -> IV k -> L.ByteString -> (L.ByteString, IV k) cfb k (IV v) msg = 	let blks = chunkFor k msg@@ -482,7 +484,8 @@ 	in (c:cs, ivFinal) {-# INLINEABLE cfb #-} --- |Ciphertext feed-back decryption mode for lazy bytestrings (with s == blockSize)+-- |Ciphertext feed-back decryption mode for lazy bytestrings (with s+-- == blockSize) unCfb :: BlockCipher k => k -> IV k -> L.ByteString -> (L.ByteString, IV k) unCfb k (IV v) msg =  	let blks = chunkFor k msg@@ -496,7 +499,8 @@ 	in (p:ps, ivF) {-# INLINEABLE unCfb #-} --- |Ciphertext feed-back encryption mode for strict bytestrings (with s == blockSize)+-- |Ciphertext feed-back encryption mode for strict bytestrings (with+-- s == blockSize) cfb' :: BlockCipher k => k -> IV k -> B.ByteString -> (B.ByteString, IV k) cfb' k (IV v) msg = 	let blks = chunkFor' k msg@@ -567,7 +571,7 @@ 			| otherwise		-> Left (GenErrorOther "Generator failed to provide requested number of bytes") {-# INLINEABLE getIV #-} --- | Obtain an `IV` using the system entropy (see "System.Crypto.Random")+-- | Obtain an 'IV' using the system entropy (see 'System.Crypto.Random') getIVIO :: (BlockCipher k) => IO (IV k) getIVIO = do 	let p = Proxy
Crypto/Padding.hs view
@@ -1,15 +1,17 @@ {-|- - Maintainer: Thomas.DuBuisson@gmail.com- - Stability: beta- - Portability: portable - -- - PKCS5 (RFC 1423) and IPSec ESP (RFC 4303) padding methods are implemented both- - as trivial functions operating on bytestrings and as 'Put' routines usable from- - the "Data.Serialize" module.  These methods do not work for algorithms or pad- - sizes in excess of 255 bytes (2040 bits, so extremely large as far as cipher needs- - are concerned).- -}+  Maintainer: Thomas.DuBuisson@gmail.com+  Stability: beta+  Portability: portable +PKCS5 (RFC 1423) and IPSec ESP (RFC 4303)+padding methods are implemented both as trivial functions operating on+bytestrings and as 'Put' routines usable from the "Data.Serialize"+module.  These methods do not work for algorithms or pad sizes in+excess of 255 bytes (2040 bits, so extremely large as far as cipher+needs are concerned).++-}+ module Crypto.Padding 	( 	-- * PKCS5 (RFC 1423) based [un]padding routines@@ -35,13 +37,14 @@ padPKCS5 :: ByteLength -> B.ByteString -> B.ByteString padPKCS5 len bs = runPut $ putPaddedPKCS5 len bs --- |+-- | Ex:+-- -- @ --     putPaddedPKCS5 m bs -- @ ----- Will pad out @bs@ to a byte multiple--- of @m@ and put both the bytestring and it's padding via 'Put'+-- Will pad out `bs` to a byte multiple+-- of `m` and put both the bytestring and it's padding via 'Put' -- (this saves on copying if you are already using Cereal). putPaddedPKCS5 :: ByteLength -> B.ByteString -> Put putPaddedPKCS5 0 bs = putByteString bs >> putWord8 1@@ -74,7 +77,8 @@   pLen = fromIntegral padLen   (msg,pad) = B.splitAt (bsLen - pLen) bs --- |unpad a strict bytestring without checking the pad bytes and length any more than necessary.+-- |unpad a strict bytestring without checking the pad bytes and+-- length any more than necessary. unpadPKCS5 :: B.ByteString -> B.ByteString unpadPKCS5 bs = if bsLen == 0 then bs else msg   where@@ -130,7 +134,7 @@   padLen = l - ((B.length bs + 1) `rem` l)   pLen = fromIntegral padLen --- A static espPad allows reuse of a single B.pack'ed pad for all calls to padESP+-- |A static espPad allows reuse of a single B.pack'ed pad for all calls to padESP espPad = B.pack [1..255]  -- | unpad and return the padded message (Nothing is returned if the padding is invalid)
Crypto/Random.hs view
@@ -5,8 +5,10 @@  Portability: portable   - This module is for instantiating cryptographically strong determinitic random bit generators (DRBGs, aka PRNGs)- For the simple use case of using the system random number generator ('System.Crypto.Random') to seed the DRBG:+ This module is for instantiating cryptographically strong+determinitic random bit generators (DRBGs, aka PRNGs) For the simple+use case of using the system random number generator+('System.Crypto.Random') to seed the DRBG:  @   g <- newGenIO @@@ -54,33 +56,42 @@ 	| NeedsInfiniteSeed	-- ^ This generator can not be instantiated or reseeded with a finite seed (ex: 'SystemRandom')   deriving (Eq, Ord, Show) --- |A class of random bit generators that allows for the possibility of failure,--- reseeding, providing entropy at the same time as requesting bytes+-- |A class of random bit generators that allows for the possibility+-- of failure, reseeding, providing entropy at the same time as+-- requesting bytes ----- Minimum complete definition: `newGen`, `genSeedLength`, `genBytes`, `reseed`.+-- Minimum complete definition: `newGen`, `genSeedLength`, `genBytes`,+-- `reseed`. class CryptoRandomGen g where-	-- |Instantiate a new random bit generator.  The provided bytestring should-	-- be of length >= genSeedLength.  If the bytestring is shorter-	-- then the call may fail (suggested error: `NotEnoughEntropy`).  If the-	-- bytestring is of sufficent length the call should always succeed.+	-- |Instantiate a new random bit generator.  The provided+	-- bytestring should be of length >= genSeedLength.  If the+	-- bytestring is shorter then the call may fail (suggested+	-- error: `NotEnoughEntropy`).  If the bytestring is of+	-- sufficent length the call should always succeed. 	newGen :: B.ByteString -> Either GenError g -	-- |Length of input entropy necessary to instantiate or reseed a generator+	-- |Length of input entropy necessary to instantiate or reseed+	-- a generator 	genSeedLength :: Tagged g ByteLength -	-- | @genBytes len g@ generates a random ByteString of length @len@ and new generator.-	-- The "MonadCryptoRandom" package has routines useful for converting the ByteString-	-- to commonly needed values (but "cereal" or other deserialization libraries would also work).+	-- | @genBytes len g@ generates a random ByteString of length+	-- @len@ and new generator.  The "MonadCryptoRandom" package+	-- has routines useful for converting the ByteString to+	-- commonly needed values (but "cereal" or other+	-- deserialization libraries would also work). 	---	-- This routine can fail if the generator has gone too long without a reseed (usually this-	-- is in the ball-park of 2^48 requests).  Suggested error in this cases is `NeedReseed`+	-- This routine can fail if the generator has gone too long+	-- without a reseed (usually this is in the ball-park of 2^48+	-- requests).  Suggested error in this cases is `NeedReseed` 	genBytes	:: ByteLength -> g -> Either GenError (B.ByteString, g) -	-- |@genBytesWithEntropy g i entropy@ generates @i@ random bytes and use the-	-- additional input @entropy@ in the generation of the requested data to-	-- increase the confidence our generated data is a secure random stream.+	-- |@genBytesWithEntropy g i entropy@ generates @i@ random+	-- bytes and use the additional input @entropy@ in the+	-- generation of the requested data to increase the confidence+	-- our generated data is a secure random stream. 	---	-- Some generators use @entropy@ to perturb the state of the generator, meaning:+	-- Some generators use @entropy@ to perturb the state of the+	-- generator, meaning: 	-- 	-- @ 	--     (_,g2') <- genBytesWithEntropy len g1 ent@@ -104,13 +115,16 @@ 				let entropy' = B.append entropy (B.replicate (len - B.length entropy) 0) 				in Right (zwp' entropy' bs, g') -	-- |If the generator has produced too many random bytes on its existing seed-	-- it will throw `NeedReseed`.  In that case, reseed the generator using this function and-	-- a new high-entropy seed of length >= `genSeedLength`.  Using bytestrings that are too short-	-- can result in an error (`NotEnoughEntropy`).+	-- |If the generator has produced too many random bytes on its+	-- existing seed it will throw `NeedReseed`.  In that case,+	-- reseed the generator using this function and a new+	-- high-entropy seed of length >= `genSeedLength`.  Using+	-- bytestrings that are too short can result in an error+	-- (`NotEnoughEntropy`). 	reseed		:: B.ByteString -> g -> Either GenError g -	-- |By default this uses "System.Crypto.Random" to obtain entropy for `newGen`.+	-- |By default this uses "System.Crypto.Random" to obtain+	-- entropy for `newGen`. 	newGenIO :: IO g 	newGenIO = go 0 	  where@@ -134,8 +148,10 @@                 return (bs:more)         liftM (SysRandom . L.fromChunks) getBS --- |Not that it is technically correct as an instance of 'CryptoRandomGen', but simply because--- it's a reasonable engineering choice here is a CryptoRandomGen which streams the system randoms. Take note:+-- |Not that it is technically correct as an instance of+-- 'CryptoRandomGen', but simply because it's a reasonable engineering+-- choice here is a CryptoRandomGen which streams the system+-- randoms. Take note: --  --  * It uses the default definition of 'genByteWithEntropy' --@@ -144,6 +160,7 @@ --  * 'reseed' will always fail! -- --  * the handle to the system random is never closed+-- data SystemRandom = SysRandom L.ByteString  instance CryptoRandomGen SystemRandom where@@ -159,9 +176,11 @@         reseed _ _ = Left NeedsInfiniteSeed         newGenIO = getSystemGen --- |While the safety and wisdom of a splitting function depends on the properties of the generator being split,--- several arguments from informed people indicate such a function is safe for NIST SP 800-90 generators.--- (see libraries@haskell.org discussion ~ Sept, Oct 2010)+-- | While the safety and wisdom of a splitting function depends on the+-- properties of the generator being split, several arguments from+-- informed people indicate such a function is safe for NIST SP 800-90+-- generators.  (see libraries\@haskell.org discussion around Sept, Oct+-- 2010) splitGen :: CryptoRandomGen g => g -> Either GenError (g,g) splitGen g = do 	let e = genBytes (genSeedLength `for` g) g@@ -176,6 +195,7 @@ for :: Tagged a b -> a -> b for t _ = unTagged t +-- |Helper function to convert bytestrings to integers bs2i :: B.ByteString -> Integer bs2i bs = B.foldl' (\i b -> (i `shiftL` 8) + fromIntegral b) 0 bs {-# INLINE bs2i #-}
Crypto/Types.hs view
@@ -1,7 +1,11 @@+-- |Type aliases used throughout the crypto-api modules. module Crypto.Types where  import Data.ByteString as B import Data.ByteString.Lazy as L +-- |The length of a field (usually a ByteString) in bits type BitLength = Int++-- |The length fo a field in bytes. type ByteLength = Int
crypto-api.cabal view
@@ -1,5 +1,5 @@ name:           crypto-api-version:        0.6.2+version:        0.6.2.1 license:        BSD3 license-file:   LICENSE copyright:      Thomas DuBuisson <thomas.dubuisson@gmail.com>, Francisco Blas Izquierdo Riera (klondike) (see AUTHORS)