packages feed

cryptocipher 0.2.4 → 0.2.5

raw patch · 3 files changed

+234/−33 lines, 3 filesdep +cerealdep +taggeddep ~crypto-apiPVP ok

version bump matches the API change (PVP)

Dependencies added: cereal, tagged

Dependency ranges changed: crypto-api

API changes (from Hackage documentation)

+ Crypto.Cipher.AES: data AES128
+ Crypto.Cipher.AES: data AES192
+ Crypto.Cipher.AES: data AES256
+ Crypto.Cipher.AES: decryptCBC :: Key -> IV -> ByteString -> ByteString
+ Crypto.Cipher.AES: encryptCBC :: Key -> IV -> ByteString -> ByteString
+ Crypto.Cipher.AES: instance BlockCipher AES128
+ Crypto.Cipher.AES: instance BlockCipher AES192
+ Crypto.Cipher.AES: instance BlockCipher AES256
+ Crypto.Cipher.AES: instance Serialize AES128
+ Crypto.Cipher.AES: instance Serialize AES192
+ Crypto.Cipher.AES: instance Serialize AES256

Files

Crypto/Cipher/AES.hs view
@@ -1,11 +1,26 @@+-- |+-- Module      : Crypto.Cipher.AES+-- License     : BSD-style+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>+-- Stability   : experimental+-- Portability : Good+ module Crypto.Cipher.AES 	( Key+	-- * Basic encryption and decryption 	, encrypt 	, decrypt+	-- * CBC encryption and decryption+	, encryptCBC+	, decryptCBC+	-- * key building mechanism 	, initKey128-	-- * those key sizes are not actually working right now. 	, initKey192 	, initKey256+	-- * Wrappers for "crypto-api" instances+	, AES128+	, AES192+	, AES256 	) where  import Data.Word@@ -17,22 +32,109 @@ import qualified Data.ByteString as B import qualified Data.ByteString.Unsafe as B -newtype Key = Key (Vector Word8)+import Data.Tagged (Tagged(..))+import Crypto.Classes (BlockCipher(..))+import Data.Serialize (Serialize(..), getByteString, putByteString)++newtype AES128 = A128 { unA128 :: Key }+newtype AES192 = A192 { unA192 :: Key }+newtype AES256 = A256 { unA256 :: Key }++instance BlockCipher AES128 where+	blockSize    = Tagged 128+	encryptBlock = encrypt . unA128+	decryptBlock = decrypt . unA128+	buildKey b   = either (const Nothing) (Just . A128) $ initKey128 b+	keyLength    = Tagged 128++instance BlockCipher AES192 where+	blockSize    = Tagged 128+	encryptBlock = encrypt . unA192+	decryptBlock = decrypt . unA192+	buildKey b   = either (const Nothing) (Just . A192) $ initKey192 b+	keyLength    = Tagged 192++instance BlockCipher AES256 where+	blockSize    = Tagged 128+	encryptBlock = encrypt . unA256+	decryptBlock = decrypt . unA256+	buildKey b   = either (const Nothing) (Just . A256) $ initKey256 b+	keyLength    = Tagged 256++serializeKey :: Key -> ByteString+serializeKey (Key v)+	| V.length v == 176 = B.pack $ map (V.unsafeIndex v) [0..15]+	| V.length v == 208 = B.pack $ map (V.unsafeIndex v) [0..23]+	| otherwise         = B.pack $ map (V.unsafeIndex v) [0..31]++instance Serialize AES128 where+	put = putByteString . serializeKey . unA128+	get = do+		raw <- getByteString (128 `div` 8)+		case buildKey raw of+			Nothing -> fail "Invalid raw key material."+			Just k  -> return k++instance Serialize AES192 where+	put = putByteString . serializeKey . unA192+	get = do+		raw <- getByteString (192 `div` 8)+		case buildKey raw of+			Nothing -> fail "Invalid raw key material."+			Just k  -> return k++instance Serialize AES256 where+	put = putByteString . serializeKey . unA256+	get = do+		raw <- getByteString (256 `div` 8)+		case buildKey raw of+			Nothing -> fail "Invalid raw key material."+			Just k  -> return k++data Key = Key (Vector Word8) 	deriving (Show,Eq) +type IV = B.ByteString+ type AESState = Vector Word8 -{- | encrypt with the key a bytestring and returns the encrypted bytestring -}+{- | encrypt using CBC mode+ - IV need to be 16 bytes and the data to encrypt a multiple of 16 bytes -}+encryptCBC :: Key -> IV -> B.ByteString -> B.ByteString+encryptCBC key iv b+	| B.length iv /= 16        = error "invalid IV length"+	| B.length b `mod` 16 /= 0 = error "invalid data length"+	| otherwise                = B.concat $ encryptIter iv (makeChunks b)+		where+			encryptIter _   []     = []+			encryptIter iv' (x:xs) =+				let r = coreEncrypt key $ B.pack $ B.zipWith xor iv' x in+				r : encryptIter r xs++{- | encrypt using simple EBC mode -} encrypt :: Key -> B.ByteString -> B.ByteString encrypt key b 	| B.length b `mod` 16 == 0 = B.concat $ doChunks (coreEncrypt key) b-	| otherwise                = error "wrong length"+	| otherwise                = error "invalid data length" -{- | decrypt with the key a bytestring and returns the encrypted bytestring -}+{- | decrypt using CBC mode+ - IV need to be 16 bytes and the data to decrypt a multiple of 16 bytes -}+decryptCBC :: Key -> IV -> B.ByteString -> B.ByteString+decryptCBC key iv b+	| B.length iv /= 16        = error "invalid IV length"+	| B.length b `mod` 16 /= 0 = error "invalid data length"+	| otherwise                = B.concat $ decryptIter iv (makeChunks b)+		where+			decryptIter _   []     = []+			decryptIter iv' (x:xs) =+				let r = B.pack $ B.zipWith xor iv' $ coreDecrypt key x in+				r : decryptIter x xs++{- | decrypt using simple EBC mode -} decrypt :: Key -> B.ByteString -> B.ByteString decrypt key b 	| B.length b `mod` 16 == 0 = B.concat $ doChunks (coreDecrypt key) b-	| otherwise                = error "wrong length"+	| otherwise                = error "invalid data length"  doChunks :: (B.ByteString -> B.ByteString) -> B.ByteString -> [B.ByteString] doChunks f b =@@ -41,24 +143,33 @@ 		then f x : doChunks f rest 		else [ f x ] +makeChunks :: B.ByteString -> [B.ByteString]+makeChunks = doChunks id+ coreEncrypt :: Key -> ByteString -> ByteString-coreEncrypt key input = swapBlockInv $ aesMain 10 key $ swapBlock input+coreEncrypt key input = swapBlockInv $ aesMain (getNbr key) key $ swapBlock input  coreDecrypt :: Key -> ByteString -> ByteString-coreDecrypt key input = swapBlockInv $ aesMainInv 10 key $ swapBlock input+coreDecrypt key input = swapBlockInv $ aesMainInv (getNbr key) key $ swapBlock input +getNbr :: Key -> Int+getNbr (Key v)+	| V.length v == 176 = 10+	| V.length v == 208 = 12+	| otherwise         = 14+ initKey128 :: ByteString -> Either String Key-initKey128 = initKey 16 10+initKey128 = initKey 16  initKey192 :: ByteString -> Either String Key-initKey192 = initKey 24 12+initKey192 = initKey 24  initKey256 :: ByteString -> Either String Key-initKey256 = initKey 32 14+initKey256 = initKey 32 -initKey :: Int -> Int -> ByteString -> Either String Key-initKey sz nbr b-	| B.length b == sz = Right $ coreExpandKey nbr (V.generate sz $ B.unsafeIndex b)+initKey :: Int -> ByteString -> Either String Key+initKey sz b+	| B.length b == sz = Right $ coreExpandKey (V.generate sz $ B.unsafeIndex b) 	| otherwise        = Left "wrong key size"  aesMain :: Int -> Key -> AESState -> AESState@@ -79,29 +190,83 @@ swapIndex :: Int -> Int swapIndex i = V.unsafeIndex swapIndexes i -coreExpandKey :: Int -> Vector Word8 -> Key-coreExpandKey nbr vkey = Key (V.concat (ek0 : ekN))+coreExpandKey :: Vector Word8 -> Key+coreExpandKey vkey+	| V.length vkey == 16 = Key (V.concat (ek0 : ekN16))+	| V.length vkey == 24 = Key (V.concat (ek0 : ekN24))+	| V.length vkey == 32 = Key (V.concat (ek0 : ekN32))+	| otherwise           = Key (V.empty) 	where 		ek0 = vkey-		ekN = reverse $ snd $ foldl generateFold (ek0, []) [1..nbr]+		ekN16 = reverse $ snd $ foldl (generateFold generate16) (ek0, []) [1..10] -		generateFold (prevk, accK) it = let nk = generate prevk it in (nk, nk : accK)-		generate prevk it =-			let v0 = cR0 it (V.unsafeIndex prevk 12)-			                (V.unsafeIndex prevk 13)-			                (V.unsafeIndex prevk 14)-			                (V.unsafeIndex prevk 15) in-			let (e0,e1,e2,e3) = xorVector prevk 0 v0 in-			let (e4,e5,e6,e7) = xorVector prevk 4 (e0,e1,e2,e3) in-			let (e8,e9,e10,e11) = xorVector prevk 8 (e4,e5,e6,e7) in-			let (e12,e13,e14,e15) = xorVector prevk 12 (e8,e9,e10,e11) in+		ekN24 =+			let (lk, acc) = foldl (generateFold generate24) (ek0, []) [1..7] in+			let nk = generate16 lk 8 in+			reverse (nk : acc)++		ekN32 =+			let (lk, acc) = foldl (generateFold generate32) (ek0, []) [1..6] in+			let nk = generate16 lk 7 in+			reverse (nk : acc)++		generateFold gen (prevk, accK) it = let nk = gen prevk it in (nk, nk : accK)++		generate16 prevk it =+			let len = V.length prevk in+			let v0 = cR0 it (V.unsafeIndex prevk $ len - 4)+			                (V.unsafeIndex prevk $ len - 3)+			                (V.unsafeIndex prevk $ len - 2)+			                (V.unsafeIndex prevk $ len - 1) in+			let eg0@(e0,e1,e2,e3)     = xorVector prevk 0 v0   in+			let eg1@(e4,e5,e6,e7)     = xorVector prevk 4 eg0  in+			let eg2@(e8,e9,e10,e11)   = xorVector prevk 8 eg1  in+			let     (e12,e13,e14,e15) = xorVector prevk 12 eg2 in 			V.fromList [e0,e1,e2,e3,e4,e5,e6,e7,e8,e9,e10,e11,e12,e13,e14,e15] +		generate24 prevk it =+			let len = V.length prevk in+			let v0 = cR0 it (V.unsafeIndex prevk $ len - 4)+			                (V.unsafeIndex prevk $ len - 3)+			                (V.unsafeIndex prevk $ len - 2)+			                (V.unsafeIndex prevk $ len - 1) in+			let eg0@(e0,e1,e2,e3)     = xorVector prevk 0 v0   in+			let eg1@(e4,e5,e6,e7)     = xorVector prevk 4 eg0  in+			let eg2@(e8,e9,e10,e11)   = xorVector prevk 8 eg1  in+			let eg3@(e12,e13,e14,e15) = xorVector prevk 12 eg2 in+			let eg4@(e16,e17,e18,e19) = xorVector prevk 16 eg3 in+			let     (e20,e21,e22,e23) = xorVector prevk 20 eg4 in+			V.fromList [e0,e1,e2,e3,e4,e5,e6,e7,e8,e9,e10,e11,e12,e13,e14,e15,e16,e17,e18,e19,e20,e21,e22,e23]++		generate32 prevk it =+			let len = V.length prevk in+			let v0 = cR0 it (V.unsafeIndex prevk $ len - 4)+			                (V.unsafeIndex prevk $ len - 3)+			                (V.unsafeIndex prevk $ len - 2)+			                (V.unsafeIndex prevk $ len - 1) in+			let eg0@(e0,e1,e2,e3)     = xorVector prevk 0 v0   in+			let eg1@(e4,e5,e6,e7)     = xorVector prevk 4 eg0  in+			let eg2@(e8,e9,e10,e11)   = xorVector prevk 8 eg1  in+			let eg3@(e12,e13,e14,e15) = xorVector prevk 12 eg2 in+			let eg4@(e16,e17,e18,e19) = xorSboxVector prevk 16 eg3 in+			let eg5@(e20,e21,e22,e23) = xorVector prevk 20 eg4 in+			let eg6@(e24,e25,e26,e27) = xorVector prevk 24 eg5 in+			let     (e28,e29,e30,e31) = xorVector prevk 28 eg6 in+			V.fromList [e0,e1,e2,e3,e4,e5,e6,e7,e8,e9,e10,e11,e12,e13,e14,e15,e16+			           ,e17,e18,e19,e20,e21,e22,e23,e24,e25,e26,e27,e28,e29,e30,e31]+ 		xorVector k i (t0,t1,t2,t3) = 			( V.unsafeIndex k (i+0) `xor` t0 			, V.unsafeIndex k (i+1) `xor` t1 			, V.unsafeIndex k (i+2) `xor` t2 			, V.unsafeIndex k (i+3) `xor` t3+			)++		xorSboxVector k i (t0,t1,t2,t3) =+			( V.unsafeIndex k (i+0) `xor` mSbox t0+			, V.unsafeIndex k (i+1) `xor` mSbox t1+			, V.unsafeIndex k (i+2) `xor` mSbox t2+			, V.unsafeIndex k (i+3) `xor` mSbox t3 			)  		cR0 it r0 r1 r2 r3 =
Tests.hs view
@@ -93,8 +93,32 @@ 	  ) 	] +vectors_aes256 =+	[ ( replicate 32 0+	  , B.replicate 16 0+	  , [0xdc,0x95,0xc0,0x78,0xa2,0x40,0x89,0x89,0xad,0x48,0xa2,0x14,0x92,0x84,0x20,0x87]+	  )+	, ( replicate 32 0+	  , B.replicate 16 1+	  , [0x7b,0xc3,0x02,0x6c,0xd7,0x37,0x10,0x3e,0x62,0x90,0x2b,0xcd,0x18,0xfb,0x01,0x63]+	  )+	, ( replicate 32 1+	  , B.replicate 16 2+	  , [0x62,0xae,0x12,0xf3,0x24,0xbf,0xea,0x08,0xd5,0xf6,0x75,0xb5,0x13,0x02,0x6b,0xbf]+	  )+	, ( replicate 32 2+	  , B.replicate 16 1+	  , [0x00,0xf9,0xc7,0x44,0x4b,0xb0,0xcc,0x80,0x6c,0x7c,0x39,0xee,0x22,0x11,0xf1,0x46]+	  )+	, ( replicate 32 3+	  , B.replicate 16 2+	  , [0xb4,0x05,0x87,0x3e,0xa0,0x76,0x1b,0x9c,0xa9,0x9f,0x70,0xb0,0x16,0x16,0xce,0xb1]+	  )+	]+ aes128InitKey = AES.initKey128 . B.pack aes192InitKey = AES.initKey192 . B.pack+aes256InitKey = AES.initKey256 . B.pack  vectors_rc4 = 	[ (wordify "Key", "Plaintext", [ 0xBB,0xF3,0x16,0xE8,0xD9,0x40,0xAF,0x0A,0xD3 ])@@ -135,6 +159,7 @@ 	[ ("RC4",      vectors_rc4,         encryptStream RC4.initCtx RC4.encrypt) 	, ("AES128",   vectors_aes128,      encryptBlock aes128InitKey AES.encrypt) 	, ("AES192",   vectors_aes192,      encryptBlock aes192InitKey AES.encrypt)+	, ("AES256",   vectors_aes256,      encryptBlock aes256InitKey AES.encrypt) 	, ("Camellia", vectors_camellia128, encryptBlock Camellia.initKey Camellia.encrypt) 	] @@ -262,20 +287,28 @@ {-----------------------------------------------------------------------------------------------} {- testing AES -} {-----------------------------------------------------------------------------------------------}-data AES128Message = AES128Message B.ByteString B.ByteString deriving (Show, Eq)+data AES128Message = AES128Message B.ByteString B.ByteString B.ByteString deriving (Show, Eq)  instance Arbitrary AES128Message where 	arbitrary = do 		sz <- choose (1, 12) 		ws <- replicateM (sz*16) (choose (0,255) :: Gen Int) 		key <- replicateM 16 (choose (0,255) :: Gen Int)-		return $ AES128Message (B.pack $ map fromIntegral key) (B.pack $ map fromIntegral ws)+		iv  <- replicateM 16 (choose (0,255) :: Gen Int)+		return $ AES128Message (B.pack $ map fromIntegral key)+		                       (B.pack $ map fromIntegral iv)+		                       (B.pack $ map fromIntegral ws) -prop_aes128_valid (AES128Message key msg) =+prop_aes128_ecb_valid (AES128Message key _ msg) = 	let (Right k) = AES.initKey128 key in 	let emsg = AES.encrypt k msg in 	AES.decrypt k emsg == msg +prop_aes128_cbc_valid (AES128Message key iv msg) =+	let (Right k) = AES.initKey128 key in+	let emsg = AES.encryptCBC k iv msg in+	AES.decryptCBC k iv emsg == msg+ {-----------------------------------------------------------------------------------------------} {- main -} {-----------------------------------------------------------------------------------------------}@@ -304,4 +337,5 @@  	run_test "DSA verify . sign = true" prop_dsa_valid -	run_test "AES128 decrypt.encrypt = id" prop_aes128_valid+	run_test "AES128 (ECB) decrypt.encrypt = id" prop_aes128_ecb_valid+	run_test "AES128 (CBC) decrypt.encrypt = id" prop_aes128_cbc_valid
cryptocipher.cabal view
@@ -1,5 +1,5 @@ Name:                cryptocipher-Version:             0.2.4+Version:             0.2.5 Description:         Symmetrical Block, Stream and PubKey Ciphers License:             BSD3 License-file:        LICENSE@@ -20,7 +20,9 @@   Build-Depends:     base >= 4 && < 5                    , bytestring                    , vector-                   , crypto-api >= 0.2+                   , crypto-api >= 0.5+                   , tagged+                   , cereal   Exposed-modules:   Crypto.Cipher.RC4                      Crypto.Cipher.AES                      Crypto.Cipher.Camellia