1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
|
-- |
-- 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.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
|