cryptonite 0.13 → 0.14
raw patch · 18 files changed
+440/−41 lines, 18 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Crypto.PubKey.DH: instance GHC.Classes.Ord Crypto.PubKey.DH.SharedKey
- Crypto.PubKey.DH: instance GHC.Enum.Enum Crypto.PubKey.DH.SharedKey
- Crypto.PubKey.DH: instance GHC.Num.Num Crypto.PubKey.DH.SharedKey
- Crypto.PubKey.DH: instance GHC.Read.Read Crypto.PubKey.DH.SharedKey
- Crypto.PubKey.DH: instance GHC.Real.Real Crypto.PubKey.DH.SharedKey
+ Crypto.MAC.CMAC: cmac :: (ByteArrayAccess bin, BlockCipher cipher) => cipher -> bin -> CMAC cipher
+ Crypto.MAC.CMAC: data CMAC a
+ Crypto.MAC.CMAC: instance Data.ByteArray.Types.ByteArrayAccess (Crypto.MAC.CMAC.CMAC a)
+ Crypto.MAC.CMAC: instance GHC.Classes.Eq (Crypto.MAC.CMAC.CMAC a)
+ Crypto.MAC.CMAC: subKeys :: (BlockCipher k, ByteArray ba) => k -> (ba, ba)
+ Crypto.PubKey.DH: [params_bits] :: Params -> Int
+ Crypto.PubKey.DH: instance Data.ByteArray.Types.ByteArrayAccess Crypto.PubKey.DH.SharedKey
+ Crypto.PubKey.ECC.Types: instance GHC.Enum.Bounded Crypto.PubKey.ECC.Types.CurveName
+ Crypto.Random: data Seed
+ Crypto.Random: drgNewSeed :: Seed -> ChaChaDRG
+ Crypto.Random: instance Data.ByteArray.Types.ByteArrayAccess Crypto.Random.Seed
+ Crypto.Random: seedFromInteger :: Integer -> Seed
+ Crypto.Random: seedNew :: MonadRandom randomly => randomly Seed
+ Crypto.Random: seedToInteger :: Seed -> Integer
- Crypto.PubKey.DH: Params :: Integer -> Integer -> Params
+ Crypto.PubKey.DH: Params :: Integer -> Integer -> Int -> Params
- Crypto.PubKey.DH: SharedKey :: Integer -> SharedKey
+ Crypto.PubKey.DH: SharedKey :: ScrubbedBytes -> SharedKey
- Crypto.PubKey.ECC.DH: SharedKey :: Integer -> SharedKey
+ Crypto.PubKey.ECC.DH: SharedKey :: ScrubbedBytes -> SharedKey
Files
- CHANGELOG.md +13/−0
- Crypto/Hash/Keccak.hs +4/−4
- Crypto/Hash/SHA3.hs +4/−4
- Crypto/KDF/BCrypt.hs +3/−1
- Crypto/KDF/HKDF.hs +5/−4
- Crypto/MAC/CMAC.hs +132/−0
- Crypto/PubKey/DH.hs +9/−6
- Crypto/PubKey/ECC/DH.hs +4/−2
- Crypto/PubKey/ECC/Types.hs +1/−1
- Crypto/PubKey/ElGamal.hs +7/−7
- Crypto/Random.hs +34/−4
- cbits/cryptonite_keccak.c +3/−2
- cbits/cryptonite_keccak.h +1/−1
- cbits/cryptonite_sha3.c +3/−2
- cbits/cryptonite_sha3.h +1/−1
- cryptonite.cabal +4/−2
- tests/KAT_CMAC.hs +210/−0
- tests/Tests.hs +2/−0
CHANGELOG.md view
@@ -1,3 +1,16 @@+## 0.14++* Reduce size of SHA3 context instead of allocating all-size fit memory. save+ up to 72 bytes of memory per context for SHA3-512.+* Add a Seed capability to the main DRG, to be able to debug/reproduce randomized program+ where you would want to disable the randomness.+* Add support for Cipher-based Message Authentication Code (CMAC) (Kei Hibino)+* *CHANGE* Change the `SharedKey` for `Crypto.PubKey.DH` and `Crypto.PubKey.ECC.DH`,+ from an Integer newtype to a ScrubbedBytes newtype. Prevent mistake where the+ bytes representation is generated without the right padding (when needed).+* *CHANGE* Keep The field size in bits, in the `Params` in `Crypto.PubKey.DH`,+ moving from 2 elements to 3 elements in the structure.+ ## 0.13 * *SECURITY* Fix buffer overflow issue in SHA384, copying 16 extra bytes from
Crypto/Hash/Keccak.hs view
@@ -25,7 +25,7 @@ instance HashAlgorithm Keccak_224 where hashBlockSize _ = 144 hashDigestSize _ = 28- hashInternalContextSize _ = 360+ hashInternalContextSize _ = 352 hashInternalInit p = c_keccak_init p 224 hashInternalUpdate = c_keccak_update hashInternalFinalize p = c_keccak_finalize p 224@@ -37,7 +37,7 @@ instance HashAlgorithm Keccak_256 where hashBlockSize _ = 136 hashDigestSize _ = 32- hashInternalContextSize _ = 360+ hashInternalContextSize _ = 344 hashInternalInit p = c_keccak_init p 256 hashInternalUpdate = c_keccak_update hashInternalFinalize p = c_keccak_finalize p 256@@ -49,7 +49,7 @@ instance HashAlgorithm Keccak_384 where hashBlockSize _ = 104 hashDigestSize _ = 48- hashInternalContextSize _ = 360+ hashInternalContextSize _ = 312 hashInternalInit p = c_keccak_init p 384 hashInternalUpdate = c_keccak_update hashInternalFinalize p = c_keccak_finalize p 384@@ -61,7 +61,7 @@ instance HashAlgorithm Keccak_512 where hashBlockSize _ = 72 hashDigestSize _ = 64- hashInternalContextSize _ = 360+ hashInternalContextSize _ = 280 hashInternalInit p = c_keccak_init p 512 hashInternalUpdate = c_keccak_update hashInternalFinalize p = c_keccak_finalize p 512
Crypto/Hash/SHA3.hs view
@@ -25,7 +25,7 @@ instance HashAlgorithm SHA3_224 where hashBlockSize _ = 144 hashDigestSize _ = 28- hashInternalContextSize _ = 360+ hashInternalContextSize _ = 352 hashInternalInit p = c_sha3_init p 224 hashInternalUpdate = c_sha3_update hashInternalFinalize p = c_sha3_finalize p 224@@ -37,7 +37,7 @@ instance HashAlgorithm SHA3_256 where hashBlockSize _ = 136 hashDigestSize _ = 32- hashInternalContextSize _ = 360+ hashInternalContextSize _ = 344 hashInternalInit p = c_sha3_init p 256 hashInternalUpdate = c_sha3_update hashInternalFinalize p = c_sha3_finalize p 256@@ -49,7 +49,7 @@ instance HashAlgorithm SHA3_384 where hashBlockSize _ = 104 hashDigestSize _ = 48- hashInternalContextSize _ = 360+ hashInternalContextSize _ = 312 hashInternalInit p = c_sha3_init p 384 hashInternalUpdate = c_sha3_update hashInternalFinalize p = c_sha3_finalize p 384@@ -61,7 +61,7 @@ instance HashAlgorithm SHA3_512 where hashBlockSize _ = 72 hashDigestSize _ = 64- hashInternalContextSize _ = 360+ hashInternalContextSize _ = 280 hashInternalInit p = c_sha3_init p 512 hashInternalUpdate = c_sha3_update hashInternalFinalize p = c_sha3_finalize p 512
Crypto/KDF/BCrypt.hs view
@@ -1,7 +1,7 @@ -- | Password encoding and validation using bcrypt. ----- Example usasge:+-- Example usage: -- -- >>> import Crypto.KDF.BCrypt (hashPassword, validatePassword) -- >>> import qualified Data.ByteString.Char8 as B@@ -78,6 +78,8 @@ return $ bcrypt cost (salt :: Bytes) password -- | Create a bcrypt hash for a password with a provided cost value and salt.+--+-- Cost value under 4 will be automatically adjusted back to 10 for safety reason. bcrypt :: (ByteArray salt, ByteArray password, ByteArray output) => Int -- ^ The cost parameter. Should be between 4 and 31 (inclusive).
Crypto/KDF/HKDF.hs view
@@ -7,10 +7,9 @@ -- -- Key Derivation Function based on HMAC ----- See rfc5869+-- See RFC5869 -- {-# LANGUAGE BangPatterns #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-} module Crypto.KDF.HKDF ( PRK , extract@@ -35,7 +34,10 @@ -> PRK a -- ^ Pseudo random key extract salt ikm = PRK $ hmac salt ikm --- | Create a PRK directly from the input key material, skipping any hmacing+-- | Create a PRK directly from the input key material.+--+-- Only use when guaranteed to have a good quality and random data to use directly as key.+-- This effectively skip a HMAC with key=salt and data=key. extractSkip :: (HashAlgorithm a, ByteArrayAccess ikm) => ikm -> PRK a@@ -74,4 +76,3 @@ r = n - hashLen in (if n >= hashLen then ti else B.take n ti) : loop hF ti r (i+1)-
+ Crypto/MAC/CMAC.hs view
@@ -0,0 +1,132 @@+-- |+-- Module : Crypto.MAC.CMAC+-- License : BSD-style+-- Maintainer : Kei Hibino <ex8k.hibino@gmail.com>+-- Stability : experimental+-- Portability : unknown+--+-- provide the CMAC (Cipher based Message Authentification Code) base algorithm.+-- <http://en.wikipedia.org/wiki/CMAC>+-- <http://csrc.nist.gov/publications/nistpubs/800-38B/SP_800-38B.pdf>+--+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+module Crypto.MAC.CMAC+ ( cmac+ , CMAC+ , subKeys+ ) where++import Data.Word+import Data.Bits (setBit, testBit, shiftL)+import Data.List (foldl')++import Crypto.Cipher.Types+import Crypto.Internal.ByteArray (ByteArrayAccess, ByteArray, Bytes)+import qualified Crypto.Internal.ByteArray as B++-- | Authentication code+newtype CMAC a = CMAC Bytes+ deriving (ByteArrayAccess)++instance Eq (CMAC a) where+ CMAC b1 == CMAC b2 = B.constEq b1 b2++-- | compute a MAC using the supplied cipher+cmac :: (ByteArrayAccess bin, BlockCipher cipher)+ => cipher -- ^ key to compute CMAC with+ -> bin -- ^ input message+ -> CMAC cipher -- ^ output tag+cmac k msg =+ CMAC $ foldl' (\c m -> ecbEncrypt k $ bxor c m) zeroV ms+ where+ bytes = blockSize k+ zeroV = B.replicate bytes 0 :: Bytes+ (k1, k2) = subKeys k+ ms = cmacChunks k k1 k2 $ B.convert msg++cmacChunks :: (BlockCipher k, ByteArray ba) => k -> ba -> ba -> ba -> [ba]+cmacChunks k k1 k2 = rec' where+ rec' msg+ | B.null tl = if lack == 0+ then [bxor k1 hd]+ else [bxor k2 $ hd `B.append` B.pack (0x80 : replicate (lack - 1) 0)]+ | otherwise = hd : rec' tl+ where+ bytes = blockSize k+ (hd, tl) = B.splitAt bytes msg+ lack = bytes - B.length hd++-- | make sub-keys used in CMAC+subKeys :: (BlockCipher k, ByteArray ba)+ => k -- ^ key to compute CMAC with+ -> (ba, ba) -- ^ sub-keys to compute CMAC+subKeys k = (k1, k2) where+ ipt = cipherIPT k+ k0 = ecbEncrypt k $ B.replicate (blockSize k) 0+ k1 = subKey ipt k0+ k2 = subKey ipt k1++-- polynomial multiply operation to culculate subkey+subKey :: (ByteArray ba) => [Word8] -> ba -> ba+subKey ipt ws = case B.unpack ws of+ [] -> B.empty+ w:_ | testBit w 7 -> B.pack ipt `bxor` shiftL1 ws+ | otherwise -> shiftL1 ws++shiftL1 :: (ByteArray ba) => ba -> ba+shiftL1 = B.pack . shiftL1W . B.unpack++shiftL1W :: [Word8] -> [Word8]+shiftL1W [] = []+shiftL1W ws@(_:ns) = rec' $ zip ws (ns ++ [0]) where+ rec' [] = []+ rec' ((x,y):ps) = w : rec' ps+ where+ w | testBit y 7 = setBit sl1 0+ | otherwise = sl1+ where sl1 = shiftL x 1++bxor :: ByteArray ba => ba -> ba -> ba+bxor = B.xor+++-----+++cipherIPT :: BlockCipher k => k -> [Word8]+cipherIPT = expandIPT . blockSize where++-- Data type which represents the smallest irreducibule binary polynomial+-- against specified degree.+--+-- Maximum degree bit and degree 0 bit are omitted.+-- For example, The value /Q 7 2 1/ corresponds to the degree /128/.+-- It represents that the smallest irreducible binary polynomial of degree 128+-- is x^128 + x^7 + x^2 + x^1 + 1.+data IPolynomial+ = Q Int Int Int+--- | T Int++iPolynomial :: Int -> Maybe IPolynomial+iPolynomial = d where+ d 64 = Just $ Q 4 3 1+ d 128 = Just $ Q 7 2 1+ d _ = Nothing++-- Expand a tail bit pattern of irreducible binary polynomial+expandIPT :: Int -> [Word8]+expandIPT bytes = expandIPT' bytes ipt where+ ipt = maybe (error $ "Irreducible binary polynomial not defined against " ++ show nb ++ " bit") id+ $ iPolynomial nb+ nb = bytes * 8++-- Expand a tail bit pattern of irreducible binary polynomial+expandIPT' :: Int -- ^ width in byte+ -> IPolynomial -- ^ irreducible binary polynomial definition+ -> [Word8] -- ^ result bit pattern+expandIPT' bytes (Q x y z) =+ reverse . setB x . setB y . setB z . setB 0 $ replicate bytes 0+ where+ setB i ws = hd ++ setBit (head tl) r : tail tl where+ (q, r) = i `quotRem` 8+ (hd, tl) = splitAt q ws
Crypto/PubKey/DH.hs view
@@ -23,13 +23,16 @@ import Crypto.Number.ModArithmetic (expSafe) import Crypto.Number.Prime (generateSafePrime) import Crypto.Number.Generate (generateMax)+import Crypto.Number.Serialize (i2ospOf_) import Crypto.Random.Types+import Data.ByteArray (ByteArrayAccess, ScrubbedBytes) import Data.Data -- | Represent Diffie Hellman parameters namely P (prime), and G (generator). data Params = Params { params_p :: Integer , params_g :: Integer+ , params_bits :: Int } deriving (Show,Read,Eq,Data,Typeable) -- | Represent Diffie Hellman public number Y.@@ -41,8 +44,8 @@ deriving (Show,Read,Eq,Enum,Real,Num,Ord) -- | Represent Diffie Hellman shared secret.-newtype SharedKey = SharedKey Integer- deriving (Show,Read,Eq,Enum,Real,Num,Ord)+newtype SharedKey = SharedKey ScrubbedBytes+ deriving (Show,Eq,ByteArrayAccess) -- | generate params from a specific generator (2 or 5 are common values) -- we generate a safe prime (a prime number of the form 2p+1 where p is also prime)@@ -51,17 +54,17 @@ -> Integer -- ^ generator -> m Params generateParams bits generator =- (\p -> Params p generator) <$> generateSafePrime bits+ (\p -> Params p generator bits) <$> generateSafePrime bits -- | generate a private number with no specific property -- this number is usually called X in DH text. generatePrivate :: MonadRandom m => Params -> m PrivateNumber-generatePrivate (Params p _) = PrivateNumber <$> generateMax p+generatePrivate (Params p _ _) = PrivateNumber <$> generateMax p -- | calculate the public number from the parameters and the private key -- this number is usually called Y in DH text. calculatePublic :: Params -> PrivateNumber -> PublicNumber-calculatePublic (Params p g) (PrivateNumber x) = PublicNumber $ expSafe g x p+calculatePublic (Params p g _) (PrivateNumber x) = PublicNumber $ expSafe g x p -- | calculate the public number from the parameters and the private key -- this number is usually called Y in DH text.@@ -73,4 +76,4 @@ -- | generate a shared key using our private number and the other party public number getShared :: Params -> PrivateNumber -> PublicNumber -> SharedKey-getShared (Params p _) (PrivateNumber x) (PublicNumber y) = SharedKey $ expSafe y x p+getShared (Params p _ bits) (PrivateNumber x) (PublicNumber y) = SharedKey $ i2ospOf_ (bits + 7 `div` 8) $ expSafe y x p
Crypto/PubKey/ECC/DH.hs view
@@ -19,10 +19,11 @@ ) where import Crypto.Number.Generate (generateMax)+import Crypto.Number.Serialize (i2ospOf_) import Crypto.PubKey.ECC.Prim (pointMul) import Crypto.Random.Types import Crypto.PubKey.DH (SharedKey(..))-import Crypto.PubKey.ECC.Types (PublicPoint, PrivateNumber, Curve, Point(..))+import Crypto.PubKey.ECC.Types (PublicPoint, PrivateNumber, Curve, Point(..), curveSizeBits) import Crypto.PubKey.ECC.Types (ecc_n, ecc_g, common_curve) -- | Generating a private number d.@@ -41,6 +42,7 @@ -- | Generating a shared key using our private number and -- the other party public point. getShared :: Curve -> PrivateNumber -> PublicPoint -> SharedKey-getShared curve db qa = SharedKey x+getShared curve db qa = SharedKey $ i2ospOf_ (nbBits + 7 `div` 8) x where Point x _ = pointMul curve db qa+ nbBits = curveSizeBits curve
Crypto/PubKey/ECC/Types.hs view
@@ -121,7 +121,7 @@ | SEC_t409r1 | SEC_t571k1 | SEC_t571r1- deriving (Show,Read,Eq,Ord,Enum,Data,Typeable)+ deriving (Show,Read,Eq,Ord,Enum,Bounded,Data,Typeable) {- curvesOIDs :: [ (CurveName, [Integer]) ]
Crypto/PubKey/ElGamal.hs view
@@ -68,12 +68,12 @@ -- | generate a public number that is for the other party benefits. -- this number is usually called h=g^a generatePublic :: Params -> PrivateNumber -> PublicNumber-generatePublic (Params p g) (PrivateNumber a) = PublicNumber $ expSafe g a p+generatePublic (Params p g _) (PrivateNumber a) = PublicNumber $ expSafe g a p -- | encrypt with a specified ephemeral key -- do not reuse ephemeral key. encryptWith :: EphemeralKey -> Params -> PublicNumber -> Integer -> (Integer,Integer)-encryptWith (EphemeralKey b) (Params p g) (PublicNumber h) m = (c1,c2)+encryptWith (EphemeralKey b) (Params p g _) (PublicNumber h) m = (c1,c2) where s = expSafe h b p c1 = expSafe g b p c2 = (s * m) `mod` p@@ -81,12 +81,12 @@ -- | encrypt a message using params and public keys -- will generate b (called the ephemeral key) encrypt :: MonadRandom m => Params -> PublicNumber -> Integer -> m (Integer,Integer)-encrypt params@(Params p _) public m = (\b -> encryptWith b params public m) <$> generateEphemeral q+encrypt params@(Params p _ _) public m = (\b -> encryptWith b params public m) <$> generateEphemeral q where q = p-1 -- p is prime, hence order of the group is p-1 -- | decrypt message decrypt :: Params -> PrivateNumber -> (Integer, Integer) -> Integer-decrypt (Params p _) (PrivateNumber a) (c1,c2) = (c2 * sm1) `mod` p+decrypt (Params p _ _) (PrivateNumber a) (c1,c2) = (c2 * sm1) `mod` p where s = expSafe c1 a p sm1 = fromJust $ inverse s p -- always inversible in Zp @@ -104,7 +104,7 @@ -> hash -- ^ collision resistant hash algorithm -> msg -- ^ message to sign -> Maybe Signature-signWith k (Params p g) (PrivateNumber x) hashAlg msg+signWith k (Params p g _) (PrivateNumber x) hashAlg msg | k >= p-1 || d > 1 = Nothing -- gcd(k,p-1) is not 1 | s == 0 = Nothing | otherwise = Just $ Signature (r,s)@@ -125,7 +125,7 @@ -> hash -- ^ collision resistant hash algorithm -> msg -- ^ message to sign -> m Signature-sign params@(Params p _) priv hashAlg msg = do+sign params@(Params p _ _) priv hashAlg msg = do k <- generateMax (p-1) case signWith k params priv hashAlg msg of Nothing -> sign params priv hashAlg msg@@ -139,7 +139,7 @@ -> msg -> Signature -> Bool-verify (Params p g) (PublicNumber y) hashAlg msg (Signature (r,s))+verify (Params p g _) (PublicNumber y) hashAlg msg (Signature (r,s)) | or [r <= 0,r >= p,s <= 0,s >= (p-1)] = False | otherwise = lhs == rhs where h = os2ip $ hashWith hashAlg msg
Crypto/Random.hs view
@@ -5,14 +5,21 @@ -- Stability : stable -- Portability : good --+{-# LANGUAGE GeneralizedNewtypeDeriving #-} module Crypto.Random ( -- * Deterministic instances ChaChaDRG , SystemDRG+ , Seed+ -- * Seed+ , seedNew+ , seedFromInteger+ , seedToInteger -- * Deterministic Random class , getSystemDRG , drgNew+ , drgNewSeed , drgNewTest , withDRG , withRandomBytes@@ -25,14 +32,37 @@ import Crypto.Random.Types import Crypto.Random.ChaChaDRG import Crypto.Random.SystemDRG-import Data.ByteArray (ByteArray, ScrubbedBytes)+import Data.ByteArray (ByteArray, ByteArrayAccess, ScrubbedBytes) import Crypto.Internal.Imports +import qualified Crypto.Number.Serialize as Serialize++newtype Seed = Seed ScrubbedBytes+ deriving (ByteArrayAccess)++-- Length for ChaCha DRG seed+seedLength :: Int+seedLength = 40++-- | Create a new Seed from system entropy+seedNew :: MonadRandom randomly => randomly Seed+seedNew = Seed `fmap` getRandomBytes seedLength++-- | Convert a Seed to an integer+seedToInteger :: Seed -> Integer+seedToInteger (Seed b) = Serialize.os2ip b++-- | Convert an integer to a Seed+seedFromInteger :: Integer -> Seed+seedFromInteger i = Seed $ Serialize.i2ospOf_ seedLength (i `mod` 2^(seedLength * 8))+ -- | Create a new DRG from system entropy drgNew :: MonadRandom randomly => randomly ChaChaDRG-drgNew = do- b <- getRandomBytes 40- return $ initialize (b :: ScrubbedBytes)+drgNew = drgNewSeed `fmap` seedNew++-- | Create a new DRG from a seed+drgNewSeed :: Seed -> ChaChaDRG+drgNewSeed (Seed seed) = initialize seed -- | Create a new DRG from 5 Word64. --
cbits/cryptonite_keccak.c view
@@ -99,8 +99,9 @@ void cryptonite_keccak_init(struct keccak_ctx *ctx, uint32_t hashlen) {- memset(ctx, 0, sizeof(*ctx));- ctx->bufsz = 200 - 2 * (hashlen / 8);+ int bufsz = 200 - 2 * (hashlen / 8);+ memset(ctx, 0, sizeof(*ctx) + bufsz);+ ctx->bufsz = bufsz; } void cryptonite_keccak_update(struct keccak_ctx *ctx, uint8_t *data, uint32_t len)
cbits/cryptonite_keccak.h view
@@ -31,7 +31,7 @@ uint32_t bufindex; uint32_t bufsz; uint64_t state[25];- uint8_t buf[144]; /* minimum SHA3-224, otherwise buffer need increases */+ uint8_t buf[0]; /* maximum SHA3-224 = 144, otherwise buffer need decrease */ }; #define SHA3_CTX_SIZE sizeof(struct keccak_ctx)
cbits/cryptonite_sha3.c view
@@ -99,8 +99,9 @@ void cryptonite_sha3_init(struct sha3_ctx *ctx, uint32_t hashlen) {- memset(ctx, 0, sizeof(*ctx));- ctx->bufsz = 200 - 2 * (hashlen / 8);+ int bufsz = 200 - 2 * (hashlen / 8);+ memset(ctx, 0, sizeof(*ctx) + bufsz);+ ctx->bufsz = bufsz; } void cryptonite_sha3_update(struct sha3_ctx *ctx, const uint8_t *data, uint32_t len)
cbits/cryptonite_sha3.h view
@@ -31,7 +31,7 @@ uint32_t bufindex; uint32_t bufsz; uint64_t state[25];- uint8_t buf[144]; /* minimum SHA3-224, otherwise buffer need increases */+ uint8_t buf[0]; /* maximum SHA3-224 is 144 bytes, otherwise buffer can be decreases */ }; #define SHA3_CTX_SIZE sizeof(struct sha3_ctx)
cryptonite.cabal view
@@ -1,5 +1,5 @@ Name: cryptonite-Version: 0.13+Version: 0.14 Synopsis: Cryptography Primitives sink Description: A repository of cryptographic primitives.@@ -57,7 +57,7 @@ Manual: True Flag support_rdrand- Description: allow compilation with AESNI on system and architecture that supports it+ Description: allow compilation with RDRAND on system and architecture that supports it Default: True Manual: True @@ -100,6 +100,7 @@ Crypto.Data.AFIS Crypto.Data.Padding Crypto.Error+ Crypto.MAC.CMAC Crypto.MAC.Poly1305 Crypto.MAC.HMAC Crypto.Number.Basic@@ -303,6 +304,7 @@ KAT_Curve25519 KAT_DES KAT_Ed25519+ KAT_CMAC KAT_HMAC KAT_PBKDF2 KAT_PubKey.DSA
+ tests/KAT_CMAC.hs view
@@ -0,0 +1,210 @@++module KAT_CMAC (tests) where++import qualified Crypto.MAC.CMAC as CMAC+import Crypto.Cipher.Types (Cipher, cipherInit, BlockCipher, ecbEncrypt, blockSize)+import Crypto.Error (eitherCryptoError)+import Crypto.Cipher.AES (AES128, AES192, AES256)+import Crypto.Cipher.TripleDES (DES_EDE3, DES_EDE2)++import Imports++import Data.Char (digitToInt)+import qualified Data.ByteString as BS+import qualified Data.ByteArray as B+++hxs :: String -> ByteString+hxs = BS.pack . rec' where+ dtoW8 = fromIntegral . digitToInt+ rec' (' ':xs) = rec' xs+ rec' (x:y:xs) = dtoW8 x * 16 + dtoW8 y : rec' xs+ rec' [_] = error "hxs: invalid hex pattern."+ rec' [] = []++unsafeCipher :: Cipher k => ByteString -> k+unsafeCipher = either (error . show) id . eitherCryptoError . cipherInit++ecb0 :: BlockCipher k => k -> ByteString+ecb0 k = ecbEncrypt k $ BS.replicate (blockSize k) 0++{- Test vectors from NIST data-sheet+ (AES128-CMAC, AES192-CMAC, AES256-CMAC, Three Key TDEA, Two Key TDEA)+ http://csrc.nist.gov/publications/nistpubs/800-38B/Updated_CMAC_Examples.pdf+ The data of AES128-CMAC is same as them in RFC4493.+ -}++msg512 :: ByteString+msg512 =+ hxs $+ "6bc1bee2 2e409f96 e93d7e11 7393172a" +++ "ae2d8a57 1e03ac9c 9eb76fac 45af8e51" +++ "30c81c46 a35ce411 e5fbc119 1a0a52ef" +++ "f69f2445 df4f9b17 ad2b417b e66c3710"++msg320 :: ByteString+msg320 = BS.take 40 msg512++msg256 :: ByteString+msg256 = BS.take 32 msg512++msg160 :: ByteString+msg160 = BS.take 20 msg512++msg128 :: ByteString+msg128 = BS.take 16 msg512++msg64 :: ByteString+msg64 = BS.take 8 msg512++msg0 :: ByteString+msg0 = BS.empty++bsCMAC :: BlockCipher k => k -> ByteString -> ByteString+bsCMAC k = B.convert . CMAC.cmac k++gAES128 :: TestTree+gAES128 =+ igroup "aes128"+ [ ecb0 aes128key @?= hxs "7df76b0c 1ab899b3 3e42f047 b91b546f"+ , aes128k1 @?= hxs "fbeed618 35713366 7c85e08f 7236a8de"+ , aes128k2 @?= hxs "f7ddac30 6ae266cc f90bc11e e46d513b"++ , bsCMAC aes128key msg0+ @?= hxs "bb1d6929 e9593728 7fa37d12 9b756746"+ , bsCMAC aes128key msg128+ @?= hxs "070a16b4 6b4d4144 f79bdd9d d04a287c"+ , bsCMAC aes128key msg320+ @?= hxs "dfa66747 de9ae630 30ca3261 1497c827"+ , bsCMAC aes128key msg512+ @?= hxs "51f0bebf 7e3b9d92 fc497417 79363cfe"+ ]+ where+ aes128key :: AES128+ aes128key =+ unsafeCipher $ hxs+ "2b7e1516 28aed2a6 abf71588 09cf4f3c"++ aes128k1, aes128k2 :: ByteString+ (aes128k1, aes128k2) = CMAC.subKeys aes128key+++gAES192 :: TestTree+gAES192 =+ igroup "aes192"+ [ ecb0 aes192key @?= hxs "22452d8e 49a8a593 9f7321ce ea6d514b"+ , aes192k1 @?= hxs "448a5b1c 93514b27 3ee6439d d4daa296"+ , aes192k2 @?= hxs "8914b639 26a2964e 7dcc873b a9b5452c"++ , bsCMAC aes192key msg0+ @?= hxs "d17ddf46 adaacde5 31cac483 de7a9367"+ , bsCMAC aes192key msg128+ @?= hxs "9e99a7bf 31e71090 0662f65e 617c5184"+ , bsCMAC aes192key msg320+ @?= hxs "8a1de5be 2eb31aad 089a82e6 ee908b0e"+ , bsCMAC aes192key msg512+ @?= hxs "a1d5df0e ed790f79 4d775896 59f39a11"+ ]+ where+ aes192key :: AES192+ aes192key =+ unsafeCipher . hxs $+ "8e73b0f7 da0e6452 c810f32b 809079e5" +++ "62f8ead2 522c6b7b"++ aes192k1, aes192k2 :: ByteString+ (aes192k1, aes192k2) = CMAC.subKeys aes192key++gAES256 :: TestTree+gAES256 =+ igroup "aes256"+ [ ecb0 aes256key @?= hxs "e568f681 94cf76d6 174d4cc0 4310a854"+ , aes256k1 @?= hxs "cad1ed03 299eedac 2e9a9980 8621502f"+ , aes256k2 @?= hxs "95a3da06 533ddb58 5d353301 0c42a0d9"++ , bsCMAC aes256key msg0+ @?= hxs "028962f6 1b7bf89e fc6b551f 4667d983"+ , bsCMAC aes256key msg128+ @?= hxs "28a7023f 452e8f82 bd4bf28d 8c37c35c"+ , bsCMAC aes256key msg320+ @?= hxs "aaf3d8f1 de5640c2 32f5b169 b9c911e6"+ , bsCMAC aes256key msg512+ @?= hxs "e1992190 549f6ed5 696a2c05 6c315410"+ ]+ where+ aes256key :: AES256+ aes256key =+ unsafeCipher . hxs $+ "603deb10 15ca71be 2b73aef0 857d7781" +++ "1f352c07 3b6108d7 2d9810a3 0914dff4"++ aes256k1, aes256k2 :: ByteString+ (aes256k1, aes256k2) = CMAC.subKeys aes256key++gTDEA3 :: TestTree+gTDEA3 =+ igroup "Three Key TDEA"+ [ ecb0 tdea3key @?= hxs "c8cc74e9 8a7329a2"+ , tdea3k1 @?= hxs "9198e9d3 14e6535f"+ , tdea3k2 @?= hxs "2331d3a6 29cca6a5"++ , bsCMAC tdea3key msg0+ @?= hxs "b7a688e1 22ffaf95"+ , bsCMAC tdea3key msg64+ @?= hxs "8e8f2931 36283797"+ , bsCMAC tdea3key msg160+ @?= hxs "743ddbe0 ce2dc2ed"+ , bsCMAC tdea3key msg256+ @?= hxs "33e6b109 2400eae5"+ ]+ where+ tdea3key :: DES_EDE3+ tdea3key =+ unsafeCipher . hxs $+ "8aa83bf8 cbda1062" +++ "0bc1bf19 fbb6cd58" +++ "bc313d4a 371ca8b5"++ tdea3k1, tdea3k2 :: ByteString+ (tdea3k1, tdea3k2) = CMAC.subKeys tdea3key++gTDEA2 :: TestTree+gTDEA2 =+ igroup "Two Key TDEA"+ [ ecb0 tdea2key @?= hxs "c7679b9f 6b8d7d7a"+ , tdea2k1 @?= hxs "8ecf373e d71afaef"+ , tdea2k2 @?= hxs "1d9e6e7d ae35f5c5"++ , bsCMAC tdea2key msg0+ @?= hxs "bd2ebf9a 3ba00361"+ , bsCMAC tdea2key msg64+ @?= hxs "4ff2ab81 3c53ce83"+ , bsCMAC tdea2key msg160+ @?= hxs "62dd1b47 1902bd4e"+ , bsCMAC tdea2key msg256+ @?= hxs "31b1e431 dabc4eb8"+ ]+ where+ tdea2key :: DES_EDE2+ tdea2key =+ unsafeCipher . hxs $+ "4cf15134 a2850dd5" +++ "8a3d10ba 80570d38"++ tdea2k1, tdea2k2 :: ByteString+ (tdea2k1, tdea2k2) = CMAC.subKeys tdea2key++igroup :: TestName -> [Assertion] -> TestTree+igroup nm = testGroup nm . zipWith (flip ($)) [1..] . map icase+ where+ icase c i = testCase (show (i :: Int)) c++nistVectors :: TestTree+nistVectors =+ testGroup "KAT - NIST test vectors"+ [ gAES128, gAES192, gAES256, gTDEA3, gTDEA2 ]++tests :: TestTree+tests =+ testGroup "CMAC"+ [ nistVectors ]
tests/Tests.hs view
@@ -10,6 +10,7 @@ import qualified Salsa import qualified ChaCha import qualified ChaChaPoly1305+import qualified KAT_CMAC import qualified KAT_HMAC import qualified KAT_HKDF import qualified KAT_PBKDF2@@ -35,6 +36,7 @@ , Padding.tests , testGroup "MAC" [ Poly1305.tests+ , KAT_CMAC.tests , KAT_HMAC.tests ] , KAT_Curve25519.tests