From 9ae9e38ce286871d7c7702884339818ef91c6ea1 Mon Sep 17 00:00:00 2001 From: Vincent Hanquez Date: Sat, 9 May 2015 14:23:32 +0100 Subject: [PATCH] move to memory stuff --- Crypto/Cipher/AES/Primitive.hs | 8 +- Crypto/Cipher/Camellia/Primitive.hs | 3 +- Crypto/Cipher/ChaCha.hs | 14 +- Crypto/Cipher/DES.hs | 3 +- Crypto/Cipher/DES/Primitive.hs | 1 + Crypto/Cipher/RC4.hs | 4 +- Crypto/Cipher/Salsa.hs | 12 +- Crypto/Cipher/TripleDES.hs | 5 +- Crypto/Data/AFIS.hs | 13 +- Crypto/Internal/ByteArray.hs | 265 +--------------------------- Crypto/Internal/Bytes.hs | 72 -------- Crypto/Internal/Memory.hs | 127 ------------- Crypto/Internal/Words.hs | 4 +- Crypto/KDF/PBKDF2.hs | 12 +- Crypto/MAC/HMAC.hs | 24 +-- Crypto/MAC/Poly1305.hs | 8 +- Crypto/PubKey/Curve25519.hs | 6 +- Crypto/PubKey/ECC/P256.hs | 4 +- Crypto/PubKey/Ed25519.hs | 5 +- Crypto/Random.hs | 4 +- Crypto/Random/ChaChaDRG.hs | 4 +- Crypto/Random/EntropyPool.hs | 4 +- cryptonite.cabal | 5 +- tests/BlockCipher.hs | 2 +- tests/Hash.hs | 2 +- tests/KAT_Curve25519.hs | 2 +- tests/Tests.hs | 2 +- 27 files changed, 77 insertions(+), 538 deletions(-) delete mode 100644 Crypto/Internal/Bytes.hs delete mode 100644 Crypto/Internal/Memory.hs diff --git a/Crypto/Cipher/AES/Primitive.hs b/Crypto/Cipher/AES/Primitive.hs index 82bb546..5ae76ec 100644 --- a/Crypto/Cipher/AES/Primitive.hs +++ b/Crypto/Cipher/AES/Primitive.hs @@ -67,7 +67,7 @@ import Crypto.Error import Crypto.Cipher.Types import Crypto.Cipher.Types.Block (IV(..)) import Crypto.Internal.Compat -import Crypto.Internal.ByteArray (ByteArray, ByteArrayAccess, SecureBytes, withByteArray) +import Crypto.Internal.ByteArray (ByteArray, ByteArrayAccess, ScrubbedBytes, withByteArray) import qualified Crypto.Internal.ByteArray as B instance Cipher AES where @@ -107,13 +107,13 @@ ocbMode aes = AEADModeImpl -- | AES Context (pre-processed key) -newtype AES = AES SecureBytes +newtype AES = AES ScrubbedBytes -- | AESGCM State -newtype AESGCM = AESGCM SecureBytes +newtype AESGCM = AESGCM ScrubbedBytes -- | AESOCB State -newtype AESOCB = AESOCB SecureBytes +newtype AESOCB = AESOCB ScrubbedBytes sizeGCM :: Int sizeGCM = 80 diff --git a/Crypto/Cipher/Camellia/Primitive.hs b/Crypto/Cipher/Camellia/Primitive.hs index 20641d2..d7432b0 100644 --- a/Crypto/Cipher/Camellia/Primitive.hs +++ b/Crypto/Cipher/Camellia/Primitive.hs @@ -26,6 +26,7 @@ import Crypto.Internal.ByteArray (ByteArrayAccess, ByteArray) import qualified Crypto.Internal.ByteArray as B import Crypto.Internal.Words import Crypto.Internal.WordArray +import Data.Memory.Endian data Mode = Decrypt | Encrypt @@ -118,7 +119,7 @@ data Camellia = Camellia setKeyInterim :: ByteArrayAccess key => key -> (Word128, Word128, Word128, Word128) setKeyInterim keyseed = (w64tow128 kL, w64tow128 kR, w64tow128 kA, w64tow128 kB) - where kL = (B.toW64BE keyseed 0, B.toW64BE keyseed 8) + where kL = (fromBE $ B.toW64BE keyseed 0, fromBE $ B.toW64BE keyseed 8) kR = (0, 0) kA = let d1 = (fst kL `xor` fst kR) diff --git a/Crypto/Cipher/ChaCha.hs b/Crypto/Cipher/ChaCha.hs index bb0c9ab..af53d21 100644 --- a/Crypto/Cipher/ChaCha.hs +++ b/Crypto/Cipher/ChaCha.hs @@ -20,22 +20,22 @@ module Crypto.Cipher.ChaCha import Data.ByteString (ByteString) import qualified Data.ByteString as BS import qualified Data.ByteString.Internal as BS -import Crypto.Internal.ByteArray (ByteArrayAccess, ByteArray, SecureBytes, withByteArray) +import Crypto.Internal.ByteArray (ByteArrayAccess, ByteArray, ScrubbedBytes, withByteArray) import qualified Crypto.Internal.ByteArray as B import Crypto.Internal.Compat import Crypto.Internal.Imports -import Crypto.Internal.Bytes (bufXor) +import Data.Memory.PtrMethods (memXor) import Foreign.Ptr import Foreign.ForeignPtr import Foreign.C.Types -- | ChaCha context -data State = State Int -- number of rounds - SecureBytes -- ChaCha's state - ByteString -- previous generated chunk +data State = State Int -- number of rounds + ScrubbedBytes -- ChaCha's state + ByteString -- previous generated chunk -- | ChaCha context for DRG purpose (see Crypto.Random.ChaChaDRG) -newtype StateSimple = StateSimple SecureBytes -- just ChaCha's state +newtype StateSimple = StateSimple ScrubbedBytes -- just ChaCha's state round64 :: Int -> (Bool, Int) round64 len @@ -102,7 +102,7 @@ combine prev@(State nbRounds prevSt prevOut) src withByteArray src $ \srcPtr -> do -- copy the previous buffer by xor if any withByteArray prevOut $ \prevPtr -> - bufXor dstPtr srcPtr prevPtr prevBufLen + memXor dstPtr srcPtr prevPtr prevBufLen -- then create a new mutable copy of state B.copy prevSt $ \stPtr -> diff --git a/Crypto/Cipher/DES.hs b/Crypto/Cipher/DES.hs index 1a291e2..028a6ad 100644 --- a/Crypto/Cipher/DES.hs +++ b/Crypto/Cipher/DES.hs @@ -15,6 +15,7 @@ import Crypto.Cipher.Types import Crypto.Cipher.DES.Primitive import Crypto.Internal.ByteArray (ByteArrayAccess) import qualified Crypto.Internal.ByteArray as B +import Data.Memory.Endian -- | DES Context data DES = DES Word64 @@ -35,4 +36,4 @@ initDES k | len == 8 = CryptoPassed $ DES key | otherwise = CryptoFailed $ CryptoError_KeySizeInvalid where len = B.length k - key = B.toW64BE k 0 + key = fromBE $ B.toW64BE k 0 diff --git a/Crypto/Cipher/DES/Primitive.hs b/Crypto/Cipher/DES/Primitive.hs index 18a623c..2da9803 100644 --- a/Crypto/Cipher/DES/Primitive.hs +++ b/Crypto/Cipher/DES/Primitive.hs @@ -15,6 +15,7 @@ module Crypto.Cipher.DES.Primitive (encrypt, decrypt, Block(..)) where import Data.Word import Data.Bits +import Data.Memory.Endian newtype Block = Block { unBlock :: Word64 } diff --git a/Crypto/Cipher/RC4.hs b/Crypto/Cipher/RC4.hs index 8971783..bd1f241 100644 --- a/Crypto/Cipher/RC4.hs +++ b/Crypto/Cipher/RC4.hs @@ -23,13 +23,13 @@ module Crypto.Cipher.RC4 import Data.Word import Foreign.Ptr -import Crypto.Internal.ByteArray (SecureBytes, ByteArray, ByteArrayAccess) +import Crypto.Internal.ByteArray (ScrubbedBytes, ByteArray, ByteArrayAccess) import qualified Crypto.Internal.ByteArray as B import Crypto.Internal.Compat -- | The encryption state for RC4 -newtype State = State SecureBytes +newtype State = State ScrubbedBytes deriving (ByteArrayAccess) -- | C Call for initializing the encryptor diff --git a/Crypto/Cipher/Salsa.hs b/Crypto/Cipher/Salsa.hs index a4d9ca5..75be3e5 100644 --- a/Crypto/Cipher/Salsa.hs +++ b/Crypto/Cipher/Salsa.hs @@ -14,8 +14,8 @@ module Crypto.Cipher.Salsa ) where import Data.ByteString (ByteString) -import Crypto.Internal.Bytes (bufXor) -import Crypto.Internal.ByteArray (ByteArrayAccess, ByteArray, SecureBytes) +import Data.Memory.PtrMethods (memXor) +import Crypto.Internal.ByteArray (ByteArrayAccess, ByteArray, ScrubbedBytes) import qualified Crypto.Internal.ByteArray as B import qualified Data.ByteString.Internal as BS import qualified Data.ByteString as BS @@ -27,9 +27,9 @@ import Foreign.ForeignPtr import Foreign.C.Types -- | Salsa context -data State = State Int -- number of rounds - SecureBytes -- Salsa's state - ByteString -- previous generated chunk +data State = State Int -- number of rounds + ScrubbedBytes -- Salsa's state + ByteString -- previous generated chunk round64 :: Int -> (Bool, Int) round64 len @@ -83,7 +83,7 @@ combine prev@(State nbRounds prevSt prevOut) src B.withByteArray src $ \srcPtr -> do -- copy the previous buffer by xor if any B.withByteArray prevOut $ \prevPtr -> - bufXor dstPtr srcPtr prevPtr prevBufLen + memXor dstPtr srcPtr prevPtr prevBufLen -- then create a new mutable copy of state B.copy prevSt $ \stPtr -> diff --git a/Crypto/Cipher/TripleDES.hs b/Crypto/Cipher/TripleDES.hs index 99b330e..581fa8f 100644 --- a/Crypto/Cipher/TripleDES.hs +++ b/Crypto/Cipher/TripleDES.hs @@ -17,6 +17,7 @@ import Crypto.Cipher.Types import Crypto.Cipher.DES.Primitive import Crypto.Internal.ByteArray (ByteArrayAccess) import qualified Crypto.Internal.ByteArray as B +import Data.Memory.Endian -- | 3DES with 3 different keys used all in the same direction data DES_EEE3 = DES_EEE3 Word64 Word64 Word64 @@ -79,11 +80,11 @@ init3DES constr k | len == 24 = CryptoPassed $ constr k1 k2 k3 | otherwise = CryptoFailed CryptoError_KeySizeInvalid where len = B.length k - (k1, k2, k3) = (B.toW64BE k 0, B.toW64BE k 8, B.toW64BE k 16) + (k1, k2, k3) = (fromBE $ B.toW64BE k 0, fromBE $ B.toW64BE k 8, fromBE $ B.toW64BE k 16) init2DES :: ByteArrayAccess key => (Word64 -> Word64 -> a) -> key -> CryptoFailable a init2DES constr k | len == 16 = CryptoPassed $ constr k1 k2 | otherwise = CryptoFailed CryptoError_KeySizeInvalid where len = B.length k - (k1, k2) = (B.toW64BE k 0, B.toW64BE k 8) + (k1, k2) = (fromBE $ B.toW64BE k 0, fromBE $ B.toW64BE k 8) diff --git a/Crypto/Data/AFIS.hs b/Crypto/Data/AFIS.hs index 2fb5e72..87b90be 100644 --- a/Crypto/Data/AFIS.hs +++ b/Crypto/Data/AFIS.hs @@ -20,7 +20,6 @@ module Crypto.Data.AFIS import Crypto.Hash import Crypto.Random.Types -import Crypto.Internal.Bytes (bufSet, bufCopy) import Crypto.Internal.Compat import Control.Monad (forM_, foldM) import Data.Word @@ -31,6 +30,8 @@ import Foreign.Ptr import Crypto.Internal.ByteArray (ByteArray, Bytes, MemView(..)) import qualified Crypto.Internal.ByteArray as B +import Data.Memory.PtrMethods (memSet, memCopy) + -- | Split data to diffused data, using a random generator and -- an hash algorithm. -- @@ -65,7 +66,7 @@ split hashAlg rng expandTimes src blockSize = B.length src runOp dstPtr = do let lastBlock = dstPtr `plusPtr` (blockSize * (expandTimes-1)) - bufSet lastBlock 0 blockSize + memSet lastBlock 0 blockSize let randomBlockPtrs = map (plusPtr dstPtr . (*) blockSize) [0..(expandTimes-2)] rng' <- foldM fillRandomBlock rng randomBlockPtrs mapM_ (addRandomBlock lastBlock) randomBlockPtrs @@ -76,7 +77,7 @@ split hashAlg rng expandTimes src diffuse hashAlg lastBlock blockSize fillRandomBlock g blockPtr = do let (rand :: Bytes, g') = randomBytesGenerate blockSize g - B.withByteArray rand $ \randPtr -> bufCopy blockPtr randPtr (fromIntegral blockSize) + B.withByteArray rand $ \randPtr -> memCopy blockPtr randPtr (fromIntegral blockSize) return g' -- | Merge previously diffused data back to the original data. @@ -91,7 +92,7 @@ merge hashAlg expandTimes bs | originalSize <= 0 = error "diffused data null" | otherwise = B.allocAndFreeze originalSize $ \dstPtr -> B.withByteArray bs $ \srcPtr -> do - bufSet dstPtr 0 originalSize + memSet dstPtr 0 originalSize forM_ [0..(expandTimes-2)] $ \i -> do xorMem (srcPtr `plusPtr` (i * originalSize)) dstPtr originalSize diffuse hashAlg dstPtr originalSize @@ -122,10 +123,10 @@ diffuse hashAlg src sz = loop src 0 where (full,pad) = sz `quotRem` digestSize loop s i | i < full = do h <- hashBlock i s digestSize - B.withByteArray h $ \hPtr -> bufCopy s hPtr digestSize + B.withByteArray h $ \hPtr -> memCopy s hPtr digestSize loop (s `plusPtr` digestSize) (i+1) | pad /= 0 = do h <- hashBlock i s pad - B.withByteArray h $ \hPtr -> bufCopy s hPtr pad + B.withByteArray h $ \hPtr -> memCopy s hPtr pad return () | otherwise = return () diff --git a/Crypto/Internal/ByteArray.hs b/Crypto/Internal/ByteArray.hs index afce181..b242a66 100644 --- a/Crypto/Internal/ByteArray.hs +++ b/Crypto/Internal/ByteArray.hs @@ -7,269 +7,8 @@ -- -- Simple and efficient byte array types -- -{-# LANGUAGE BangPatterns #-} -{-# LANGUAGE MagicHash #-} -{-# LANGUAGE UnboxedTuples #-} -{-# LANGUAGE NoImplicitPrelude #-} module Crypto.Internal.ByteArray - ( - ByteArray(..) - , ByteArrayAccess(..) - -- * Inhabitants - , Bytes - , SecureBytes - , MemView(..) - -- * methods - , alloc - , allocAndFreeze - , empty - , zero - , copy - , take - , convert - , convertHex - , copyRet - , copyAndFreeze - , split - , xor - , eq - , index - , constEq - , concat - , toBS - , fromBS - , toW64BE - , toW64LE - , mapAsWord64 - , mapAsWord128 + ( module X ) where -import Data.SecureMem -import Crypto.Internal.Memory -import Crypto.Internal.Compat -import Crypto.Internal.Endian -import Crypto.Internal.Bytes (bufXor, bufCopy, bufSet) -import Crypto.Internal.Hex -import Crypto.Internal.Words -import Crypto.Internal.Imports hiding (empty) -import Foreign.Ptr -import Foreign.Storable -import Foreign.ForeignPtr -import Data.ByteString (ByteString) -import qualified Data.ByteString as B (length) -import qualified Data.ByteString.Internal as B - -import Prelude (flip, return, div, (*), (-), ($), (==), (/=), (<=), (>=), Int, Bool(..), IO, otherwise, sum, map, fmap, snd, (.), min) - -data MemView = MemView !(Ptr Word8) !Int - -instance ByteArrayAccess MemView where - length (MemView _ l) = l - withByteArray (MemView p _) f = f (castPtr p) - -class ByteArrayAccess ba where - length :: ba -> Int - withByteArray :: ba -> (Ptr p -> IO a) -> IO a - -class ByteArrayAccess ba => ByteArray ba where - allocRet :: Int -> (Ptr p -> IO a) -> IO (a, ba) - -alloc :: ByteArray ba => Int -> (Ptr p -> IO ()) -> IO ba -alloc n f = snd `fmap` allocRet n f - -instance ByteArrayAccess Bytes where - length = bytesLength - withByteArray = withBytes -instance ByteArray Bytes where - allocRet = bytesAllocRet - -instance ByteArrayAccess ByteString where - length = B.length - withByteArray b f = withForeignPtr fptr $ \ptr -> f (ptr `plusPtr` off) - where (fptr, off, _) = B.toForeignPtr b -instance ByteArray ByteString where - allocRet sz f = do - fptr <- B.mallocByteString sz - r <- withForeignPtr fptr (f . castPtr) - return (r, B.PS fptr 0 sz) - -instance ByteArrayAccess SecureMem where - length = secureMemGetSize - withByteArray b f = withSecureMemPtr b (f . castPtr) -instance ByteArray SecureMem where - allocRet sz f = do - out <- allocateSecureMem sz - r <- withSecureMemPtr out (f . castPtr) - return (r, out) - -allocAndFreeze :: ByteArray a => Int -> (Ptr p -> IO ()) -> a -allocAndFreeze sz f = unsafeDoIO (alloc sz f) - -empty :: ByteArray a => a -empty = unsafeDoIO (alloc 0 $ \_ -> return ()) - --- | Create a xor of bytes between a and b. --- --- the returns byte array is the size of the smallest input. -xor :: (ByteArrayAccess a, ByteArrayAccess b, ByteArray c) => a -> b -> c -xor a b = - allocAndFreeze n $ \pc -> - withByteArray a $ \pa -> - withByteArray b $ \pb -> - bufXor pc pa pb n - where - n = min la lb - la = length a - lb = length b - -index :: ByteArrayAccess a => a -> Int -> Word8 -index b i = unsafeDoIO $ withByteArray b $ \p -> peek (p `plusPtr` i) - -split :: ByteArray bs => Int -> bs -> (bs, bs) -split n bs - | n <= 0 = (empty, bs) - | n >= len = (bs, empty) - | otherwise = unsafeDoIO $ do - withByteArray bs $ \p -> do - b1 <- alloc n $ \r -> bufCopy r p n - b2 <- alloc (len - n) $ \r -> bufCopy r (p `plusPtr` n) (len - n) - return (b1, b2) - where len = length bs - -take :: ByteArray bs => Int -> bs -> bs -take n bs = - allocAndFreeze m $ \d -> withByteArray bs $ \s -> bufCopy d s m - where - m = min len n - len = length bs - -concat :: ByteArray bs => [bs] -> bs -concat [] = empty -concat allBs = allocAndFreeze total (loop allBs) - where - total = sum $ map length allBs - - loop [] _ = return () - loop (b:bs) dst = do - let sz = length b - withByteArray b $ \p -> bufCopy dst p sz - loop bs (dst `plusPtr` sz) - -copy :: (ByteArrayAccess bs1, ByteArray bs2) => bs1 -> (Ptr p -> IO ()) -> IO bs2 -copy bs f = - alloc (length bs) $ \d -> do - withByteArray bs $ \s -> bufCopy d s (length bs) - f (castPtr d) - -copyRet :: (ByteArrayAccess bs1, ByteArray bs2) => bs1 -> (Ptr p -> IO a) -> IO (a, bs2) -copyRet bs f = - allocRet (length bs) $ \d -> do - withByteArray bs $ \s -> bufCopy d s (length bs) - f (castPtr d) - -copyAndFreeze :: (ByteArrayAccess bs1, ByteArray bs2) => bs1 -> (Ptr p -> IO ()) -> bs2 -copyAndFreeze bs f = - allocAndFreeze (length bs) $ \d -> do - withByteArray bs $ \s -> bufCopy d s (length bs) - f (castPtr d) - -zero :: ByteArray ba => Int -> ba -zero n = allocAndFreeze n $ \ptr -> bufSet ptr 0 n - -eq :: (ByteArrayAccess bs1, ByteArrayAccess bs2) => bs1 -> bs2 -> Bool -eq b1 b2 - | l1 /= l2 = False - | otherwise = unsafeDoIO $ - withByteArray b1 $ \p1 -> - withByteArray b2 $ \p2 -> - loop l1 p1 p2 - where - l1 = length b1 - l2 = length b2 - loop :: Int -> Ptr Word8 -> Ptr Word8 -> IO Bool - loop 0 _ _ = return True - loop i p1 p2 = do - e <- (==) <$> peek p1 <*> peek p2 - if e then loop (i-1) (p1 `plusPtr` 1) (p2 `plusPtr` 1) else return False - --- | A constant time equality test for 2 ByteArrayAccess values. --- --- If values are of 2 different sizes, the function will abort early --- without comparing any bytes. --- --- compared to == , this function will go over all the bytes --- present before yielding a result even when knowing the --- overall result early in the processing. -constEq :: (ByteArrayAccess bs1, ByteArrayAccess bs2) => bs1 -> bs2 -> Bool -constEq b1 b2 - | l1 /= l2 = False - | otherwise = unsafeDoIO $ - withByteArray b1 $ \p1 -> - withByteArray b2 $ \p2 -> - loop l1 True p1 p2 - where - l1 = length b1 - l2 = length b2 - loop :: Int -> Bool -> Ptr Word8 -> Ptr Word8 -> IO Bool - loop 0 !ret _ _ = return ret - loop i !ret p1 p2 = do - e <- (==) <$> peek p1 <*> peek p2 - loop (i-1) (ret &&! e) (p1 `plusPtr` 1) (p2 `plusPtr` 1) - - -- Bool == Bool - (&&!) :: Bool -> Bool -> Bool - True &&! True = True - True &&! False = False - False &&! True = False - False &&! False = False - -toBS :: ByteArray bs => bs -> ByteString -toBS bs = copyAndFreeze bs (\_ -> return ()) - -fromBS :: ByteArray bs => ByteString -> bs -fromBS bs = copyAndFreeze bs (\_ -> return ()) - -toW64BE :: ByteArrayAccess bs => bs -> Int -> Word64 -toW64BE bs ofs = unsafeDoIO $ withByteArray bs $ \p -> fromBE64 <$> peek (p `plusPtr` ofs) - -toW64LE :: ByteArrayAccess bs => bs -> Int -> Word64 -toW64LE bs ofs = unsafeDoIO $ withByteArray bs $ \p -> fromLE64 <$> peek (p `plusPtr` ofs) - -mapAsWord128 :: ByteArray bs => (Word128 -> Word128) -> bs -> bs -mapAsWord128 f bs = - allocAndFreeze len $ \dst -> - withByteArray bs $ \src -> - loop (len `div` 16) dst src - where - len = length bs - loop 0 _ _ = return () - loop i d s = do - w1 <- peek s - w2 <- peek (s `plusPtr` 8) - let (Word128 r1 r2) = f (Word128 (fromBE64 w1) (fromBE64 w2)) - poke d (toBE64 r1) - poke (d `plusPtr` 8) (toBE64 r2) - loop (i-1) (d `plusPtr` 16) (s `plusPtr` 16) - -mapAsWord64 :: ByteArray bs => (Word64 -> Word64) -> bs -> bs -mapAsWord64 f bs = - allocAndFreeze len $ \dst -> - withByteArray bs $ \src -> - loop (len `div` 8) dst src - where - len = length bs - loop 0 _ _ = return () - loop i d s = do - w <- peek s - let r = f (fromBE64 w) - poke d (toBE64 r) - loop (i-1) (d `plusPtr` 8) (s `plusPtr` 8) - -convert :: (ByteArrayAccess bin, ByteArray bout) => bin -> bout -convert = flip copyAndFreeze (\_ -> return ()) - -convertHex :: (ByteArrayAccess bin, ByteArray bout) => bin -> bout -convertHex b = - allocAndFreeze (length b * 2) $ \bout -> - withByteArray b $ \bin -> - toHexadecimal bout bin (length b) +import Data.Memory.ByteArray as X diff --git a/Crypto/Internal/Bytes.hs b/Crypto/Internal/Bytes.hs deleted file mode 100644 index 289293e..0000000 --- a/Crypto/Internal/Bytes.hs +++ /dev/null @@ -1,72 +0,0 @@ --- | --- Module : Crypto.Internal.Bytes --- License : BSD-style --- Maintainer : Vincent Hanquez --- Stability : experimental --- Portability : unknown --- --- internal helpers function to manipulate sequence of bytes --- like ByteString and buffer. --- -module Crypto.Internal.Bytes - ( withByteStringPtr - , tempBufCreate - , bufXor - , bufXorWith - , bufCopy - , bufSet - ) where - -import Crypto.Internal.Imports -import Foreign.Ptr (Ptr, plusPtr) -import Foreign.ForeignPtr (withForeignPtr) -import Foreign.Storable (peek, poke, pokeByteOff, peekByteOff) -import Foreign.Marshal.Alloc (allocaBytesAligned) -import Data.ByteString (ByteString) -import Data.Bits (xor) -import Data.ByteString.Internal (toForeignPtr) -import Data.ByteString.Internal (memcpy, memset) - -withByteStringPtr :: ByteString -> (Ptr Word8 -> IO a) -> IO a -withByteStringPtr b f = - withForeignPtr fptr $ \ptr -> f (ptr `plusPtr` off) - where (fptr, off, _) = toForeignPtr b - --- | Create a new temporary buffer -tempBufCreate :: Int -> (Ptr Word8 -> IO a) -> IO a -tempBufCreate size f = allocaBytesAligned size 8 f - --- | xor bytes from source1 and source2 to destination --- --- d = s1 xor s2 --- --- s1, nor s2 are modified unless d point to s1 or s2 -bufXor :: Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Int -> IO () -bufXor _ _ _ 0 = return () -bufXor d s1 s2 n = do - (xor <$> peek s1 <*> peek s2) >>= poke d - bufXor (d `plusPtr` 1) (s1 `plusPtr` 1) (s2 `plusPtr` 1) (n-1) - --- | xor bytes from source with a specific value to destination --- --- d = replicate (sizeof s) v `xor` s -bufXorWith :: Ptr Word8 -> Word8 -> Ptr Word8 -> Int -> IO () -bufXorWith d v s n = loop 0 - where - loop i - | i == n = return () - | otherwise = do - (xor v <$> peekByteOff s i) >>= pokeByteOff d i - loop (i+1) - -bufCopy :: Ptr Word8 -> Ptr Word8 -> Int -> IO () -bufCopy dst src n = memcpy dst src (fromIntegral n) - --- | Set @n number of bytes to the same value @v -bufSet :: Ptr Word8 -> Word8 -> Int -> IO () -bufSet start v n = memset start v (fromIntegral n) >>= \_ -> return () - {-loop 0 - where loop i - | i == n = return () - | otherwise = pokeByteOff start i v >> loop (i+1) --} diff --git a/Crypto/Internal/Memory.hs b/Crypto/Internal/Memory.hs deleted file mode 100644 index a4ae80e..0000000 --- a/Crypto/Internal/Memory.hs +++ /dev/null @@ -1,127 +0,0 @@ --- | --- Module : Crypto.Internal.Memory --- License : BSD-style --- Maintainer : Vincent Hanquez --- Stability : stable --- Portability : Good --- --- Simple and efficient byte array types --- -{-# LANGUAGE BangPatterns #-} -{-# LANGUAGE MagicHash #-} -{-# LANGUAGE UnboxedTuples #-} -module Crypto.Internal.Memory - ( Bytes - , bytesCopyAndModify - , bytesTemporary - , bytesCopyTemporary - , bytesAlloc - , bytesAllocRet - , bytesLength - , bytesIndex - , withBytes - , SecureBytes - ) where - -import GHC.Types -import GHC.Prim -import GHC.Word -import GHC.Ptr -import Foreign.Marshal.Utils (copyBytes) -import Data.SecureMem (SecureMem) -import Crypto.Internal.CompatPrim -import Crypto.Internal.Compat (unsafeDoIO) -import Crypto.Internal.Hex (showHexadecimal) - -data Bytes = Bytes (MutableByteArray# RealWorld) - -type SecureBytes = SecureMem - -instance Show Bytes where - show = bytesShowHex -instance Eq Bytes where - (==) = bytesEq - ------------------------------------------------------------------------- -newBytes :: Int -> IO Bytes -newBytes (I# sz) = IO $ \s -> - case newAlignedPinnedByteArray# sz 8# s of - (# s', mbarr #) -> (# s', Bytes mbarr #) - -touchBytes :: Bytes -> IO () -touchBytes (Bytes mba) = IO $ \s -> case touch# mba s of s' -> (# s', () #) - -sizeofBytes :: Bytes -> Int -sizeofBytes (Bytes mba) = I# (sizeofMutableByteArray# mba) - -withPtr :: Bytes -> (Ptr p -> IO a) -> IO a -withPtr b@(Bytes mba) f = do - a <- f (Ptr (byteArrayContents# (unsafeCoerce# mba))) - touchBytes b - return a ------------------------------------------------------------------------- - -bytesCopyAndModify :: Bytes -> (Ptr a -> IO ()) -> IO Bytes -bytesCopyAndModify src f = do - dst <- newBytes sz - withPtr dst $ \d -> do - withPtr src $ \s -> copyBytes (castPtr d) s sz - f d - return dst - where sz = sizeofBytes src - -bytesTemporary :: Int -> (Ptr p -> IO a) -> IO a -bytesTemporary sz f = newBytes sz >>= \ba -> withPtr ba f - -bytesCopyTemporary :: Bytes -> (Ptr p -> IO a) -> IO a -bytesCopyTemporary src f = do - dst <- newBytes (sizeofBytes src) - withPtr dst $ \d -> do - withPtr src $ \s -> copyBytes (castPtr d) s (sizeofBytes src) - f d - -bytesAlloc :: Int -> (Ptr p -> IO ()) -> IO Bytes -bytesAlloc sz f = do - ba <- newBytes sz - withPtr ba f - return ba - -bytesAllocRet :: Int -> (Ptr p -> IO a) -> IO (a, Bytes) -bytesAllocRet sz f = do - ba <- newBytes sz - r <- withPtr ba f - return (r, ba) - -bytesLength :: Bytes -> Int -bytesLength = sizeofBytes - -withBytes :: Bytes -> (Ptr p -> IO a) -> IO a -withBytes = withPtr - -bytesEq :: Bytes -> Bytes -> Bool -bytesEq b1@(Bytes m1) b2@(Bytes m2) - | l1 /= l2 = False - | otherwise = unsafeDoIO $ IO $ \s -> loop 0# s - where - !l1@(I# len) = bytesLength b1 - !l2 = bytesLength b2 - - loop i s - | booleanPrim (i ==# len) = (# s, True #) - | otherwise = - case readWord8Array# m1 i s of - (# s', e1 #) -> case readWord8Array# m2 i s' of - (# s'', e2 #) -> - if booleanPrim (eqWord# e1 e2) - then loop (i +# 1#) s'' - else (# s', False #) - -bytesIndex :: Bytes -> Int -> Word8 -bytesIndex (Bytes m) (I# i) = unsafeDoIO $ IO $ \s -> - case readWord8Array# m i s of - (# s', e #) -> (# s', W8# e #) -{-# NOINLINE bytesIndex #-} - -bytesShowHex :: Bytes -> String -bytesShowHex b = showHexadecimal (withPtr b) (bytesLength b) -{-# NOINLINE bytesShowHex #-} diff --git a/Crypto/Internal/Words.hs b/Crypto/Internal/Words.hs index 0cf9318..363aad0 100644 --- a/Crypto/Internal/Words.hs +++ b/Crypto/Internal/Words.hs @@ -15,9 +15,7 @@ module Crypto.Internal.Words import Data.Word import Data.Bits - --- should probably use crypto large word ? -data Word128 = Word128 !Word64 !Word64 deriving (Show, Eq) +import Data.Memory.ExtendedWords w64to32 :: Word64 -> (Word32, Word32) w64to32 w = (fromIntegral (w `shiftR` 32), fromIntegral w) diff --git a/Crypto/KDF/PBKDF2.hs b/Crypto/KDF/PBKDF2.hs index 6e9f09a..5a27e1f 100644 --- a/Crypto/KDF/PBKDF2.hs +++ b/Crypto/KDF/PBKDF2.hs @@ -27,7 +27,7 @@ import qualified Crypto.MAC.HMAC as HMAC import Crypto.Internal.ByteArray (ByteArray) import qualified Crypto.Internal.ByteArray as B (allocAndFreeze, convert, withByteArray) -import Crypto.Internal.Bytes +import Data.Memory.PtrMethods -- | The PRF used for PBKDF2 type PRF = B.ByteString -- ^ the password parameters @@ -54,7 +54,7 @@ data Parameters = Parameters generate :: ByteArray ba => PRF -> Parameters -> ba generate prf params = B.allocAndFreeze (outputLength params) $ \p -> do - bufSet p 0 (outputLength params) + memSet p 0 (outputLength params) loop 1 (outputLength params) p where !runPRF = prf (password params) @@ -74,7 +74,7 @@ generate prf params = let applyMany 0 _ = return () applyMany i uprev = do let uData = runPRF uprev - B.withByteArray uData $ \u -> bufXor p p u hLen + B.withByteArray uData $ \u -> memXor p p u hLen applyMany (i-1) uData applyMany (iterCounts params) (salt params `B.append` toBS iterNb) loop (iterNb+1) (len - hLen) (p `plusPtr` hLen) @@ -83,11 +83,11 @@ generate prf params = let applyMany 0 _ = return () applyMany i uprev = do let uData = runPRF uprev - B.withByteArray uData $ \u -> bufXor tmp tmp u hLen + B.withByteArray uData $ \u -> memXor tmp tmp u hLen applyMany (i-1) uData - bufSet tmp 0 hLen + memSet tmp 0 hLen applyMany (iterCounts params) (salt params `B.append` toBS iterNb) - bufCopy p tmp len + memCopy p tmp len -- big endian encoding of Word32 toBS :: Word32 -> ByteString diff --git a/Crypto/MAC/HMAC.hs b/Crypto/MAC/HMAC.hs index 17b72a0..860e866 100644 --- a/Crypto/MAC/HMAC.hs +++ b/Crypto/MAC/HMAC.hs @@ -24,9 +24,9 @@ module Crypto.MAC.HMAC import Crypto.Hash hiding (Context) import qualified Crypto.Hash as Hash (Context) import Crypto.Hash.IO -import Crypto.Internal.ByteArray (SecureBytes, ByteArray, ByteArrayAccess) +import Crypto.Internal.ByteArray (ScrubbedBytes, ByteArray, ByteArrayAccess) import qualified Crypto.Internal.ByteArray as B -import Crypto.Internal.Bytes +import Data.Memory.PtrMethods import Crypto.Internal.Compat import Crypto.Internal.Imports @@ -61,9 +61,9 @@ initialize secret = unsafeDoIO (doHashAlg undefined) !withKey <- case B.length secret `compare` blockSize of EQ -> return $ B.withByteArray secret LT -> do key <- B.alloc blockSize $ \k -> do - bufSet k 0 blockSize - B.withByteArray secret $ \s -> bufCopy k s (B.length secret) - return $ B.withByteArray (key :: SecureBytes) + memSet k 0 blockSize + B.withByteArray secret $ \s -> memCopy k s (B.length secret) + return $ B.withByteArray (key :: ScrubbedBytes) GT -> do -- hash the secret key ctx <- hashMutableInitWith alg @@ -74,16 +74,16 @@ initialize secret = unsafeDoIO (doHashAlg undefined) if digestSize < blockSize then do key <- B.alloc blockSize $ \k -> do - bufSet k 0 blockSize - B.withByteArray digest $ \s -> bufCopy k s (B.length digest) - return $ B.withByteArray (key :: SecureBytes) + memSet k 0 blockSize + B.withByteArray digest $ \s -> memCopy k s (B.length digest) + return $ B.withByteArray (key :: ScrubbedBytes) else return $ B.withByteArray digest (inner, outer) <- withKey $ \keyPtr -> - (,) <$> B.alloc blockSize (\p -> bufXorWith p 0x36 keyPtr blockSize) - <*> B.alloc blockSize (\p -> bufXorWith p 0x5c keyPtr blockSize) - return $ Context (hashUpdates initCtx [outer :: SecureBytes]) - (hashUpdates initCtx [inner :: SecureBytes]) + (,) <$> B.alloc blockSize (\p -> memXorWith p 0x36 keyPtr blockSize) + <*> B.alloc blockSize (\p -> memXorWith p 0x5c keyPtr blockSize) + return $ Context (hashUpdates initCtx [outer :: ScrubbedBytes]) + (hashUpdates initCtx [inner :: ScrubbedBytes]) where blockSize = hashBlockSize alg digestSize = hashDigestSize alg diff --git a/Crypto/MAC/Poly1305.hs b/Crypto/MAC/Poly1305.hs index 47d9038..ea80fea 100644 --- a/Crypto/MAC/Poly1305.hs +++ b/Crypto/MAC/Poly1305.hs @@ -26,11 +26,11 @@ module Crypto.MAC.Poly1305 import Foreign.Ptr import Foreign.C.Types import Data.Word -import Crypto.Internal.ByteArray (ByteArrayAccess, SecureBytes, Bytes) +import Crypto.Internal.ByteArray (ByteArrayAccess, ScrubbedBytes, Bytes) import qualified Crypto.Internal.ByteArray as B -- | Poly1305 Context -newtype Ctx = Ctx SecureBytes +newtype Ctx = Ctx ScrubbedBytes deriving (ByteArrayAccess) -- | Poly1305 Auth @@ -79,7 +79,7 @@ updates (Ctx prevCtx) d = Ctx $ B.copyAndFreeze prevCtx (loop d) -- | finalize the context into a digest bytestring finalize :: Ctx -> Auth finalize (Ctx prevCtx) = Auth $ B.allocAndFreeze 16 $ \dst -> do - _ <- B.copy prevCtx (\ctxPtr -> c_poly1305_finalize dst (castPtr ctxPtr)) :: IO SecureBytes + _ <- B.copy prevCtx (\ctxPtr -> c_poly1305_finalize dst (castPtr ctxPtr)) :: IO ScrubbedBytes return () {-# NOINLINE finalize #-} @@ -88,7 +88,7 @@ auth :: (ByteArrayAccess key, ByteArrayAccess ba) => key -> ba -> Auth auth key d | B.length key /= 32 = error "Poly1305: key length expected 32 bytes" | otherwise = Auth $ B.allocAndFreeze 16 $ \dst -> do - _ <- B.alloc 84 (onCtx dst) :: IO SecureBytes + _ <- B.alloc 84 (onCtx dst) :: IO ScrubbedBytes return () where onCtx dst ctxPtr = diff --git a/Crypto/PubKey/Curve25519.hs b/Crypto/PubKey/Curve25519.hs index 973c030..f25d124 100644 --- a/Crypto/PubKey/Curve25519.hs +++ b/Crypto/PubKey/Curve25519.hs @@ -28,11 +28,11 @@ import GHC.Ptr import Crypto.Internal.Compat import Crypto.Internal.Imports -import Crypto.Internal.ByteArray (ByteArrayAccess, SecureBytes, Bytes, withByteArray) +import Crypto.Internal.ByteArray (ByteArrayAccess, ScrubbedBytes, Bytes, withByteArray) import qualified Crypto.Internal.ByteArray as B -- | A Curve25519 Secret key -newtype SecretKey = SecretKey SecureBytes +newtype SecretKey = SecretKey ScrubbedBytes deriving (Show,Eq,ByteArrayAccess) -- | A Curve25519 public key @@ -41,7 +41,7 @@ newtype PublicKey = PublicKey Bytes -- | A Curve25519 Diffie Hellman secret related to a -- public key and a secret key. -newtype DhSecret = DhSecret SecureBytes +newtype DhSecret = DhSecret ScrubbedBytes deriving (Show,Eq,ByteArrayAccess) -- | Try to build a public key from a bytearray diff --git a/Crypto/PubKey/ECC/P256.hs b/Crypto/PubKey/ECC/P256.hs index 3b1e9ed..2dc1e8d 100644 --- a/Crypto/PubKey/ECC/P256.hs +++ b/Crypto/PubKey/ECC/P256.hs @@ -25,13 +25,13 @@ import Foreign.C.Types import Crypto.Internal.Compat import Crypto.Internal.Imports -import Crypto.Internal.Memory +--import Crypto.Internal.Memory import Crypto.Internal.ByteArray import qualified Crypto.Internal.ByteArray as B import Crypto.Error -- | A P256 scalar -newtype Scalar = Scalar SecureBytes +newtype Scalar = Scalar ScrubbedBytes deriving (Eq,ByteArrayAccess) -- | A P256 point diff --git a/Crypto/PubKey/Ed25519.hs b/Crypto/PubKey/Ed25519.hs index a648678..870f971 100644 --- a/Crypto/PubKey/Ed25519.hs +++ b/Crypto/PubKey/Ed25519.hs @@ -30,13 +30,12 @@ import Foreign.C.Types import Crypto.Internal.Compat import Crypto.Internal.Imports -import Crypto.Internal.Memory -import Crypto.Internal.ByteArray (ByteArrayAccess, withByteArray) +import Crypto.Internal.ByteArray (ByteArrayAccess, withByteArray, ScrubbedBytes, Bytes) import qualified Crypto.Internal.ByteArray as B import Crypto.Error -- | An Ed25519 Secret key -newtype SecretKey = SecretKey SecureBytes +newtype SecretKey = SecretKey ScrubbedBytes deriving (Eq,ByteArrayAccess) -- | An Ed25519 public key diff --git a/Crypto/Random.hs b/Crypto/Random.hs index d4a77e6..638f31c 100644 --- a/Crypto/Random.hs +++ b/Crypto/Random.hs @@ -20,11 +20,11 @@ module Crypto.Random import Crypto.Random.Types import Crypto.Random.ChaChaDRG import Crypto.Random.Entropy -import Crypto.Internal.Memory +import Data.Memory.ByteArray (ScrubbedBytes) import Crypto.Internal.Imports drgNew :: IO ChaChaDRG -drgNew = initialize <$> (getEntropy 40 :: IO SecureBytes) +drgNew = initialize <$> (getEntropy 40 :: IO ScrubbedBytes) drgNewTest :: (Word64, Word64, Word64, Word64, Word64) -> ChaChaDRG drgNewTest = initializeWords diff --git a/Crypto/Random/ChaChaDRG.hs b/Crypto/Random/ChaChaDRG.hs index f1cc31a..f102336 100644 --- a/Crypto/Random/ChaChaDRG.hs +++ b/Crypto/Random/ChaChaDRG.hs @@ -12,7 +12,7 @@ module Crypto.Random.ChaChaDRG ) where import Crypto.Random.Types -import Crypto.Internal.ByteArray (ByteArray, SecureBytes) +import Crypto.Internal.ByteArray (ByteArray, ScrubbedBytes) import qualified Crypto.Internal.ByteArray as B import Data.Word import Foreign.Storable (pokeElemOff) @@ -35,7 +35,7 @@ initialize seed = ChaChaDRG $ C.initializeSimple seed -- | Initialize a new ChaCha context from 5-tuple of words64. -- This interface is useful when creating a RNG out of tests generators (e.g. QuickCheck). initializeWords :: (Word64, Word64, Word64, Word64, Word64) -> ChaChaDRG -initializeWords (a,b,c,d,e) = initialize (B.allocAndFreeze 40 fill :: SecureBytes) +initializeWords (a,b,c,d,e) = initialize (B.allocAndFreeze 40 fill :: ScrubbedBytes) where fill s = mapM_ (uncurry (pokeElemOff s)) [(0,a), (1,b), (2,c), (3,d), (4,e)] generate :: ByteArray output => Int -> ChaChaDRG -> (output, ChaChaDRG) diff --git a/Crypto/Random/EntropyPool.hs b/Crypto/Random/EntropyPool.hs index 0d55d19..15e000b 100644 --- a/Crypto/Random/EntropyPool.hs +++ b/Crypto/Random/EntropyPool.hs @@ -14,7 +14,7 @@ module Crypto.Random.EntropyPool import Control.Concurrent.MVar import Crypto.Random.Entropy.Unsafe -import Crypto.Internal.ByteArray (ByteArray, SecureBytes) +import Crypto.Internal.ByteArray (ByteArray, ScrubbedBytes) import qualified Crypto.Internal.ByteArray as B import Data.Word (Word8) import Data.Maybe (catMaybes) @@ -23,7 +23,7 @@ import Foreign.Ptr (plusPtr, Ptr) -- | Pool of Entropy. contains a self mutating pool of entropy, -- that is always guarantee to contains data. -data EntropyPool = EntropyPool [EntropyBackend] (MVar Int) SecureBytes +data EntropyPool = EntropyPool [EntropyBackend] (MVar Int) ScrubbedBytes -- size of entropy pool by default defaultPoolSize :: Int diff --git a/cryptonite.cabal b/cryptonite.cabal index 3b5ac23..d5c53a8 100644 --- a/cryptonite.cabal +++ b/cryptonite.cabal @@ -88,7 +88,6 @@ Library Crypto.Random.Entropy Crypto.Random.EntropyPool Crypto.Random.Entropy.Unsafe - Crypto.Internal.ByteArray Other-modules: Crypto.Cipher.AES.Primitive Crypto.Cipher.Blowfish.Box Crypto.Cipher.Blowfish.Primitive @@ -125,13 +124,11 @@ Library Crypto.Random.ChaChaDRG Crypto.PubKey.Internal Crypto.PubKey.ElGamal + Crypto.Internal.ByteArray Crypto.Internal.Compat Crypto.Internal.CompatPrim - Crypto.Internal.Bytes - Crypto.Internal.Endian Crypto.Internal.Hex Crypto.Internal.Imports - Crypto.Internal.Memory Crypto.Internal.Words Crypto.Internal.WordArray Build-depends: base >= 4.3 && < 5 diff --git a/tests/BlockCipher.hs b/tests/BlockCipher.hs index 1e8dbfd..e8adecf 100644 --- a/tests/BlockCipher.hs +++ b/tests/BlockCipher.hs @@ -16,7 +16,7 @@ import Imports import Data.Maybe import Crypto.Error import Crypto.Cipher.Types -import Crypto.Internal.ByteArray as B +import Data.Memory.ByteArray as B import qualified Data.ByteString as B ------------------------------------------------------------------------ diff --git a/tests/Hash.hs b/tests/Hash.hs index a8d497f..75093ef 100644 --- a/tests/Hash.hs +++ b/tests/Hash.hs @@ -8,7 +8,7 @@ module Hash import Crypto.Hash import qualified Data.ByteString as B -import qualified Crypto.Internal.ByteArray as B (convertHex) +import qualified Data.Memory.ByteArray as B (convertHex) import Imports v0,v1,v2 :: ByteString diff --git a/tests/KAT_Curve25519.hs b/tests/KAT_Curve25519.hs index 283654e..6fce0f7 100644 --- a/tests/KAT_Curve25519.hs +++ b/tests/KAT_Curve25519.hs @@ -2,7 +2,7 @@ module KAT_Curve25519 ( tests ) where import qualified Crypto.PubKey.Curve25519 as Curve25519 -import Crypto.Internal.ByteArray as B +import Data.Memory.ByteArray as B import Imports alicePrivate = either error id $ Curve25519.secretKey ("\x77\x07\x6d\x0a\x73\x18\xa5\x7d\x3c\x16\xc1\x72\x51\xb2\x66\x45\xdf\x4c\x2f\x87\xeb\xc0\x99\x2a\xb1\x77\xfb\xa5\x1d\xb9\x2c\x2a" :: ByteString) diff --git a/tests/Tests.hs b/tests/Tests.hs index 495fc81..7fe9399 100644 --- a/tests/Tests.hs +++ b/tests/Tests.hs @@ -9,7 +9,7 @@ import Imports import qualified Crypto.Cipher.ChaCha as ChaCha import qualified Crypto.Cipher.Salsa as Salsa import qualified Crypto.MAC.Poly1305 as Poly1305 -import qualified Crypto.Internal.ByteArray as B (convert) +import qualified Data.Memory.ByteArray as B (convert) import qualified Hash import qualified KAT_HMAC