merge crypto-cipher-types
This commit is contained in:
parent
abacea200d
commit
6c4557621c
@ -1,3 +1,60 @@
|
||||
-- |
|
||||
-- Module : Crypto.Cipher.Types
|
||||
-- License : BSD-style
|
||||
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
|
||||
-- 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)
|
||||
|
||||
63
Crypto/Cipher/Types/AEAD.hs
Normal file
63
Crypto/Cipher/Types/AEAD.hs
Normal file
@ -0,0 +1,63 @@
|
||||
-- |
|
||||
-- Module : Crypto.Cipher.Types.AEAD
|
||||
-- License : BSD-style
|
||||
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
|
||||
-- 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)
|
||||
|
||||
83
Crypto/Cipher/Types/Base.hs
Normal file
83
Crypto/Cipher/Types/Base.hs
Normal file
@ -0,0 +1,83 @@
|
||||
-- |
|
||||
-- Module : Crypto.Cipher.Types.Base
|
||||
-- License : BSD-style
|
||||
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
|
||||
-- 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 -- OCB3
|
||||
| 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
|
||||
253
Crypto/Cipher/Types/Block.hs
Normal file
253
Crypto/Cipher/Types/Block.hs
Normal file
@ -0,0 +1,253 @@
|
||||
-- |
|
||||
-- Module : Crypto.Cipher.Types.Block
|
||||
-- License : BSD-style
|
||||
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
|
||||
-- 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)
|
||||
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')
|
||||
49
Crypto/Cipher/Types/GF.hs
Normal file
49
Crypto/Cipher/Types/GF.hs
Normal file
@ -0,0 +1,49 @@
|
||||
-- |
|
||||
-- Module : Crypto.Cipher.Types.GF
|
||||
-- License : BSD-style
|
||||
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
|
||||
-- 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;
|
||||
-}
|
||||
20
Crypto/Cipher/Types/Stream.hs
Normal file
20
Crypto/Cipher/Types/Stream.hs
Normal file
@ -0,0 +1,20 @@
|
||||
-- |
|
||||
-- Module : Crypto.Cipher.Types.Stream
|
||||
-- License : BSD-style
|
||||
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
|
||||
-- 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)
|
||||
24
Crypto/Cipher/Types/Utils.hs
Normal file
24
Crypto/Cipher/Types/Utils.hs
Normal file
@ -0,0 +1,24 @@
|
||||
-- |
|
||||
-- Module : Crypto.Cipher.Types.Utils
|
||||
-- License : BSD-style
|
||||
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
|
||||
-- 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
|
||||
@ -30,6 +30,7 @@ Library
|
||||
Exposed-modules: Crypto.Cipher.ChaCha
|
||||
Crypto.Cipher.Salsa
|
||||
Crypto.Cipher.RC4
|
||||
Crypto.Cipher.Types
|
||||
Crypto.Data.AFIS
|
||||
Crypto.MAC.Poly1305
|
||||
Crypto.MAC.HMAC
|
||||
@ -80,6 +81,12 @@ Library
|
||||
Crypto.Random.EntropyPool
|
||||
Crypto.Random.Entropy.Unsafe
|
||||
Other-modules: Crypto.Cipher.AES.Internal
|
||||
Crypto.Cipher.Types.AEAD
|
||||
Crypto.Cipher.Types.Base
|
||||
Crypto.Cipher.Types.Block
|
||||
Crypto.Cipher.Types.GF
|
||||
Crypto.Cipher.Types.Stream
|
||||
Crypto.Cipher.Types.Utils
|
||||
Crypto.Hash.Utils
|
||||
Crypto.Hash.Utils.Cpu
|
||||
Crypto.Hash.Types
|
||||
|
||||
Loading…
Reference in New Issue
Block a user