packages feed

cipher-aes-0.1.6: Tests/Tests.hs

{-# LANGUAGE ViewPatterns #-}
module Main where

import Control.Applicative
import Control.Monad

import Test.Framework (Test, defaultMain, testGroup)
import Test.Framework.Providers.QuickCheck2 (testProperty)

import Test.QuickCheck
import Test.QuickCheck.Test
import Test.Framework.Providers.QuickCheck2 (testProperty)

import qualified Data.ByteString as B
import qualified Crypto.Cipher.AES as AES

import qualified KATECB
import qualified KATCBC
import qualified KATXTS
import qualified KATGCM

encryptBlock initF encryptF key plaintext =
    B.unpack $ encryptF (initF (B.pack key)) plaintext

katECBTests vectors f = concatMap makeTests vectors
    where makeTests (name, v) = map (\(z,i) -> testProperty (name ++ " " ++ show i) $ makeTest z) $ zip v [0..]
               where makeTest (AES.initKey -> key,plaintext,expected) = assertEq expected $ f key plaintext

katCBCTests vectors f = concatMap makeTests vectors
    where makeTests (name, v) = map (\(z,i) -> testProperty (name ++ " " ++ show i) $ makeTest z) $ zip v [0..]
            where makeTest (AES.initKey -> key,AES.IV -> iv,plaintext,expected) = assertEq expected $ f key iv plaintext

katXTSTests vectors f = concatMap makeTests vectors
    where makeTests (name, v) = map (\(z,i) -> testProperty (name ++ " " ++ show i) $ makeTest z) $ zip v [0..]
              where makeTest (AES.initKey -> key1,AES.initKey -> key2, AES.IV -> iv,plaintext,_,expected) =
                        (assertEq expected $ f (key1,key2) iv 0 plaintext)

katGCMTests vectors f = concatMap makeTests vectors
    where makeTests (name, v) = map (\(z,i) -> testProperty (name ++ " " ++ show i) $ makeTest z) $ zip v [0..]
            where makeTest (AES.initKey -> key, AES.IV -> iv, aad, plaintext, expectedOutput, taglen, expectedTag) =
                        let (output,tag) = f key iv aad plaintext in
                        assertEq expectedOutput output && (assertEq tag expectedTag)


data ECBUnit = ECBUnit B.ByteString B.ByteString
    deriving (Show,Eq)
data CBCUnit = CBCUnit B.ByteString B.ByteString B.ByteString
    deriving (Show,Eq)
data CTRUnit = CTRUnit B.ByteString B.ByteString B.ByteString
    deriving (Show,Eq)
data XTSUnit = XTSUnit B.ByteString B.ByteString B.ByteString B.ByteString
    deriving (Show,Eq)
data GCMUnit = GCMUnit B.ByteString B.ByteString B.ByteString B.ByteString
    deriving (Show,Eq)
data KeyUnit = KeyUnit B.ByteString
    deriving (Show,Eq)

generateKeyOf size = B.pack <$> replicateM size arbitrary
generateKey = elements [16,24,32] >>= generateKeyOf

generateIv = B.pack <$> replicateM 16 arbitrary
generateIvGCM = choose (12,90) >>= \sz -> (B.pack <$> replicateM sz arbitrary)

generatePlaintextMultiple16 = choose (1,128) >>= \size -> replicateM (size*16) arbitrary >>= return . B.pack

generatePlaintext = choose (0,324) >>= \size -> replicateM size arbitrary >>= return . B.pack

instance Arbitrary ECBUnit where
    arbitrary = ECBUnit <$> generateKey
                        <*> generatePlaintextMultiple16

instance Arbitrary CBCUnit where
    arbitrary = CBCUnit <$> generateKey
                        <*> generateIv
                        <*> generatePlaintextMultiple16

instance Arbitrary CTRUnit where
    arbitrary = CTRUnit <$> generateKey
                        <*> generateIv
                        <*> generatePlaintext

instance Arbitrary GCMUnit where
    arbitrary = GCMUnit <$> generateKey
                        <*> generateIvGCM
                        <*> generatePlaintext
                        <*> generatePlaintext

instance Arbitrary XTSUnit where
    arbitrary = do
        size <- elements [16,32]
        XTSUnit <$> generateKeyOf size
                <*> generateKeyOf size
                <*> generateIv
                <*> generatePlaintextMultiple16

instance Arbitrary KeyUnit where
    arbitrary = KeyUnit <$> generateKey

idECBTests (ECBUnit (AES.initKey -> key) plaintext) =
    plaintext `assertEq` AES.decryptECB key (AES.encryptECB key plaintext)

idCBCTests (CBCUnit (AES.initKey -> key) (AES.IV -> iv) plaintext) =
    plaintext `assertEq` AES.decryptCBC key iv (AES.encryptCBC key iv plaintext)

idCTRTests (CTRUnit (AES.initKey -> key) (AES.IV -> iv) plaintext) =
    plaintext `assertEq` AES.decryptCTR key iv (AES.encryptCTR key iv plaintext)

idXTSTests (XTSUnit (AES.initKey -> key1) (AES.initKey -> key2) (AES.IV -> iv) plaintext) =
    plaintext `assertEq` AES.decryptXTS (key1, key2) iv 0 (AES.encryptXTS (key1, key2) iv 0 plaintext)

idGCMTests (GCMUnit (AES.initKey -> key) (AES.IV -> iv) aad plaintext) =
    let (cipherText, tag) = AES.encryptGCM key iv aad plaintext in
    let (plaintext2, tag2) = AES.decryptGCM key iv aad cipherText in
    (plaintext `assertEq` plaintext2) && (tag == tag2)

idKey (KeyUnit keyBs) = keyBs == AES.keyOfCtx (AES.initKey keyBs)

assertEq expected got
	| expected == got = True
	| otherwise       = error ("expected: " ++ showhex expected ++ " got: " ++ showhex got)
    where showhex = concatMap toHex . B.unpack
          toHex b = let (l,r) = b `divMod` 16 in map (toHexChar . fromIntegral) [l,r]
          toHexChar c
                  | c >= 0 && c <= 9   = toEnum (c + fromEnum '0')
                  | c >= 10 && c <= 16 = toEnum (c + fromEnum 'a')
                  | otherwise          = '_'

tests =
    [ testProperty "key-id" idKey
    , testGroup "KAT-ECB-Encrypt" $ katECBTests KATECB.vectors_encrypt AES.encryptECB
    , testGroup "KAT-ECB-Decrypt" $ katECBTests KATECB.vectors_decrypt AES.decryptECB
    , testGroup "KAT-CBC-Encrypt" $ katCBCTests KATCBC.vectors_encrypt AES.encryptCBC
    , testGroup "KAT-CBC-Decrypt" $ katCBCTests KATCBC.vectors_decrypt AES.decryptCBC
    , testGroup "KAT-XTS-Encrypt" $ katXTSTests KATXTS.vectors_encrypt AES.encryptXTS
    , testGroup "KAT-XTS-Decrypt" $ katXTSTests KATXTS.vectors_decrypt AES.decryptXTS
    , testGroup "KAT-GCM-Encrypt" $ katGCMTests KATGCM.vectors_encrypt AES.encryptGCM
    , testGroup "decrypt-encrypt-is-ID"
        [ testProperty "ECB" idECBTests
        , testProperty "CBC" idCBCTests
        , testProperty "CTR" idCTRTests
        , testProperty "XTS" idXTSTests
        , testProperty "GCM" idGCMTests
        ]
    ]

main = defaultMain tests