crypto-cipher-types-0.0.9/0000755000000000000000000000000012232400460013631 5ustar0000000000000000crypto-cipher-types-0.0.9/LICENSE0000644000000000000000000000272212232400460014641 0ustar0000000000000000Copyright (c) 2013 Vincent Hanquez All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the author nor the names of his contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. crypto-cipher-types-0.0.9/README.md0000644000000000000000000000022112232400460015103 0ustar0000000000000000crypto-cipher-types =================== Documentation: [crypto-cipher-types on hackage](http://hackage.haskell.org/package/crypto-cipher-types) crypto-cipher-types-0.0.9/Setup.hs0000644000000000000000000000005612232400460015266 0ustar0000000000000000import Distribution.Simple main = defaultMain crypto-cipher-types-0.0.9/crypto-cipher-types.cabal0000644000000000000000000000253512232400460020554 0ustar0000000000000000Name: crypto-cipher-types Version: 0.0.9 Synopsis: Generic cryptography cipher types Description: Generic cryptography cipher types License: BSD3 License-file: LICENSE Copyright: Vincent Hanquez Author: Vincent Hanquez Maintainer: vincent@snarc.org Category: Cryptography Stability: experimental Build-Type: Simple Homepage: http://github.com/vincenthz/hs-crypto-cipher Cabal-Version: >=1.8 data-files: README.md Library Exposed-modules: Crypto.Cipher.Types , Crypto.Cipher.Types.Unsafe Other-modules: Crypto.Cipher.Types.GF , Crypto.Cipher.Types.Block , Crypto.Cipher.Types.BlockIO , Crypto.Cipher.Types.Stream , Crypto.Cipher.Types.OfIO , Crypto.Cipher.Types.AEAD , Crypto.Cipher.Types.Base , Crypto.Cipher.Types.Utils Build-depends: base >= 4 && < 5 , bytestring , byteable >= 0.1.1 , securemem >= 0.1.1 ghc-options: -Wall -fwarn-tabs source-repository head type: git location: git://github.com/vincenthz/hs-crypto-cipher subdir: types crypto-cipher-types-0.0.9/Crypto/0000755000000000000000000000000012232400460015111 5ustar0000000000000000crypto-cipher-types-0.0.9/Crypto/Cipher/0000755000000000000000000000000012232400460016323 5ustar0000000000000000crypto-cipher-types-0.0.9/Crypto/Cipher/Types.hs0000644000000000000000000000343612232400460017771 0ustar0000000000000000-- | -- Module : Crypto.Cipher.Types -- License : BSD-style -- Maintainer : Vincent Hanquez -- Stability : Stable -- Portability : Excellent -- -- symmetric cipher basic types -- {-# LANGUAGE DeriveDataTypeable #-} module Crypto.Cipher.Types ( -- * Cipher classes Cipher(..) , BlockCipher(..) , StreamCipher(..) , DataUnitOffset , KeySizeSpecifier(..) , KeyError(..) , AEAD(..) , AEADState(..) , AEADMode(..) , AEADModeImpl(..) , cfb8Encrypt , cfb8Decrypt -- * AEAD functions , module Crypto.Cipher.Types.AEAD -- * Key type and constructor , Key , makeKey -- * Initial Vector type and constructor , IV , makeIV , nullIV , ivAdd -- * Authentification Tag , AuthTag(..) ) where import Data.SecureMem import Data.Byteable import Crypto.Cipher.Types.Base import Crypto.Cipher.Types.Block import Crypto.Cipher.Types.Stream import Crypto.Cipher.Types.AEAD -- | Create a Key for a specified cipher makeKey :: (ToSecureMem b, Cipher c) => b -> Either KeyError (Key c) makeKey b = toKey undefined where sm = toSecureMem b smLen = byteableLength sm toKey :: Cipher c => c -> Either KeyError (Key c) toKey cipher = case cipherKeySize cipher of KeySizeRange mi ma | smLen < mi -> Left KeyErrorTooSmall | smLen > ma -> Left KeyErrorTooBig | otherwise -> Right $ Key sm KeySizeEnum l | smLen `elem` l -> Right $ Key sm | otherwise -> Left $ KeyErrorInvalid ("valid size: " ++ show l) KeySizeFixed v | smLen == v -> Right $ Key sm | otherwise -> Left $ KeyErrorInvalid ("valid size: " ++ show v) crypto-cipher-types-0.0.9/Crypto/Cipher/Types/0000755000000000000000000000000012232400460017427 5ustar0000000000000000crypto-cipher-types-0.0.9/Crypto/Cipher/Types/Unsafe.hs0000644000000000000000000000070212232400460021203 0ustar0000000000000000-- | -- Module : Crypto.Cipher.Types.Unsafe -- License : BSD-style -- Maintainer : Vincent Hanquez -- Stability : Stable -- Portability : Excellent -- -- mutable and unsafe interface for Block ciphers. -- export a BlockCipherIO class -- module Crypto.Cipher.Types.Unsafe ( BlockCipherIO(..) , BufferLength , PtrDest , PtrSource , PtrIV , onBlock ) where import Crypto.Cipher.Types.BlockIO crypto-cipher-types-0.0.9/Crypto/Cipher/Types/Base.hs0000644000000000000000000000410612232400460020636 0ustar0000000000000000-- | -- Module : Crypto.Cipher.Types.Base -- License : BSD-style -- Maintainer : Vincent Hanquez -- Stability : Stable -- Portability : Excellent -- -- symmetric cipher basic types -- module Crypto.Cipher.Types.Base ( KeyError(..) , KeySizeSpecifier(..) , Key(..) , IV(..) , Cipher(..) , AuthTag(..) , AEADMode(..) , DataUnitOffset ) where import Data.Byteable import Data.SecureMem import Data.Word import Data.ByteString (ByteString) -- | Possible Error that can be reported when initializating a key data KeyError = KeyErrorTooSmall | KeyErrorTooBig | KeyErrorInvalid String deriving (Show,Eq) -- | Different specifier for key size in bytes data KeySizeSpecifier = KeySizeRange Int Int -- ^ in the range [min,max] | KeySizeEnum [Int] -- ^ one of the specified values | KeySizeFixed Int -- ^ a specific size deriving (Show,Eq) -- | Offset inside an XTS data unit, measured in block size. type DataUnitOffset = Word32 -- | a Key parametrized by the cipher newtype Key c = Key SecureMem deriving (Eq) instance ToSecureMem (Key c) where toSecureMem (Key sm) = sm instance Byteable (Key c) where toBytes (Key sm) = toBytes sm -- | an IV parametrized by the cipher newtype IV c = IV ByteString deriving (Eq) instance Byteable (IV c) where toBytes (IV sm) = sm -- | Authentification Tag for AE cipher mode newtype AuthTag = AuthTag ByteString deriving (Show) instance Eq AuthTag where (AuthTag a) == (AuthTag b) = constEqBytes a b instance Byteable AuthTag where toBytes (AuthTag bs) = bs -- | AEAD Mode data AEADMode = AEAD_OCB | AEAD_CCM | AEAD_EAX | AEAD_CWC | AEAD_GCM deriving (Show,Eq) -- | Symmetric cipher class. class Cipher cipher where -- | Initialize a cipher context from a key cipherInit :: Key cipher -> cipher -- | Cipher name cipherName :: cipher -> String -- | return the size of the key required for this cipher. -- Some cipher accept any size for key cipherKeySize :: cipher -> KeySizeSpecifier crypto-cipher-types-0.0.9/Crypto/Cipher/Types/Stream.hs0000644000000000000000000000104112232400460021212 0ustar0000000000000000-- | -- Module : Crypto.Cipher.Types.Stream -- License : BSD-style -- Maintainer : Vincent Hanquez -- Stability : Stable -- Portability : Excellent -- -- stream cipher basic types -- module Crypto.Cipher.Types.Stream ( StreamCipher(..) ) where import Crypto.Cipher.Types.Base import Data.ByteString (ByteString) -- | Symmetric stream cipher class class Cipher cipher => StreamCipher cipher where -- | Combine using the stream cipher streamCombine :: cipher -> ByteString -> (ByteString, cipher) crypto-cipher-types-0.0.9/Crypto/Cipher/Types/OfIO.hs0000644000000000000000000001504112232400460020560 0ustar0000000000000000-- | -- Module : Crypto.Cipher.Types.Modes -- License : BSD-style -- Maintainer : Vincent Hanquez -- Stability : Stable -- Portability : Excellent -- -- block cipher modes immutable interfaces -- module Crypto.Cipher.Types.OfIO ( -- * ECB ecbEncryptOfIO , ecbDecryptOfIO {- -- * CBC , cbcEncryptOfIO , cbcDecryptOfIO -- * CFB , cfbEncryptOfIO , cfbDecryptOfIO , cfb8EncryptOfIO , cfb8DecryptOfIO -- * CTR , ctrCombineOfIO -- * XTS , xtsEncryptOfIO , xtsDecryptOfIO -} ) where import Data.ByteString (ByteString) import qualified Data.ByteString as B import qualified Data.ByteString.Internal as B import Data.Byteable --import Crypto.Cipher.Types.Base import Crypto.Cipher.Types.Block import Crypto.Cipher.Types.BlockIO --import Foreign.Storable (poke) --import Foreign.Ptr isBlockSized :: (BlockCipher cipher, BlockCipherIO cipher) => cipher -> Int -> Bool isBlockSized cipher bsLen = (bsLen `mod` blockSize cipher) == 0 notBlockSized :: (BlockCipher cipher, BlockCipherIO cipher) => cipher -> a notBlockSized = undefined withDest :: BlockCipherIO cipher => cipher -> ByteString -> (PtrDest -> PtrSource -> BufferLength -> IO ()) -> ByteString withDest cipher bs f | B.null bs = B.empty | not (isBlockSized cipher len) = notBlockSized cipher | otherwise = B.unsafeCreate len $ \dst -> withBytePtr bs $ \src -> f dst src (fromIntegral len) where len = B.length bs {- withDestIV :: BlockCipherIO cipher => cipher -> IV cipher -> ByteString -> (PtrIV -> PtrDest -> PtrSource -> BufferLength -> IO ()) -> ByteString withDestIV cipher (IV iv) bs f | B.null bs = B.empty | not (isBlockSized cipher len) = notBlockSized cipher | otherwise = B.unsafeCreate len $ \dst -> withBytePtr iv $ \ivPtr -> withBytePtr bs $ \src -> f ivPtr dst src (fromIntegral len) where len = B.length bs withDestIVAnySize :: BlockCipherIO cipher => IV cipher -> ByteString -> (PtrIV -> PtrDest -> PtrSource -> BufferLength -> IO ()) -> ByteString withDestIVAnySize (IV iv) bs f | B.null bs = B.empty | otherwise = B.unsafeCreate len $ \dst -> withBytePtr iv $ \ivPtr -> withBytePtr bs $ \src -> f ivPtr dst src (fromIntegral len) where len = B.length bs -} -- | Encrypt using the ECB mode. -- -- input need to be a multiple of the blocksize ecbEncryptOfIO :: BlockCipherIO cipher => cipher -> ByteString -> ByteString ecbEncryptOfIO cipher bs = withDest cipher bs $ ecbEncryptMutable cipher -- | Decrypt using the ECB mode. -- -- input need to be a multiple of the blocksize ecbDecryptOfIO :: BlockCipherIO cipher => cipher -> ByteString -> ByteString ecbDecryptOfIO cipher bs = withDest cipher bs $ ecbEncryptMutable cipher {- -- | encrypt using the CBC mode. -- -- input need to be a multiple of the blocksize cbcEncryptOfIO :: BlockCipherIO cipher => cipher -> IV cipher -> ByteString -> ByteString cbcEncryptOfIO cipher iv bs = withDestIV cipher iv bs $ cbcEncryptMutable cipher -- | decrypt using the CBC mode. -- -- input need to be a multiple of the blocksize cbcDecryptOfIO :: BlockCipherIO cipher => cipher -> IV cipher -> ByteString -> ByteString cbcDecryptOfIO cipher iv bs = withDestIV cipher iv bs $ cbcDecryptMutable cipher -- | encrypt using the CFB mode. -- -- input need to be a multiple of the blocksize cfbEncryptOfIO :: BlockCipherIO cipher => cipher -> IV cipher -> ByteString -> ByteString cfbEncryptOfIO cipher iv bs = withDestIV cipher iv bs $ cfbEncryptMutable cipher -- | decrypt using the CFB mode. -- -- input need to be a multiple of the blocksize cfbDecryptOfIO :: BlockCipherIO cipher => cipher -> IV cipher -> ByteString -> ByteString cfbDecryptOfIO cipher iv bs = withDestIV cipher iv bs $ cfbDecryptMutable cipher -- | combine using the CTR mode. -- -- CTR mode produce a stream of randomized data that is combined -- (by XOR operation) with the input stream. -- -- encryption and decryption are the same operation. -- -- input can be of any size ctrCombineOfIO :: BlockCipherIO cipher => cipher -> IV cipher -> ByteString -> ByteString ctrCombineOfIO cipher iv bs = withDestIVAnySize iv bs $ cfbDecryptMutable cipher -- | encrypt using the XTS mode. -- -- input need to be a multiple of the blocksize xtsEncryptOfIO :: BlockCipherIO cipher => (cipher, cipher) -> IV cipher -> DataUnitOffset -> ByteString -> ByteString xtsEncryptOfIO ciphers@(c1,_) iv ofs bs = withDestIV c1 iv bs $ \ivPtr -> xtsEncryptMutable ciphers ivPtr ofs -- | decrypt using the XTS mode. -- -- input need to be a multiple of the blocksize xtsDecryptOfIO :: BlockCipherIO cipher => (cipher, cipher) -> IV cipher -> DataUnitOffset -> ByteString -> ByteString xtsDecryptOfIO ciphers@(c1,_) iv ofs bs = withDestIV c1 iv bs $ \ivPtr -> xtsDecryptMutable ciphers ivPtr ofs -- | Encrypt using CFB mode in 8 bit output -- -- Effectively turn a Block cipher in CFB mode into a Stream cipher cfb8EncryptOfIO :: BlockCipherIO a => a -> IV a -> B.ByteString -> B.ByteString cfb8EncryptOfIO ctx origIv msg = B.unsafeCreate (B.length msg) $ \dst -> loop dst origIv msg where loop d iv@(IV i) m | B.null m = return () | otherwise = poke d out >> loop (d `plusPtr` 1) ni (B.drop 1 m) where m' = if B.length m < blockSize ctx then m `B.append` B.replicate (blockSize ctx - B.length m) 0 else B.take (blockSize ctx) m r = cfbEncryptOfIO ctx iv m' out = B.head r ni = IV (B.drop 1 i `B.snoc` out) -- | Decrypt using CFB mode in 8 bit output -- -- Effectively turn a Block cipher in CFB mode into a Stream cipher cfb8DecryptOfIO :: BlockCipherIO a => a -> IV a -> B.ByteString -> B.ByteString cfb8DecryptOfIO ctx origIv msg = B.unsafeCreate (B.length msg) $ \dst -> loop dst origIv msg where loop d iv@(IV i) m | B.null m = return () | otherwise = poke d out >> loop (d `plusPtr` 1) ni (B.drop 1 m) where m' = if B.length m < blockSize ctx then m `B.append` B.replicate (blockSize ctx - B.length m) 0 else B.take (blockSize ctx) m r = cfbDecryptOfIO ctx iv m' out = B.head r ni = IV (B.drop 1 i `B.snoc` B.head m') -} crypto-cipher-types-0.0.9/Crypto/Cipher/Types/GF.hs0000644000000000000000000000321012232400460020253 0ustar0000000000000000-- | -- Module : Crypto.Cipher.Types.GF -- License : BSD-style -- Maintainer : Vincent Hanquez -- Stability : Stable -- Portability : Excellent -- -- Slow Galois Field arithmetic for generic XTS and GCM implementation -- module Crypto.Cipher.Types.GF ( -- * XTS support xtsGFMul ) where import Control.Applicative import Data.ByteString (ByteString) import qualified Data.ByteString as B import qualified Data.ByteString.Internal as B import Data.Byteable import Foreign.Storable import Foreign.Ptr import Data.Word import Data.Bits -- block size need to be 128 bits. -- -- FIXME: add support for big endian. xtsGFMul :: ByteString -> ByteString xtsGFMul b | B.length b == 16 = B.unsafeCreate (B.length b) $ \dst -> withBytePtr b $ \src -> do (hi,lo) <- gf <$> peek (castPtr src) <*> peek (castPtr src `plusPtr` 8) poke (castPtr dst) lo poke (castPtr dst `plusPtr` 8) hi | otherwise = error "unsupported block size in GF" where gf :: Word64 -> Word64 -> (Word64, Word64) gf srcLo srcHi = ((if carryLo then (.|. 1) else id) (srcHi `shiftL` 1) ,(if carryHi then xor 0x87 else id) $ (srcLo `shiftL` 1) ) where carryHi = srcHi `testBit` 63 carryLo = srcLo `testBit` 63 {- const uint64_t gf_mask = cpu_to_le64(0x8000000000000000ULL); uint64_t r = ((a->q[1] & gf_mask) ? cpu_to_le64(0x87) : 0); a->q[1] = cpu_to_le64((le64_to_cpu(a->q[1]) << 1) | (a->q[0] & gf_mask ? 1 : 0)); a->q[0] = cpu_to_le64(le64_to_cpu(a->q[0]) << 1) ^ r; -} crypto-cipher-types-0.0.9/Crypto/Cipher/Types/Block.hs0000644000000000000000000002327612232400460021027 0ustar0000000000000000-- | -- Module : Crypto.Cipher.Types.Block -- License : BSD-style -- Maintainer : Vincent Hanquez -- Stability : Stable -- Portability : Excellent -- -- block cipher basic types -- {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE ViewPatterns #-} module Crypto.Cipher.Types.Block ( -- * BlockCipher BlockCipher(..) -- * initialization vector (IV) , IV , makeIV , nullIV , ivAdd -- * XTS , XTS -- * AEAD , AEAD(..) , AEADState(..) , AEADModeImpl(..) -- * CFB 8 bits , cfb8Encrypt , cfb8Decrypt ) where import Data.ByteString (ByteString) import qualified Data.ByteString as B import qualified Data.ByteString.Internal as B (unsafeCreate) import Data.Byteable import Data.Word import Data.Bits (shiftR, Bits) import Crypto.Cipher.Types.Base import Crypto.Cipher.Types.GF import Crypto.Cipher.Types.Utils import Foreign.Ptr import Foreign.Storable type XTS cipher = (cipher, cipher) -> IV cipher -- ^ Usually represent the Data Unit (e.g. disk sector) -> DataUnitOffset -- ^ Offset in the data unit in number of blocks -> ByteString -- ^ Data -> ByteString -- ^ Processed Data -- | Symmetric block cipher class class Cipher cipher => BlockCipher cipher where -- | Return the size of block required for this block cipher blockSize :: cipher -> Int -- | Encrypt blocks -- -- the input string need to be multiple of the block size ecbEncrypt :: cipher -> ByteString -> ByteString -- | Decrypt blocks -- -- the input string need to be multiple of the block size ecbDecrypt :: cipher -> ByteString -> ByteString -- | encrypt using the CBC mode. -- -- input need to be a multiple of the blocksize cbcEncrypt :: cipher -> IV cipher -> ByteString -> ByteString cbcEncrypt = cbcEncryptGeneric -- | decrypt using the CBC mode. -- -- input need to be a multiple of the blocksize cbcDecrypt :: cipher -> IV cipher -> ByteString -> ByteString cbcDecrypt = cbcDecryptGeneric -- | encrypt using the CFB mode. -- -- input need to be a multiple of the blocksize cfbEncrypt :: cipher -> IV cipher -> ByteString -> ByteString cfbEncrypt = cfbEncryptGeneric -- | decrypt using the CFB mode. -- -- input need to be a multiple of the blocksize cfbDecrypt :: cipher -> IV cipher -> ByteString -> ByteString cfbDecrypt = cfbDecryptGeneric -- | combine using the CTR mode. -- -- CTR mode produce a stream of randomized data that is combined -- (by XOR operation) with the input stream. -- -- encryption and decryption are the same operation. -- -- input can be of any size ctrCombine :: cipher -> IV cipher -> ByteString -> ByteString ctrCombine = ctrCombineGeneric -- | encrypt using the XTS mode. -- -- input need to be a multiple of the blocksize, and the cipher -- need to process 128 bits block only xtsEncrypt :: (cipher, cipher) -> IV cipher -- ^ Usually represent the Data Unit (e.g. disk sector) -> DataUnitOffset -- ^ Offset in the data unit in number of blocks -> ByteString -- ^ Plaintext -> ByteString -- ^ Ciphertext xtsEncrypt = xtsEncryptGeneric -- | decrypt using the XTS mode. -- -- input need to be a multiple of the blocksize, and the cipher -- need to process 128 bits block only xtsDecrypt :: (cipher, cipher) -> IV cipher -- ^ Usually represent the Data Unit (e.g. disk sector) -> DataUnitOffset -- ^ Offset in the data unit in number of blocks -> ByteString -- ^ Ciphertext -> ByteString -- ^ Plaintext xtsDecrypt = xtsDecryptGeneric -- | Initialize a new AEAD State -- -- When Nothing is returns, it means the mode is not handled. aeadInit :: Byteable iv => AEADMode -> cipher -> iv -> Maybe (AEAD cipher) aeadInit _ _ _ = Nothing -- | Authenticated Encryption with Associated Data algorithms data AEAD cipher = AEAD cipher (AEADState cipher) -- | Wrapper for any AEADState data AEADState cipher = forall st . AEADModeImpl cipher st => AEADState st -- | Class of AEAD Mode implementation class BlockCipher cipher => AEADModeImpl cipher state where aeadStateAppendHeader :: cipher -> state -> ByteString -> state aeadStateEncrypt :: cipher -> state -> ByteString -> (ByteString, state) aeadStateDecrypt :: cipher -> state -> ByteString -> (ByteString, state) aeadStateFinalize :: cipher -> state -> Int -> AuthTag -- | Create an IV for a specified block cipher makeIV :: (Byteable b, BlockCipher c) => b -> Maybe (IV c) makeIV b = toIV undefined where toIV :: BlockCipher c => c -> Maybe (IV c) toIV cipher | byteableLength b == sz = Just (IV $ toBytes b) | otherwise = Nothing where sz = blockSize cipher -- | Create an IV that is effectively representing the number 0 nullIV :: BlockCipher c => IV c nullIV = toIV undefined where toIV :: BlockCipher c => c -> IV c toIV cipher = IV $ B.replicate (blockSize cipher) 0 -- | Increment an IV by a number. -- -- Assume the IV is in Big Endian format. ivAdd :: BlockCipher c => IV c -> Int -> IV c ivAdd (IV b) i = IV $ snd $ B.mapAccumR addCarry i b where addCarry :: Int -> Word8 -> (Int, Word8) addCarry acc w | acc == 0 = (0, w) | otherwise = let (hi,lo) = acc `divMod` 256 nw = lo + (fromIntegral w) in (hi + (nw `shiftR` 8), fromIntegral nw) cbcEncryptGeneric :: BlockCipher cipher => cipher -> IV cipher -> ByteString -> ByteString cbcEncryptGeneric cipher (IV ivini) input = B.concat $ doEnc ivini $ chunk (blockSize cipher) input where doEnc _ [] = [] doEnc iv (i:is) = let o = ecbEncrypt cipher $ bxor iv i in o : doEnc o is cbcDecryptGeneric :: BlockCipher cipher => cipher -> IV cipher -> ByteString -> ByteString cbcDecryptGeneric cipher (IV ivini) input = B.concat $ doDec ivini $ chunk (blockSize cipher) input where doDec _ [] = [] doDec iv (i:is) = let o = bxor iv $ ecbDecrypt cipher i in o : doDec i is cfbEncryptGeneric :: BlockCipher cipher => cipher -> IV cipher -> ByteString -> ByteString cfbEncryptGeneric cipher (IV ivini) input = B.concat $ doEnc ivini $ chunk (blockSize cipher) input where doEnc _ [] = [] doEnc iv (i:is) = let o = bxor i $ ecbEncrypt cipher iv in o : doEnc o is cfbDecryptGeneric :: BlockCipher cipher => cipher -> IV cipher -> ByteString -> ByteString cfbDecryptGeneric cipher (IV ivini) input = B.concat $ doDec ivini $ chunk (blockSize cipher) input where doDec _ [] = [] doDec iv (i:is) = let o = bxor i $ ecbEncrypt cipher iv in o : doDec i is ctrCombineGeneric :: BlockCipher cipher => cipher -> IV cipher -> ByteString -> ByteString ctrCombineGeneric cipher ivini input = B.concat $ doCnt ivini $ chunk (blockSize cipher) input where doCnt _ [] = [] doCnt iv (i:is) = let ivEnc = ecbEncrypt cipher (toBytes iv) in bxor i ivEnc : doCnt (ivAdd iv 1) is xtsEncryptGeneric :: BlockCipher cipher => XTS cipher xtsEncryptGeneric = xtsGeneric ecbEncrypt xtsDecryptGeneric :: BlockCipher cipher => XTS cipher xtsDecryptGeneric = xtsGeneric ecbDecrypt xtsGeneric :: BlockCipher cipher => (cipher -> B.ByteString -> B.ByteString) -> (cipher, cipher) -> IV cipher -> DataUnitOffset -> ByteString -> ByteString xtsGeneric f (cipher, tweakCipher) iv sPoint input | blockSize cipher /= 16 = error "XTS mode is only available with cipher that have a block size of 128 bits" | otherwise = B.concat $ doXts iniTweak $ chunk (blockSize cipher) input where encTweak = ecbEncrypt tweakCipher (toBytes iv) iniTweak = iterate xtsGFMul encTweak !! fromIntegral sPoint doXts _ [] = [] doXts tweak (i:is) = let o = bxor (f cipher $ bxor i tweak) tweak in o : doXts (xtsGFMul tweak) is -- | Encrypt using CFB mode in 8 bit output -- -- Effectively turn a Block cipher in CFB mode into a Stream cipher cfb8Encrypt :: BlockCipher a => a -> IV a -> B.ByteString -> B.ByteString cfb8Encrypt ctx origIv msg = B.unsafeCreate (B.length msg) $ \dst -> loop dst origIv msg where loop d iv@(IV i) m | B.null m = return () | otherwise = poke d out >> loop (d `plusPtr` 1) ni (B.drop 1 m) where m' = if B.length m < blockSize ctx then m `B.append` B.replicate (blockSize ctx - B.length m) 0 else B.take (blockSize ctx) m r = cfbEncrypt ctx iv m' out = B.head r ni = IV (B.drop 1 i `B.snoc` out) -- | Decrypt using CFB mode in 8 bit output -- -- Effectively turn a Block cipher in CFB mode into a Stream cipher cfb8Decrypt :: BlockCipher a => a -> IV a -> B.ByteString -> B.ByteString cfb8Decrypt ctx origIv msg = B.unsafeCreate (B.length msg) $ \dst -> loop dst origIv msg where loop d iv@(IV i) m | B.null m = return () | otherwise = poke d out >> loop (d `plusPtr` 1) ni (B.drop 1 m) where m' = if B.length m < blockSize ctx then m `B.append` B.replicate (blockSize ctx - B.length m) 0 else B.take (blockSize ctx) m r = cfbDecrypt ctx iv m' out = B.head r ni = IV (B.drop 1 i `B.snoc` B.head m') crypto-cipher-types-0.0.9/Crypto/Cipher/Types/Utils.hs0000644000000000000000000000127312232400460021066 0ustar0000000000000000-- | -- Module : Crypto.Cipher.Types.Utils -- License : BSD-style -- Maintainer : Vincent Hanquez -- Stability : Stable -- Portability : Excellent -- -- basic utility for cipher related stuff -- module Crypto.Cipher.Types.Utils where import Data.Bits (xor) import Data.ByteString (ByteString) import qualified Data.ByteString as B chunk :: Int -> ByteString -> [ByteString] chunk sz bs = split bs where split b | B.length b <= sz = [b] | otherwise = let (b1, b2) = B.splitAt sz b in b1 : split b2 bxor :: ByteString -> ByteString -> ByteString bxor src dst = B.pack $ B.zipWith xor src dst crypto-cipher-types-0.0.9/Crypto/Cipher/Types/AEAD.hs0000644000000000000000000000522312232400460020457 0ustar0000000000000000-- | -- Module : Crypto.Cipher.Types.AEAD -- License : BSD-style -- Maintainer : Vincent Hanquez -- Stability : Stable -- Portability : Excellent -- -- AEAD cipher basic types -- module Crypto.Cipher.Types.AEAD where import Data.ByteString (ByteString) import qualified Data.ByteString as B import Data.Byteable import Crypto.Cipher.Types.Base import Crypto.Cipher.Types.Block -- | Append associated data into the AEAD state aeadAppendHeader :: BlockCipher a => AEAD a -> ByteString -> AEAD a aeadAppendHeader (AEAD cipher (AEADState state)) bs = AEAD cipher $ AEADState (aeadStateAppendHeader cipher state bs) -- | Encrypt input and append into the AEAD state aeadEncrypt :: BlockCipher a => AEAD a -> ByteString -> (ByteString, AEAD a) aeadEncrypt (AEAD cipher (AEADState state)) input = (output, AEAD cipher (AEADState nst)) where (output, nst) = aeadStateEncrypt cipher state input -- | Decrypt input and append into the AEAD state aeadDecrypt :: BlockCipher a => AEAD a -> ByteString -> (ByteString, AEAD a) aeadDecrypt (AEAD cipher (AEADState state)) input = (output, AEAD cipher (AEADState nst)) where (output, nst) = aeadStateDecrypt cipher state input -- | Finalize the AEAD state and create an authentification tag aeadFinalize :: BlockCipher a => AEAD a -> Int -> AuthTag aeadFinalize (AEAD cipher (AEADState state)) len = aeadStateFinalize cipher state len -- | Simple AEAD encryption aeadSimpleEncrypt :: BlockCipher a => AEAD a -- ^ A new AEAD Context -> B.ByteString -- ^ Optional Authentified Header -> B.ByteString -- ^ Optional Plaintext -> Int -- ^ Tag length -> (AuthTag, B.ByteString) -- ^ Authentification tag and ciphertext aeadSimpleEncrypt aeadIni header input taglen = (tag, output) where aead = aeadAppendHeader aeadIni header (output, aeadFinal) = aeadEncrypt aead input tag = aeadFinalize aeadFinal taglen -- | Simple AEAD decryption aeadSimpleDecrypt :: BlockCipher a => AEAD a -- ^ A new AEAD Context -> B.ByteString -- ^ Optional Authentified Header -> B.ByteString -- ^ Optional Plaintext -> AuthTag -- ^ Tag length -> Maybe B.ByteString -- ^ Plaintext aeadSimpleDecrypt aeadIni header input authTag | tag == authTag = Just output | otherwise = Nothing where aead = aeadAppendHeader aeadIni header (output, aeadFinal) = aeadDecrypt aead input tag = aeadFinalize aeadFinal (byteableLength authTag) crypto-cipher-types-0.0.9/Crypto/Cipher/Types/BlockIO.hs0000644000000000000000000001501712232400460021251 0ustar0000000000000000-- | -- Module : Crypto.Cipher.Types.Block -- License : BSD-style -- Maintainer : Vincent Hanquez -- Stability : Stable -- Portability : Excellent -- -- block cipher basic types -- {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE ViewPatterns #-} module Crypto.Cipher.Types.BlockIO ( BlockCipherIO(..) , PtrDest , PtrSource , PtrIV , BufferLength , onBlock ) where import Control.Applicative import Data.Word import Data.ByteString (ByteString) import qualified Data.ByteString.Internal as B (fromForeignPtr, memcpy) import Data.Byteable import Data.Bits (xor, Bits) import Foreign.Storable (poke, peek, Storable) --import Foreign.Ptr (plusPtr, Ptr, castPtr, nullPtr) import Crypto.Cipher.Types.Block import Foreign.Ptr import Foreign.ForeignPtr (newForeignPtr_) -- | pointer to the destination data type PtrDest = Ptr Word8 -- | pointer to the source data type PtrSource = Ptr Word8 -- | pointer to the IV data type PtrIV = Ptr Word8 -- | Length of the pointed data type BufferLength = Word32 -- | Symmetric block cipher class, mutable API class BlockCipher cipher => BlockCipherIO cipher where -- | Encrypt using the ECB mode. -- -- input need to be a multiple of the blocksize ecbEncryptMutable :: cipher -> PtrDest -> PtrSource -> BufferLength -> IO () -- | Decrypt using the ECB mode. -- -- input need to be a multiple of the blocksize ecbDecryptMutable :: cipher -> PtrDest -> PtrSource -> BufferLength -> IO () -- | encrypt using the CBC mode. -- -- input need to be a multiple of the blocksize cbcEncryptMutable :: cipher -> PtrIV -> PtrDest -> PtrSource -> BufferLength -> IO () cbcEncryptMutable = cbcEncryptGeneric -- | decrypt using the CBC mode. -- -- input need to be a multiple of the blocksize cbcDecryptMutable :: cipher -> PtrIV -> PtrDest -> PtrSource -> BufferLength -> IO () cbcDecryptMutable = cbcDecryptGeneric {- -- | encrypt using the CFB mode. -- -- input need to be a multiple of the blocksize cfbEncryptMutable :: cipher -> PtrIV -> PtrDest -> PtrSource -> BufferLength -> IO () cfbEncryptMutable = cfbEncryptGeneric -- | decrypt using the CFB mode. -- -- input need to be a multiple of the blocksize cfbDecryptMutable :: cipher -> PtrIV -> PtrDest -> PtrSource -> BufferLength -> IO () cfbDecryptMutable = cfbDecryptGeneric -- | combine using the CTR mode. -- -- CTR mode produce a stream of randomized data that is combined -- (by XOR operation) with the input stream. -- -- encryption and decryption are the same operation. -- -- input can be of any size ctrCombineMutable :: cipher -> PtrIV -> PtrDest -> PtrSource -> BufferLength -> IO () ctrCombineMutable = ctrCombineGeneric -- | encrypt using the XTS mode. -- -- input need to be a multiple of the blocksize xtsEncryptMutable :: (cipher, cipher) -> PtrIV -> DataUnitOffset -> PtrDest -> PtrSource -> BufferLength -> IO () xtsEncryptMutable = xtsEncryptGeneric -- | decrypt using the XTS mode. -- -- input need to be a multiple of the blocksize xtsDecryptMutable :: (cipher, cipher) -> PtrIV -> DataUnitOffset -> PtrDest -> PtrSource -> BufferLength -> IO () xtsDecryptMutable = xtsDecryptGeneric -} cbcEncryptGeneric :: BlockCipherIO cipher => cipher -> PtrIV -> PtrDest -> PtrSource -> BufferLength -> IO () cbcEncryptGeneric cipher = loopBS cipher encrypt where encrypt bs iv d s = do mutableXor d iv s bs ecbEncryptMutable cipher d d (fromIntegral bs) return s cbcDecryptGeneric :: BlockCipherIO cipher => cipher -> PtrIV -> PtrDest -> PtrSource -> BufferLength -> IO () cbcDecryptGeneric cipher = loopBS cipher decrypt where decrypt bs iv d s = do ecbEncryptMutable cipher d s (fromIntegral bs) -- FIXME only work if s != d mutableXor d iv d bs return d {- cfbEncryptGeneric :: BlockCipherIO cipher => cipher -> PtrIV -> PtrDest -> PtrSource -> BufferLength -> IO () cfbEncryptGeneric cipher = loopBS cipher encrypt where encrypt bs iv d s = do ecbEncryptMutable cipher d iv (fromIntegral bs) mutableXor d d s bs return d cfbDecryptGeneric :: BlockCipherIO cipher => cipher -> PtrIV -> PtrDest -> PtrSource -> BufferLength -> IO () cfbDecryptGeneric cipher = loopBS cipher decrypt where decrypt bs iv d s = do ecbEncryptMutable cipher d iv (fromIntegral bs) mutableXor d d s bs return s ctrCombineGeneric :: BlockCipherIO cipher => cipher -> PtrIV -> PtrDest -> PtrSource -> BufferLength -> IO () ctrCombineGeneric cipher ivini dst src len = return () {-B.concat $ doCnt ivini $ chunk (blockSize cipher) input where doCnt _ [] = [] doCnt iv (i:is) = let ivEnc = ecbEncrypt cipher (toBytes iv) in bxor i ivEnc : doCnt (ivAdd iv 1) is-} -} -- | Helper to use a purer interface onBlock :: BlockCipherIO cipher => cipher -> (ByteString -> ByteString) -> PtrDest -> PtrSource -> BufferLength -> IO () onBlock cipher f dst src len = loopBS cipher wrap nullPtr dst src len where wrap bs fakeIv d s = do fSrc <- newForeignPtr_ s let res = f (B.fromForeignPtr fSrc 0 bs) withBytePtr res $ \r -> B.memcpy d r (fromIntegral bs) return fakeIv loopBS :: BlockCipherIO cipher => cipher -> (Int -> PtrIV -> PtrDest -> PtrSource -> IO PtrIV) -> PtrIV -> PtrDest -> PtrSource -> BufferLength -> IO () loopBS cipher f iv dst src len = loop iv dst src len where bs = blockSize cipher loop _ _ _ 0 = return () loop i d s n = do newIV <- f bs i d s loop newIV (d `plusPtr` bs) (s `plusPtr` bs) (n - fromIntegral bs) mutableXor :: PtrDest -> PtrSource -> PtrIV -> Int -> IO () mutableXor (to64 -> dst) (to64 -> src) (to64 -> iv) 16 = do peeksAndPoke dst src iv peeksAndPoke (dst `plusPtr` 8) (src `plusPtr` 8) ((iv `plusPtr` 8) :: Ptr Word64) mutableXor (to64 -> dst) (to64 -> src) (to64 -> iv) 8 = do peeksAndPoke dst src iv mutableXor dst src iv len = loop dst src iv len where loop _ _ _ 0 = return () loop d s i n = peeksAndPoke d s i >> loop (d `plusPtr` 1) (s `plusPtr` 1) (i `plusPtr` 1) (n-1) to64 :: Ptr Word8 -> Ptr Word64 to64 = castPtr peeksAndPoke :: (Bits a, Storable a) => Ptr a -> Ptr a -> Ptr a -> IO () peeksAndPoke dst a b = (xor <$> peek a <*> peek b) >>= poke dst