From 5e4b126fc5eee42aea65b3db4dfb57256b6e2880 Mon Sep 17 00:00:00 2001 From: Kei Hibino Date: Sun, 3 Apr 2016 05:51:07 +0900 Subject: [PATCH 01/14] Add implementation of MiyaguchiPreneel. --- Crypto/ConstructHash/MiyaguchiPreneel.hs | 56 ++++++++++++++++++++++++ cryptonite.cabal | 1 + 2 files changed, 57 insertions(+) create mode 100644 Crypto/ConstructHash/MiyaguchiPreneel.hs diff --git a/Crypto/ConstructHash/MiyaguchiPreneel.hs b/Crypto/ConstructHash/MiyaguchiPreneel.hs new file mode 100644 index 0000000..585b4f9 --- /dev/null +++ b/Crypto/ConstructHash/MiyaguchiPreneel.hs @@ -0,0 +1,56 @@ +-- | +-- Module : Crypto.ConstructHash.MiyaguchiPreneel +-- License : BSD-style +-- Maintainer : Kei Hibino +-- Stability : experimental +-- Portability : unknown +-- +-- provide the hash function construction method from block cipher +-- +-- +module Crypto.ConstructHash.MiyaguchiPreneel ( mp, cipherInit' ) where + +import Data.List (foldl') + +import Crypto.Cipher.Types +import Crypto.Error (eitherCryptoError) +import Crypto.Internal.ByteArray (ByteArrayAccess, ByteArray) +import qualified Crypto.Internal.ByteArray as B + + +-- | Compute Miyaguchi-Preneel one way compress using the supplied block cipher. +-- Simple usage /mp (cipherInit' :: ByteString -> AES128) msg/ +mp :: (ByteArrayAccess bin, ByteArray bout, ByteArray ba, BlockCipher cipher) + => (ba -> cipher) -- ^ key build function to compute Miyaguchi-Preneel + -> bin -- ^ input message + -> bout -- ^ output tag +mp g = B.convert . foldl' (step g) (B.replicate bsz 0) . chunks . B.convert + where + bsz = blockSize ( g B.empty {- dummy to get block size -} ) + chunks msg + | B.null tl = [hd] + | otherwise = hd : chunks tl + where + (hd, tl) = B.splitAt bsz msg + +-- | Simple key build function, which may raise size error. +cipherInit' :: (ByteArray ba, Cipher k) => ba -> k +cipherInit' = either (error . show) id . eitherCryptoError . cipherInit + +-- | computation step of Miyaguchi-Preneel +step :: (ByteArray ba, BlockCipher k) + => (ba -> k) + -> ba + -> ba + -> ba +step g iv msg = + ecbEncrypt k pmsg `bxor` iv `bxor` pmsg + where + k = g iv + pmsg = pad0 k msg + +pad0 :: (ByteArray ba, BlockCipher k) => k -> ba -> ba +pad0 k s = s `B.append` B.replicate (blockSize k - B.length s) 0 + +bxor :: ByteArray ba => ba -> ba -> ba +bxor = B.xor diff --git a/cryptonite.cabal b/cryptonite.cabal index d3da4ed..4359503 100644 --- a/cryptonite.cabal +++ b/cryptonite.cabal @@ -97,6 +97,7 @@ Library Crypto.Cipher.Salsa Crypto.Cipher.TripleDES Crypto.Cipher.Types + Crypto.ConstructHash.MiyaguchiPreneel Crypto.Data.AFIS Crypto.Data.Padding Crypto.Error From a3255c7ab5d336b278e3c24735c1a2e833509934 Mon Sep 17 00:00:00 2001 From: Kei Hibino Date: Mon, 4 Apr 2016 09:37:34 +0900 Subject: [PATCH 02/14] Add test suite of MiyaguchiPreneel. --- cryptonite.cabal | 1 + tests/KAT_MiyaguchiPreneel.hs | 56 +++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 tests/KAT_MiyaguchiPreneel.hs diff --git a/cryptonite.cabal b/cryptonite.cabal index 4359503..d1dee18 100644 --- a/cryptonite.cabal +++ b/cryptonite.cabal @@ -307,6 +307,7 @@ Test-Suite test-cryptonite KAT_Ed25519 KAT_CMAC KAT_HMAC + KAT_MiyaguchiPreneel KAT_PBKDF2 KAT_PubKey.DSA KAT_PubKey.ECC diff --git a/tests/KAT_MiyaguchiPreneel.hs b/tests/KAT_MiyaguchiPreneel.hs new file mode 100644 index 0000000..5f552b2 --- /dev/null +++ b/tests/KAT_MiyaguchiPreneel.hs @@ -0,0 +1,56 @@ + +module KAT_MiyaguchiPreneel (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 Crypto.ConstructHash.MiyaguchiPreneel + +import Imports + +import Data.Char (digitToInt) +import qualified Data.ByteString as BS + + +runMP128 :: ByteString -> ByteString +runMP128 = mp (cipherInit' :: ByteString -> AES128) + +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' [] = [] + +gAES128 :: TestTree +gAES128 = + igroup "aes128" + [ runMP128 BS.empty + @?= hxs "66e94bd4 ef8a2c3b 884cfa59 ca342b2e" + , runMP128 (hxs "01000000 00000000 00000000 00000000") + @?= hxs "46711816 e91d6ff0 59bbbf2b f58e0fd3" + , runMP128 (hxs "00000000 00000000 00000000 00000001") + @?= hxs "58e2fcce fa7e3061 367f1d57 a4e7455b" + , runMP128 (hxs $ + "00000000 00000000 00000000 00000000" ++ + "01") + @?= hxs "a5ff35ae 097adf5d 646abf5e bf4c16f4" + ] + +igroup :: TestName -> [Assertion] -> TestTree +igroup nm = testGroup nm . zipWith (flip ($)) [1..] . map icase + where + icase c i = testCase (show (i :: Int)) c + +vectors :: TestTree +vectors = + testGroup "KATs" + [ gAES128 ] + +tests :: TestTree +tests = + testGroup "MiyaguchiPreneel" + [ vectors ] From 285d9fb433668fb53af993179fc0178a76d54d79 Mon Sep 17 00:00:00 2001 From: Kei Hibino Date: Thu, 7 Apr 2016 14:43:44 +0900 Subject: [PATCH 03/14] Specify each chunk type. --- Crypto/ConstructHash/MiyaguchiPreneel.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Crypto/ConstructHash/MiyaguchiPreneel.hs b/Crypto/ConstructHash/MiyaguchiPreneel.hs index 585b4f9..a49a33b 100644 --- a/Crypto/ConstructHash/MiyaguchiPreneel.hs +++ b/Crypto/ConstructHash/MiyaguchiPreneel.hs @@ -14,7 +14,7 @@ import Data.List (foldl') import Crypto.Cipher.Types import Crypto.Error (eitherCryptoError) -import Crypto.Internal.ByteArray (ByteArrayAccess, ByteArray) +import Crypto.Internal.ByteArray (ByteArrayAccess, ByteArray, Bytes) import qualified Crypto.Internal.ByteArray as B @@ -24,11 +24,11 @@ mp :: (ByteArrayAccess bin, ByteArray bout, ByteArray ba, BlockCipher cipher) => (ba -> cipher) -- ^ key build function to compute Miyaguchi-Preneel -> bin -- ^ input message -> bout -- ^ output tag -mp g = B.convert . foldl' (step g) (B.replicate bsz 0) . chunks . B.convert +mp g = B.convert . foldl' (step $ g . B.convert) (B.replicate bsz 0) . chunks . B.convert where bsz = blockSize ( g B.empty {- dummy to get block size -} ) chunks msg - | B.null tl = [hd] + | B.null tl = [hd :: Bytes] | otherwise = hd : chunks tl where (hd, tl) = B.splitAt bsz msg From f99827c05d0152b4f415d31b01aec7af6ae20309 Mon Sep 17 00:00:00 2001 From: Kei Hibino Date: Thu, 7 Apr 2016 15:33:00 +0900 Subject: [PATCH 04/14] Drop unused imports. --- tests/KAT_MiyaguchiPreneel.hs | 6 +----- tests/Tests.hs | 4 ++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/KAT_MiyaguchiPreneel.hs b/tests/KAT_MiyaguchiPreneel.hs index 5f552b2..f117e2f 100644 --- a/tests/KAT_MiyaguchiPreneel.hs +++ b/tests/KAT_MiyaguchiPreneel.hs @@ -1,11 +1,7 @@ module KAT_MiyaguchiPreneel (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 Crypto.Cipher.AES (AES128) import Crypto.ConstructHash.MiyaguchiPreneel import Imports diff --git a/tests/Tests.hs b/tests/Tests.hs index 777cef3..9d2c017 100644 --- a/tests/Tests.hs +++ b/tests/Tests.hs @@ -10,6 +10,7 @@ import qualified Poly1305 import qualified Salsa import qualified ChaCha import qualified ChaChaPoly1305 +import qualified KAT_MiyaguchiPreneel import qualified KAT_CMAC import qualified KAT_HMAC import qualified KAT_HKDF @@ -34,6 +35,9 @@ tests = testGroup "cryptonite" [ Number.tests , Hash.tests , Padding.tests + , testGroup "ConstructHash" + [ KAT_MiyaguchiPreneel.tests + ] , testGroup "MAC" [ Poly1305.tests , KAT_CMAC.tests From 3af88f3145edc987f2ca37a1334eab5050835019 Mon Sep 17 00:00:00 2001 From: Kei Hibino Date: Fri, 8 Apr 2016 16:11:17 +0900 Subject: [PATCH 05/14] Add smart constructor of MiyaguchiPreneel hash type. --- Crypto/ConstructHash/MiyaguchiPreneel.hs | 24 ++++++++++++++++++------ tests/KAT_MiyaguchiPreneel.hs | 3 ++- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/Crypto/ConstructHash/MiyaguchiPreneel.hs b/Crypto/ConstructHash/MiyaguchiPreneel.hs index a49a33b..e7f14b8 100644 --- a/Crypto/ConstructHash/MiyaguchiPreneel.hs +++ b/Crypto/ConstructHash/MiyaguchiPreneel.hs @@ -8,7 +8,12 @@ -- provide the hash function construction method from block cipher -- -- -module Crypto.ConstructHash.MiyaguchiPreneel ( mp, cipherInit' ) where +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +module Crypto.ConstructHash.MiyaguchiPreneel + ( mp + , MiyaguchiPreneel(..) + , cipherInit' + ) where import Data.List (foldl') @@ -18,13 +23,20 @@ import Crypto.Internal.ByteArray (ByteArrayAccess, ByteArray, Bytes) import qualified Crypto.Internal.ByteArray as B +newtype MiyaguchiPreneel a = MP { chashGetBytes :: Bytes } + deriving ByteArrayAccess + +instance Eq (MiyaguchiPreneel a) where + MP b1 == MP b2 = B.constEq b1 b2 + + -- | Compute Miyaguchi-Preneel one way compress using the supplied block cipher. -- Simple usage /mp (cipherInit' :: ByteString -> AES128) msg/ -mp :: (ByteArrayAccess bin, ByteArray bout, ByteArray ba, BlockCipher cipher) - => (ba -> cipher) -- ^ key build function to compute Miyaguchi-Preneel - -> bin -- ^ input message - -> bout -- ^ output tag -mp g = B.convert . foldl' (step $ g . B.convert) (B.replicate bsz 0) . chunks . B.convert +mp :: (ByteArrayAccess bin, ByteArray ba, BlockCipher cipher) + => (ba -> cipher) -- ^ key build function to compute Miyaguchi-Preneel + -> bin -- ^ input message + -> MiyaguchiPreneel cipher -- ^ output tag +mp g = MP . foldl' (step $ g . B.convert) (B.replicate bsz 0) . chunks . B.convert where bsz = blockSize ( g B.empty {- dummy to get block size -} ) chunks msg diff --git a/tests/KAT_MiyaguchiPreneel.hs b/tests/KAT_MiyaguchiPreneel.hs index f117e2f..24bfd35 100644 --- a/tests/KAT_MiyaguchiPreneel.hs +++ b/tests/KAT_MiyaguchiPreneel.hs @@ -8,10 +8,11 @@ import Imports import Data.Char (digitToInt) import qualified Data.ByteString as BS +import qualified Data.ByteArray as B runMP128 :: ByteString -> ByteString -runMP128 = mp (cipherInit' :: ByteString -> AES128) +runMP128 s = B.convert $ mp (cipherInit' :: ByteString -> AES128) s hxs :: String -> ByteString hxs = BS.pack . rec' where From 5d96c804aeda06819dc34af183cb7551bb8821ae Mon Sep 17 00:00:00 2001 From: Kei Hibino Date: Fri, 8 Apr 2016 16:43:55 +0900 Subject: [PATCH 06/14] Add infered cipher version. --- Crypto/ConstructHash/MiyaguchiPreneel.hs | 22 +++++++++++++++------- tests/KAT_MiyaguchiPreneel.hs | 2 +- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Crypto/ConstructHash/MiyaguchiPreneel.hs b/Crypto/ConstructHash/MiyaguchiPreneel.hs index e7f14b8..0ca83fc 100644 --- a/Crypto/ConstructHash/MiyaguchiPreneel.hs +++ b/Crypto/ConstructHash/MiyaguchiPreneel.hs @@ -10,7 +10,7 @@ -- {-# LANGUAGE GeneralizedNewtypeDeriving #-} module Crypto.ConstructHash.MiyaguchiPreneel - ( mp + ( mp, mp' , MiyaguchiPreneel(..) , cipherInit' ) where @@ -31,12 +31,11 @@ instance Eq (MiyaguchiPreneel a) where -- | Compute Miyaguchi-Preneel one way compress using the supplied block cipher. --- Simple usage /mp (cipherInit' :: ByteString -> AES128) msg/ -mp :: (ByteArrayAccess bin, ByteArray ba, BlockCipher cipher) - => (ba -> cipher) -- ^ key build function to compute Miyaguchi-Preneel - -> bin -- ^ input message - -> MiyaguchiPreneel cipher -- ^ output tag -mp g = MP . foldl' (step $ g . B.convert) (B.replicate bsz 0) . chunks . B.convert +mp' :: (ByteArrayAccess bin, BlockCipher cipher) + => (Bytes -> cipher) -- ^ key build function to compute Miyaguchi-Preneel. care about block-size and key-size + -> bin -- ^ input message + -> MiyaguchiPreneel cipher -- ^ output tag +mp' g = MP . foldl' (step $ g) (B.replicate bsz 0) . chunks . B.convert where bsz = blockSize ( g B.empty {- dummy to get block size -} ) chunks msg @@ -49,6 +48,15 @@ mp g = MP . foldl' (step $ g . B.convert) (B.replicate bsz 0) . chunks . B.conve cipherInit' :: (ByteArray ba, Cipher k) => ba -> k cipherInit' = either (error . show) id . eitherCryptoError . cipherInit +-- | Compute Miyaguchi-Preneel one way compress using the infered block cipher. +-- Only safe when KEY-SIZE equals to BLOCK-SIZE. +-- +-- Simple usage /mp' msg :: MiyaguchiPreneel AES128/ +mp :: (ByteArrayAccess bin, BlockCipher cipher) + => bin -- ^ input message + -> MiyaguchiPreneel cipher -- ^ output tag +mp = mp' cipherInit' + -- | computation step of Miyaguchi-Preneel step :: (ByteArray ba, BlockCipher k) => (ba -> k) diff --git a/tests/KAT_MiyaguchiPreneel.hs b/tests/KAT_MiyaguchiPreneel.hs index 24bfd35..70fc389 100644 --- a/tests/KAT_MiyaguchiPreneel.hs +++ b/tests/KAT_MiyaguchiPreneel.hs @@ -12,7 +12,7 @@ import qualified Data.ByteArray as B runMP128 :: ByteString -> ByteString -runMP128 s = B.convert $ mp (cipherInit' :: ByteString -> AES128) s +runMP128 s = B.convert (mp s :: MiyaguchiPreneel AES128) hxs :: String -> ByteString hxs = BS.pack . rec' where From 0f241e31dbf62edbe64d15a1c16de71f23c557f0 Mon Sep 17 00:00:00 2001 From: Kei Hibino Date: Tue, 12 Apr 2016 11:00:01 +0900 Subject: [PATCH 07/14] [MP] drop the accessor in favor of just using the ByteArrayAccess constraint --- Crypto/ConstructHash/MiyaguchiPreneel.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Crypto/ConstructHash/MiyaguchiPreneel.hs b/Crypto/ConstructHash/MiyaguchiPreneel.hs index 0ca83fc..803d954 100644 --- a/Crypto/ConstructHash/MiyaguchiPreneel.hs +++ b/Crypto/ConstructHash/MiyaguchiPreneel.hs @@ -23,8 +23,8 @@ import Crypto.Internal.ByteArray (ByteArrayAccess, ByteArray, Bytes) import qualified Crypto.Internal.ByteArray as B -newtype MiyaguchiPreneel a = MP { chashGetBytes :: Bytes } - deriving ByteArrayAccess +newtype MiyaguchiPreneel a = MP Bytes + deriving (ByteArrayAccess) instance Eq (MiyaguchiPreneel a) where MP b1 == MP b2 = B.constEq b1 b2 From fce698b8218b5ca3e2aeb25ec669cac8dbbed0a2 Mon Sep 17 00:00:00 2001 From: Kei Hibino Date: Tue, 12 Apr 2016 14:53:16 +0900 Subject: [PATCH 08/14] [MP] Drop data constructor access. --- Crypto/ConstructHash/MiyaguchiPreneel.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Crypto/ConstructHash/MiyaguchiPreneel.hs b/Crypto/ConstructHash/MiyaguchiPreneel.hs index 803d954..b4a126a 100644 --- a/Crypto/ConstructHash/MiyaguchiPreneel.hs +++ b/Crypto/ConstructHash/MiyaguchiPreneel.hs @@ -11,7 +11,7 @@ {-# LANGUAGE GeneralizedNewtypeDeriving #-} module Crypto.ConstructHash.MiyaguchiPreneel ( mp, mp' - , MiyaguchiPreneel(..) + , MiyaguchiPreneel , cipherInit' ) where From f9c1aa713fc82895e368f9686f53983854fee02f Mon Sep 17 00:00:00 2001 From: Kei Hibino Date: Thu, 2 Jun 2016 17:05:17 +0900 Subject: [PATCH 09/14] drop cipherInit'. --- Crypto/ConstructHash/MiyaguchiPreneel.hs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Crypto/ConstructHash/MiyaguchiPreneel.hs b/Crypto/ConstructHash/MiyaguchiPreneel.hs index b4a126a..1e7a051 100644 --- a/Crypto/ConstructHash/MiyaguchiPreneel.hs +++ b/Crypto/ConstructHash/MiyaguchiPreneel.hs @@ -12,13 +12,12 @@ module Crypto.ConstructHash.MiyaguchiPreneel ( mp, mp' , MiyaguchiPreneel - , cipherInit' ) where import Data.List (foldl') import Crypto.Cipher.Types -import Crypto.Error (eitherCryptoError) +import Crypto.Error (throwCryptoError) import Crypto.Internal.ByteArray (ByteArrayAccess, ByteArray, Bytes) import qualified Crypto.Internal.ByteArray as B @@ -44,10 +43,6 @@ mp' g = MP . foldl' (step $ g) (B.replicate bsz 0) . chunks . B.convert where (hd, tl) = B.splitAt bsz msg --- | Simple key build function, which may raise size error. -cipherInit' :: (ByteArray ba, Cipher k) => ba -> k -cipherInit' = either (error . show) id . eitherCryptoError . cipherInit - -- | Compute Miyaguchi-Preneel one way compress using the infered block cipher. -- Only safe when KEY-SIZE equals to BLOCK-SIZE. -- @@ -55,7 +50,7 @@ cipherInit' = either (error . show) id . eitherCryptoError . cipherInit mp :: (ByteArrayAccess bin, BlockCipher cipher) => bin -- ^ input message -> MiyaguchiPreneel cipher -- ^ output tag -mp = mp' cipherInit' +mp = mp' $ throwCryptoError . cipherInit -- | computation step of Miyaguchi-Preneel step :: (ByteArray ba, BlockCipher k) From 5e76b8af5fa7f87c839e6600fb7ee066193e97c6 Mon Sep 17 00:00:00 2001 From: Kei Hibino Date: Wed, 8 Jun 2016 01:05:08 +0900 Subject: [PATCH 10/14] apply convertFromBase. --- tests/KAT_MiyaguchiPreneel.hs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/tests/KAT_MiyaguchiPreneel.hs b/tests/KAT_MiyaguchiPreneel.hs index 70fc389..8634b32 100644 --- a/tests/KAT_MiyaguchiPreneel.hs +++ b/tests/KAT_MiyaguchiPreneel.hs @@ -7,25 +7,22 @@ import Crypto.ConstructHash.MiyaguchiPreneel import Imports import Data.Char (digitToInt) -import qualified Data.ByteString as BS +import qualified Data.ByteString.Char8 as B8 import qualified Data.ByteArray as B +import Data.ByteArray.Encoding (Base (Base16), convertFromBase) runMP128 :: ByteString -> ByteString runMP128 s = B.convert (mp s :: MiyaguchiPreneel AES128) 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' [] = [] +hxs = either (error . ("hxs:" ++)) id . convertFromBase Base16 + . B8.pack . filter (/= ' ') gAES128 :: TestTree gAES128 = igroup "aes128" - [ runMP128 BS.empty + [ runMP128 B8.empty @?= hxs "66e94bd4 ef8a2c3b 884cfa59 ca342b2e" , runMP128 (hxs "01000000 00000000 00000000 00000000") @?= hxs "46711816 e91d6ff0 59bbbf2b f58e0fd3" From 87867b49bc8780b6c3b00540d19b0c15fa8806ca Mon Sep 17 00:00:00 2001 From: Kei Hibino Date: Wed, 8 Jun 2016 01:13:23 +0900 Subject: [PATCH 11/14] rename definitions which compute miyaguchi-preneel hash. --- Crypto/ConstructHash/MiyaguchiPreneel.hs | 20 ++++++++++---------- tests/KAT_MiyaguchiPreneel.hs | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Crypto/ConstructHash/MiyaguchiPreneel.hs b/Crypto/ConstructHash/MiyaguchiPreneel.hs index 1e7a051..795e989 100644 --- a/Crypto/ConstructHash/MiyaguchiPreneel.hs +++ b/Crypto/ConstructHash/MiyaguchiPreneel.hs @@ -10,7 +10,7 @@ -- {-# LANGUAGE GeneralizedNewtypeDeriving #-} module Crypto.ConstructHash.MiyaguchiPreneel - ( mp, mp' + ( compute, compute' , MiyaguchiPreneel ) where @@ -30,11 +30,11 @@ instance Eq (MiyaguchiPreneel a) where -- | Compute Miyaguchi-Preneel one way compress using the supplied block cipher. -mp' :: (ByteArrayAccess bin, BlockCipher cipher) - => (Bytes -> cipher) -- ^ key build function to compute Miyaguchi-Preneel. care about block-size and key-size - -> bin -- ^ input message - -> MiyaguchiPreneel cipher -- ^ output tag -mp' g = MP . foldl' (step $ g) (B.replicate bsz 0) . chunks . B.convert +compute' :: (ByteArrayAccess bin, BlockCipher cipher) + => (Bytes -> cipher) -- ^ key build function to compute Miyaguchi-Preneel. care about block-size and key-size + -> bin -- ^ input message + -> MiyaguchiPreneel cipher -- ^ output tag +compute' g = MP . foldl' (step $ g) (B.replicate bsz 0) . chunks . B.convert where bsz = blockSize ( g B.empty {- dummy to get block size -} ) chunks msg @@ -47,10 +47,10 @@ mp' g = MP . foldl' (step $ g) (B.replicate bsz 0) . chunks . B.convert -- Only safe when KEY-SIZE equals to BLOCK-SIZE. -- -- Simple usage /mp' msg :: MiyaguchiPreneel AES128/ -mp :: (ByteArrayAccess bin, BlockCipher cipher) - => bin -- ^ input message - -> MiyaguchiPreneel cipher -- ^ output tag -mp = mp' $ throwCryptoError . cipherInit +compute :: (ByteArrayAccess bin, BlockCipher cipher) + => bin -- ^ input message + -> MiyaguchiPreneel cipher -- ^ output tag +compute = compute' $ throwCryptoError . cipherInit -- | computation step of Miyaguchi-Preneel step :: (ByteArray ba, BlockCipher k) diff --git a/tests/KAT_MiyaguchiPreneel.hs b/tests/KAT_MiyaguchiPreneel.hs index 8634b32..163e434 100644 --- a/tests/KAT_MiyaguchiPreneel.hs +++ b/tests/KAT_MiyaguchiPreneel.hs @@ -2,7 +2,7 @@ module KAT_MiyaguchiPreneel (tests) where import Crypto.Cipher.AES (AES128) -import Crypto.ConstructHash.MiyaguchiPreneel +import Crypto.ConstructHash.MiyaguchiPreneel as MiyaguchiPreneel import Imports @@ -13,7 +13,7 @@ import Data.ByteArray.Encoding (Base (Base16), convertFromBase) runMP128 :: ByteString -> ByteString -runMP128 s = B.convert (mp s :: MiyaguchiPreneel AES128) +runMP128 s = B.convert (MiyaguchiPreneel.compute s :: MiyaguchiPreneel AES128) hxs :: String -> ByteString hxs = either (error . ("hxs:" ++)) id . convertFromBase Base16 From c2285db4e3dd38e1f9d7318f99ef90ab0e4473b0 Mon Sep 17 00:00:00 2001 From: Kei Hibino Date: Wed, 8 Jun 2016 22:23:41 +0900 Subject: [PATCH 12/14] add zero padding and its test. --- Crypto/Data/Padding.hs | 11 +++++++++++ tests/Padding.hs | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/Crypto/Data/Padding.hs b/Crypto/Data/Padding.hs index 095a2de..8bea760 100644 --- a/Crypto/Data/Padding.hs +++ b/Crypto/Data/Padding.hs @@ -21,6 +21,7 @@ import qualified Data.ByteArray as B data Format = PKCS5 -- ^ PKCS5: PKCS7 with hardcoded size of 8 | PKCS7 Int -- ^ PKCS7 with padding size between 1 and 255 + | ZERO Int -- ^ zero padding with block size deriving (Show, Eq) -- | Apply some pad to a bytearray @@ -30,6 +31,15 @@ pad (PKCS7 sz) bin = bin `B.append` paddingString where paddingString = B.replicate paddingByte (fromIntegral paddingByte) paddingByte = sz - (B.length bin `mod` sz) +pad (ZERO sz) bin = bin `B.append` paddingString + where + paddingString = B.replicate paddingSz 0 + paddingSz + | len == 0 = sz + | m == 0 = 0 + | otherwise = sz - m + m = len `mod` sz + len = B.length bin -- | Try to remove some padding from a bytearray. unpad :: ByteArray byteArray => Format -> byteArray -> Maybe byteArray @@ -46,3 +56,4 @@ unpad (PKCS7 sz) bin paddingSz = fromIntegral paddingByte (content, padding) = B.splitAt (len - paddingSz) bin paddingWitness = B.replicate paddingSz paddingByte :: Bytes +unpad (ZERO sz) bin = Nothing diff --git a/tests/Padding.hs b/tests/Padding.hs index 7a6e7fd..a3af7cb 100644 --- a/tests/Padding.hs +++ b/tests/Padding.hs @@ -13,6 +13,12 @@ cases = , ("xyze", 5, "xyze\x01") ] +zeroCases = + [ ("", 4, "\NUL\NUL\NUL\NUL") + , ("abcdef", 8, "abcdef\NUL\NUL") + , ("0123456789abcdef", 16, "0123456789abcdef") + ] + --instance Arbitrary where testPad :: Int -> (B.ByteString, Int, B.ByteString) -> TestTree @@ -21,6 +27,11 @@ testPad n (inp, sz, padded) = , eqTest "unpadded" (Just inp) (unpad (PKCS7 sz) padded) ] +testZeroPad :: Int -> (B.ByteString, Int, B.ByteString) -> TestTree +testZeroPad n (inp, sz, padded) = + testCase (show n) $ propertyHoldCase [ eqTest "padded" padded (pad (ZERO sz) inp) ] + tests = testGroup "Padding" [ testGroup "Cases" $ map (uncurry testPad) (zip [1..] cases) + , testGroup "ZeroCases" $ map (uncurry testZeroPad) (zip [1..] zeroCases) ] From ec7e73401f9edfdd47a680023498e03f91dabc31 Mon Sep 17 00:00:00 2001 From: Kei Hibino Date: Wed, 8 Jun 2016 22:26:14 +0900 Subject: [PATCH 13/14] apply zero-padding to miyaguchi-preneel. --- Crypto/ConstructHash/MiyaguchiPreneel.hs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/Crypto/ConstructHash/MiyaguchiPreneel.hs b/Crypto/ConstructHash/MiyaguchiPreneel.hs index 795e989..fe3df1c 100644 --- a/Crypto/ConstructHash/MiyaguchiPreneel.hs +++ b/Crypto/ConstructHash/MiyaguchiPreneel.hs @@ -16,6 +16,7 @@ module Crypto.ConstructHash.MiyaguchiPreneel import Data.List (foldl') +import Crypto.Data.Padding (pad, Format (ZERO)) import Crypto.Cipher.Types import Crypto.Error (throwCryptoError) import Crypto.Internal.ByteArray (ByteArrayAccess, ByteArray, Bytes) @@ -34,12 +35,12 @@ compute' :: (ByteArrayAccess bin, BlockCipher cipher) => (Bytes -> cipher) -- ^ key build function to compute Miyaguchi-Preneel. care about block-size and key-size -> bin -- ^ input message -> MiyaguchiPreneel cipher -- ^ output tag -compute' g = MP . foldl' (step $ g) (B.replicate bsz 0) . chunks . B.convert +compute' g = MP . foldl' (step $ g) (B.replicate bsz 0) . chunks . pad (ZERO bsz) . B.convert where bsz = blockSize ( g B.empty {- dummy to get block size -} ) chunks msg - | B.null tl = [hd :: Bytes] - | otherwise = hd : chunks tl + | B.null msg = [] + | otherwise = (hd :: Bytes) : chunks tl where (hd, tl) = B.splitAt bsz msg @@ -59,13 +60,9 @@ step :: (ByteArray ba, BlockCipher k) -> ba -> ba step g iv msg = - ecbEncrypt k pmsg `bxor` iv `bxor` pmsg + ecbEncrypt k msg `bxor` iv `bxor` msg where k = g iv - pmsg = pad0 k msg - -pad0 :: (ByteArray ba, BlockCipher k) => k -> ba -> ba -pad0 k s = s `B.append` B.replicate (blockSize k - B.length s) 0 bxor :: ByteArray ba => ba -> ba -> ba bxor = B.xor From 7989dc71b0ffc0c610e120ca611d9f165a08cde5 Mon Sep 17 00:00:00 2001 From: Kei Hibino Date: Wed, 8 Jun 2016 22:57:35 +0900 Subject: [PATCH 14/14] fix unpad of zero-padding and add tests. --- Crypto/Data/Padding.hs | 8 +++++++- tests/Padding.hs | 14 ++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/Crypto/Data/Padding.hs b/Crypto/Data/Padding.hs index 8bea760..66ed160 100644 --- a/Crypto/Data/Padding.hs +++ b/Crypto/Data/Padding.hs @@ -56,4 +56,10 @@ unpad (PKCS7 sz) bin paddingSz = fromIntegral paddingByte (content, padding) = B.splitAt (len - paddingSz) bin paddingWitness = B.replicate paddingSz paddingByte :: Bytes -unpad (ZERO sz) bin = Nothing +unpad (ZERO sz) bin + | len == 0 = Nothing + | (len `mod` sz) /= 0 = Nothing + | B.index bin (len - 1) /= 0 = Just bin + | otherwise = Nothing + where + len = B.length bin diff --git a/tests/Padding.hs b/tests/Padding.hs index a3af7cb..f7be773 100644 --- a/tests/Padding.hs +++ b/tests/Padding.hs @@ -14,9 +14,9 @@ cases = ] zeroCases = - [ ("", 4, "\NUL\NUL\NUL\NUL") - , ("abcdef", 8, "abcdef\NUL\NUL") - , ("0123456789abcdef", 16, "0123456789abcdef") + [ ("", 4, "\NUL\NUL\NUL\NUL", Nothing) + , ("abcdef", 8, "abcdef\NUL\NUL", Nothing) + , ("0123456789abcdef", 16, "0123456789abcdef", Just "0123456789abcdef") ] --instance Arbitrary where @@ -27,9 +27,11 @@ testPad n (inp, sz, padded) = , eqTest "unpadded" (Just inp) (unpad (PKCS7 sz) padded) ] -testZeroPad :: Int -> (B.ByteString, Int, B.ByteString) -> TestTree -testZeroPad n (inp, sz, padded) = - testCase (show n) $ propertyHoldCase [ eqTest "padded" padded (pad (ZERO sz) inp) ] +testZeroPad :: Int -> (B.ByteString, Int, B.ByteString, Maybe B.ByteString) -> TestTree +testZeroPad n (inp, sz, padded, unpadded) = + testCase (show n) $ propertyHoldCase [ eqTest "padded" padded (pad (ZERO sz) inp) + , eqTest "unpadded" unpadded (unpad (ZERO sz) padded) + ] tests = testGroup "Padding" [ testGroup "Cases" $ map (uncurry testPad) (zip [1..] cases)