From 8eaaa06e1e2bd9c18326774b0d2d6954317d4efd Mon Sep 17 00:00:00 2001 From: Vincent Hanquez Date: Fri, 22 May 2015 18:35:46 +0100 Subject: [PATCH] add optional support for deepseq --- Crypto/Cipher/AES.hs | 5 +++++ Crypto/Cipher/AES/Primitive.hs | 4 ++++ Crypto/Cipher/Blowfish.hs | 9 +++++++- Crypto/Cipher/Blowfish/Primitive.hs | 6 +++++- Crypto/Cipher/ChaCha.hs | 3 +++ Crypto/Cipher/RC4.hs | 5 +++-- Crypto/Cipher/Salsa.hs | 2 ++ Crypto/Hash/Types.hs | 5 +++-- Crypto/Internal/DeepSeq.hs | 33 +++++++++++++++++++++++++++++ Crypto/Internal/Imports.hs | 10 ++++----- Crypto/PubKey/Curve25519.hs | 6 +++--- Crypto/PubKey/DSA.hs | 16 ++++++++++++++ Crypto/PubKey/ECC/Types.hs | 10 ++++++++- Crypto/PubKey/Ed25519.hs | 6 +++--- Crypto/PubKey/ElGamal.hs | 2 ++ Crypto/PubKey/RSA/Types.hs | 11 +++++++++- Crypto/Random/ChaChaDRG.hs | 4 +++- cryptonite.cabal | 10 +++++++++ 18 files changed, 127 insertions(+), 20 deletions(-) create mode 100644 Crypto/Internal/DeepSeq.hs diff --git a/Crypto/Cipher/AES.hs b/Crypto/Cipher/AES.hs index 00313df..cda3c8c 100644 --- a/Crypto/Cipher/AES.hs +++ b/Crypto/Cipher/AES.hs @@ -5,6 +5,7 @@ -- Stability : stable -- Portability : good {-# LANGUAGE CPP #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} module Crypto.Cipher.AES ( AES128 , AES192 @@ -15,15 +16,19 @@ import Crypto.Error import Crypto.Cipher.Types import Crypto.Cipher.Types.Block import Crypto.Cipher.AES.Primitive +import Crypto.Internal.Imports -- | AES with 128 bit key newtype AES128 = AES128 AES + deriving (NFData) -- | AES with 192 bit key newtype AES192 = AES192 AES + deriving (NFData) -- | AES with 256 bit key newtype AES256 = AES256 AES + deriving (NFData) instance Cipher AES128 where cipherName _ = "AES128" diff --git a/Crypto/Cipher/AES/Primitive.hs b/Crypto/Cipher/AES/Primitive.hs index 47bfb62..d24acf9 100644 --- a/Crypto/Cipher/AES/Primitive.hs +++ b/Crypto/Cipher/AES/Primitive.hs @@ -67,6 +67,7 @@ import Crypto.Error import Crypto.Cipher.Types import Crypto.Cipher.Types.Block (IV(..)) import Crypto.Internal.Compat +import Crypto.Internal.Imports import Crypto.Internal.ByteArray (ByteArray, ByteArrayAccess, ScrubbedBytes, withByteArray) import qualified Crypto.Internal.ByteArray as B @@ -110,12 +111,15 @@ ocbMode aes = AEADModeImpl -- | AES Context (pre-processed key) newtype AES = AES ScrubbedBytes + deriving (NFData) -- | AESGCM State newtype AESGCM = AESGCM ScrubbedBytes + deriving (NFData) -- | AESOCB State newtype AESOCB = AESOCB ScrubbedBytes + deriving (NFData) sizeGCM :: Int sizeGCM = 80 diff --git a/Crypto/Cipher/Blowfish.hs b/Crypto/Cipher/Blowfish.hs index 23478db..040391d 100644 --- a/Crypto/Cipher/Blowfish.hs +++ b/Crypto/Cipher/Blowfish.hs @@ -1,4 +1,3 @@ -{-# LANGUAGE CPP #-} -- | -- Module : Crypto.Cipher.Blowfish -- License : BSD-style @@ -6,6 +5,8 @@ -- Stability : stable -- Portability : good -- +{-# LANGUAGE CPP #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} module Crypto.Cipher.Blowfish ( Blowfish , Blowfish64 @@ -14,23 +15,29 @@ module Crypto.Cipher.Blowfish , Blowfish448 ) where +import Crypto.Internal.Imports import Crypto.Cipher.Types import Crypto.Cipher.Blowfish.Primitive -- | variable keyed blowfish state newtype Blowfish = Blowfish Context + deriving (NFData) -- | 64 bit keyed blowfish state newtype Blowfish64 = Blowfish64 Context + deriving (NFData) -- | 128 bit keyed blowfish state newtype Blowfish128 = Blowfish128 Context + deriving (NFData) -- | 256 bit keyed blowfish state newtype Blowfish256 = Blowfish256 Context + deriving (NFData) -- | 448 bit keyed blowfish state newtype Blowfish448 = Blowfish448 Context + deriving (NFData) instance Cipher Blowfish where cipherName _ = "blowfish" diff --git a/Crypto/Cipher/Blowfish/Primitive.hs b/Crypto/Cipher/Blowfish/Primitive.hs index bd863c3..a0d04f8 100644 --- a/Crypto/Cipher/Blowfish/Primitive.hs +++ b/Crypto/Cipher/Blowfish/Primitive.hs @@ -18,12 +18,13 @@ module Crypto.Cipher.Blowfish.Primitive , decrypt ) where -import Control.Monad (forM_, when) +import Control.Monad (when) import Data.Bits import Data.Word import Crypto.Error import Crypto.Internal.Compat +import Crypto.Internal.Imports import Crypto.Internal.ByteArray (ByteArrayAccess, ByteArray) import qualified Crypto.Internal.ByteArray as B import Crypto.Internal.Words @@ -37,6 +38,9 @@ data Context = BF (Int -> Word32) -- p (Int -> Word32) -- sbox2 (Int -> Word32) -- sbox2 +instance NFData Context where + rnf (BF p a b c d) = p `seq` a `seq` b `seq` c `seq` d `seq` () + -- | Encrypt blocks -- -- Input need to be a multiple of 8 bytes diff --git a/Crypto/Cipher/ChaCha.hs b/Crypto/Cipher/ChaCha.hs index e88488a..3a0f0b6 100644 --- a/Crypto/Cipher/ChaCha.hs +++ b/Crypto/Cipher/ChaCha.hs @@ -6,6 +6,7 @@ -- Portability : good -- {-# LANGUAGE ForeignFunctionInterface #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} module Crypto.Cipher.ChaCha ( initialize , combine @@ -26,9 +27,11 @@ import Foreign.C.Types -- | ChaCha context newtype State = State ScrubbedBytes + deriving (NFData) -- | ChaCha context for DRG purpose (see Crypto.Random.ChaChaDRG) newtype StateSimple = StateSimple ScrubbedBytes -- just ChaCha's state + deriving (NFData) -- | Initialize a new ChaCha context with the number of rounds, -- the key and the nonce associated. diff --git a/Crypto/Cipher/RC4.hs b/Crypto/Cipher/RC4.hs index bd1f241..a0aa92a 100644 --- a/Crypto/Cipher/RC4.hs +++ b/Crypto/Cipher/RC4.hs @@ -26,11 +26,12 @@ import Foreign.Ptr import Crypto.Internal.ByteArray (ScrubbedBytes, ByteArray, ByteArrayAccess) import qualified Crypto.Internal.ByteArray as B -import Crypto.Internal.Compat +import Crypto.Internal.Compat +import Crypto.Internal.Imports -- | The encryption state for RC4 newtype State = State ScrubbedBytes - deriving (ByteArrayAccess) + deriving (ByteArrayAccess,NFData) -- | C Call for initializing the encryptor foreign import ccall unsafe "cryptonite_rc4.h cryptonite_rc4_init" diff --git a/Crypto/Cipher/Salsa.hs b/Crypto/Cipher/Salsa.hs index 9aa2926..10a662f 100644 --- a/Crypto/Cipher/Salsa.hs +++ b/Crypto/Cipher/Salsa.hs @@ -6,6 +6,7 @@ -- Portability : good -- {-# LANGUAGE ForeignFunctionInterface #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} module Crypto.Cipher.Salsa ( initialize , combine @@ -22,6 +23,7 @@ import Foreign.C.Types -- | Salsa context newtype State = State ScrubbedBytes + deriving (NFData) -- | Initialize a new Salsa context with the number of rounds, -- the key and the nonce associated. diff --git a/Crypto/Hash/Types.hs b/Crypto/Hash/Types.hs index 7c5b132..85baf56 100644 --- a/Crypto/Hash/Types.hs +++ b/Crypto/Hash/Types.hs @@ -14,6 +14,7 @@ module Crypto.Hash.Types , Digest(..) ) where +import Crypto.Internal.Imports import Crypto.Internal.ByteArray (ByteArrayAccess, Bytes) import qualified Crypto.Internal.ByteArray as B import Data.Word @@ -47,11 +48,11 @@ hashContextGetAlgorithm = undefined -- | Represent a context for a given hash algorithm. newtype Context a = Context Bytes - deriving (ByteArrayAccess) + deriving (ByteArrayAccess,NFData) -- | Represent a digest for a given hash algorithm. newtype Digest a = Digest Bytes - deriving (Eq,ByteArrayAccess) + deriving (Eq,ByteArrayAccess,NFData) instance Show (Digest a) where show (Digest bs) = show (B.convertToBase B.Base16 bs :: Bytes) diff --git a/Crypto/Internal/DeepSeq.hs b/Crypto/Internal/DeepSeq.hs new file mode 100644 index 0000000..9da7988 --- /dev/null +++ b/Crypto/Internal/DeepSeq.hs @@ -0,0 +1,33 @@ +-- | +-- Module : Crypto.Internal.DeepSeq +-- License : BSD-style +-- Maintainer : Vincent Hanquez +-- Stability : experimental +-- Portability : unknown +-- +-- Simple abstraction module to allow compilation without deepseq +-- by defining our own NFData class if not compiling with deepseq +-- support. +-- +{-# LANGUAGE CPP #-} +module Crypto.Internal.DeepSeq + ( NFData(..) + ) where + +#ifdef WITH_DEEPSEQ_SUPPORT +import Control.DeepSeq +#else +import Data.Word +import Data.ByteArray + +class NFData a where rnf :: a -> () + +instance NFData Word8 where rnf w = w `seq` () +instance NFData Word16 where rnf w = w `seq` () +instance NFData Word32 where rnf w = w `seq` () +instance NFData Word64 where rnf w = w `seq` () + +instance NFData Bytes where rnf b = b `seq` () +instance NFData ScrubbedBytes where rnf b = b `seq` () + +#endif diff --git a/Crypto/Internal/Imports.hs b/Crypto/Internal/Imports.hs index 1edcb38..4ed44e1 100644 --- a/Crypto/Internal/Imports.hs +++ b/Crypto/Internal/Imports.hs @@ -5,12 +5,12 @@ -- Stability : experimental -- Portability : unknown -- -{-# LANGUAGE BangPatterns #-} module Crypto.Internal.Imports ( module X ) where -import Data.Word as X -import Control.Applicative as X -import Control.Monad as X (forM, forM_, void) -import Control.Arrow as X (first, second) +import Data.Word as X +import Control.Applicative as X +import Control.Monad as X (forM, forM_, void) +import Control.Arrow as X (first, second) +import Crypto.Internal.DeepSeq as X diff --git a/Crypto/PubKey/Curve25519.hs b/Crypto/PubKey/Curve25519.hs index f25d124..4d5863c 100644 --- a/Crypto/PubKey/Curve25519.hs +++ b/Crypto/PubKey/Curve25519.hs @@ -33,16 +33,16 @@ import qualified Crypto.Internal.ByteArray as B -- | A Curve25519 Secret key newtype SecretKey = SecretKey ScrubbedBytes - deriving (Show,Eq,ByteArrayAccess) + deriving (Show,Eq,ByteArrayAccess,NFData) -- | A Curve25519 public key newtype PublicKey = PublicKey Bytes - deriving (Show,Eq,ByteArrayAccess) + deriving (Show,Eq,ByteArrayAccess,NFData) -- | A Curve25519 Diffie Hellman secret related to a -- public key and a secret key. newtype DhSecret = DhSecret ScrubbedBytes - deriving (Show,Eq,ByteArrayAccess) + deriving (Show,Eq,ByteArrayAccess,NFData) -- | Try to build a public key from a bytearray publicKey :: ByteArrayAccess bs => bs -> Either String PublicKey diff --git a/Crypto/PubKey/DSA.hs b/Crypto/PubKey/DSA.hs index 7a8ea9c..d3493e4 100644 --- a/Crypto/PubKey/DSA.hs +++ b/Crypto/PubKey/DSA.hs @@ -35,6 +35,7 @@ import Crypto.Number.ModArithmetic (expFast, expSafe, inverse) import Crypto.Number.Serialize import Crypto.Number.Generate import Crypto.Internal.ByteArray (ByteArrayAccess) +import Crypto.Internal.Imports import Crypto.Hash -- | DSA Public Number, usually embedded in DSA Public Key @@ -50,18 +51,27 @@ data Params = Params , params_q :: Integer -- ^ DSA q } deriving (Show,Read,Eq,Data,Typeable) +instance NFData Params where + rnf (Params p g q) = p `seq` g `seq` q `seq` () + -- | Represent a DSA signature namely R and S. data Signature = Signature { sign_r :: Integer -- ^ DSA r , sign_s :: Integer -- ^ DSA s } deriving (Show,Read,Eq,Data,Typeable) +instance NFData Signature where + rnf (Signature r s) = r `seq` s `seq` () + -- | Represent a DSA public key. data PublicKey = PublicKey { public_params :: Params -- ^ DSA parameters , public_y :: PublicNumber -- ^ DSA public Y } deriving (Show,Read,Eq,Data,Typeable) +instance NFData PublicKey where + rnf (PublicKey params y) = y `seq` params `seq` () + -- | Represent a DSA private key. -- -- Only x need to be secret. @@ -71,10 +81,16 @@ data PrivateKey = PrivateKey , private_x :: PrivateNumber -- ^ DSA private X } deriving (Show,Read,Eq,Data,Typeable) +instance NFData PrivateKey where + rnf (PrivateKey params x) = x `seq` params `seq` () + -- | Represent a DSA key pair data KeyPair = KeyPair Params PublicNumber PrivateNumber deriving (Show,Read,Eq,Data,Typeable) +instance NFData KeyPair where + rnf (KeyPair params y x) = x `seq` y `seq` params `seq` () + -- | Public key of a DSA Key pair toPublicKey :: KeyPair -> PublicKey toPublicKey (KeyPair params pub _) = PublicKey params pub diff --git a/Crypto/PubKey/ECC/Types.hs b/Crypto/PubKey/ECC/Types.hs index 206f607..310955b 100644 --- a/Crypto/PubKey/ECC/Types.hs +++ b/Crypto/PubKey/ECC/Types.hs @@ -25,7 +25,8 @@ module Crypto.PubKey.ECC.Types , getCurveByName ) where -import Data.Data +import Data.Data +import Crypto.Internal.Imports -- | Define either a binary curve or a prime curve. data Curve = CurveF2m CurveBinary -- ^ 𝔽(2^m) @@ -43,11 +44,18 @@ data Point = Point Integer Integer | PointO -- ^ Point at Infinity deriving (Show,Read,Eq,Data,Typeable) +instance NFData Point where + rnf (Point x y) = x `seq` y `seq` () + rnf PointO = () + -- | Define an elliptic curve in 𝔽(2^m). -- The firt parameter is the Integer representatioin of the irreducible polynomial f(x). data CurveBinary = CurveBinary Integer CurveCommon deriving (Show,Read,Eq,Data,Typeable) +instance NFData CurveBinary where + rnf (CurveBinary i cc) = i `seq` cc `seq` () + -- | Define an elliptic curve in 𝔽p. -- The first parameter is the Prime Number. data CurvePrime = CurvePrime Integer CurveCommon diff --git a/Crypto/PubKey/Ed25519.hs b/Crypto/PubKey/Ed25519.hs index 2d9e844..6a80db8 100644 --- a/Crypto/PubKey/Ed25519.hs +++ b/Crypto/PubKey/Ed25519.hs @@ -35,15 +35,15 @@ import Crypto.Error -- | An Ed25519 Secret key newtype SecretKey = SecretKey ScrubbedBytes - deriving (Eq,ByteArrayAccess) + deriving (Eq,ByteArrayAccess,NFData) -- | An Ed25519 public key newtype PublicKey = PublicKey Bytes - deriving (Show,Eq,ByteArrayAccess) + deriving (Show,Eq,ByteArrayAccess,NFData) -- | An Ed25519 signature newtype Signature = Signature Bytes - deriving (Show,Eq,ByteArrayAccess) + deriving (Show,Eq,ByteArrayAccess,NFData) -- | Try to build a public key from a bytearray publicKey :: ByteArrayAccess ba => ba -> CryptoFailable PublicKey diff --git a/Crypto/PubKey/ElGamal.hs b/Crypto/PubKey/ElGamal.hs index ed3134a..deca221 100644 --- a/Crypto/PubKey/ElGamal.hs +++ b/Crypto/PubKey/ElGamal.hs @@ -11,6 +11,7 @@ -- TODO: provide a mapping between integer and ciphertext -- generate numbers correctly -- +{-# LANGUAGE GeneralizedNewtypeDeriving #-} module Crypto.PubKey.ElGamal ( Params , PublicNumber @@ -48,6 +49,7 @@ data Signature = Signature (Integer, Integer) -- | ElGamal Ephemeral key. also called Temporary key. newtype EphemeralKey = EphemeralKey Integer + deriving (NFData) -- | generate a private number with no specific property -- this number is usually called a and need to be between diff --git a/Crypto/PubKey/RSA/Types.hs b/Crypto/PubKey/RSA/Types.hs index 0aa1313..9adeea7 100644 --- a/Crypto/PubKey/RSA/Types.hs +++ b/Crypto/PubKey/RSA/Types.hs @@ -6,6 +6,7 @@ -- Portability : Good -- {-# LANGUAGE DeriveDataTypeable #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} module Crypto.PubKey.RSA.Types ( Error(..) , Blinder(..) @@ -20,6 +21,7 @@ module Crypto.PubKey.RSA.Types ) where import Data.Data +import Crypto.Internal.Imports -- | Blinder which is used to obfuscate the timing -- of the decryption primitive (used by decryption and signing). @@ -42,6 +44,9 @@ data PublicKey = PublicKey , public_e :: Integer -- ^ public exponant e } deriving (Show,Read,Eq,Data,Typeable) +instance NFData PublicKey where + rnf (PublicKey sz n e) = rnf n `seq` rnf e `seq` sz `seq` () + -- | Represent a RSA private key. -- -- Only the pub, d fields are mandatory to fill. @@ -62,6 +67,10 @@ data PrivateKey = PrivateKey , private_qinv :: Integer -- ^ q^(-1) mod p } deriving (Show,Read,Eq,Data,Typeable) +instance NFData PrivateKey where + rnf (PrivateKey pub d p q dp dq qinv) = + rnf pub `seq` rnf d `seq` rnf p `seq` rnf q `seq` rnf dp `seq` rnf dq `seq` qinv `seq` () + -- | get the size in bytes from a private key private_size :: PrivateKey -> Int private_size = public_size . private_pub @@ -78,7 +87,7 @@ private_e = public_e . private_pub -- -- note the RSA private key contains already an instance of public key for efficiency newtype KeyPair = KeyPair PrivateKey - deriving (Show,Read,Eq,Data,Typeable) + deriving (Show,Read,Eq,Data,Typeable,NFData) -- | Public key of a RSA KeyPair toPublicKey :: KeyPair -> PublicKey diff --git a/Crypto/Random/ChaChaDRG.hs b/Crypto/Random/ChaChaDRG.hs index f102336..4c6629d 100644 --- a/Crypto/Random/ChaChaDRG.hs +++ b/Crypto/Random/ChaChaDRG.hs @@ -5,6 +5,7 @@ -- Stability : stable -- Portability : good -- +{-# LANGUAGE GeneralizedNewtypeDeriving #-} module Crypto.Random.ChaChaDRG ( ChaChaDRG , initialize @@ -12,9 +13,9 @@ module Crypto.Random.ChaChaDRG ) where import Crypto.Random.Types +import Crypto.Internal.Imports import Crypto.Internal.ByteArray (ByteArray, ScrubbedBytes) import qualified Crypto.Internal.ByteArray as B -import Data.Word import Foreign.Storable (pokeElemOff) import qualified Crypto.Cipher.ChaCha as C @@ -24,6 +25,7 @@ instance DRG ChaChaDRG where -- | ChaCha Deterministic Random Generator newtype ChaChaDRG = ChaChaDRG C.StateSimple + deriving (NFData) -- | Initialize a new ChaCha context with the number of rounds, -- the key and the nonce associated. diff --git a/cryptonite.cabal b/cryptonite.cabal index d39fb29..fe5572f 100644 --- a/cryptonite.cabal +++ b/cryptonite.cabal @@ -61,6 +61,11 @@ Flag integer-gmp Default: True Manual: True +Flag support_deepseq + Description: add deepseq instances for cryptographic types + Default: True + Manual: True + Library Exposed-modules: Crypto.Cipher.AES Crypto.Cipher.Blowfish @@ -147,6 +152,7 @@ Library Crypto.Internal.ByteArray Crypto.Internal.Compat Crypto.Internal.CompatPrim + Crypto.Internal.DeepSeq Crypto.Internal.Imports Crypto.Internal.Words Crypto.Internal.WordArray @@ -216,6 +222,10 @@ Library if impl(ghc) && flag(integer-gmp) Build-depends: integer-gmp + if flag(support_deepseq) + CPP-options: -DWITH_DEEPSEQ_SUPPORT + Build-depends: deepseq + Test-Suite test-cryptonite type: exitcode-stdio-1.0 hs-source-dirs: tests