raaz 0.0.1 → 0.0.2
raw patch · 20 files changed
+594/−165 lines, 20 filesdep ~raaz
Dependency ranges changed: raaz
Files
- Raaz.hs +5/−5
- Raaz/Cipher/AES/CBC/Implementation/CPortable.hs +12/−12
- Raaz/Cipher/AES/Internal.hs +19/−19
- Raaz/Core/ByteSource.hs +23/−3
- Raaz/Core/Encode.hs +40/−25
- Raaz/Core/Encode/Base16.hs +16/−7
- Raaz/Core/Encode/Base64.hs +171/−0
- Raaz/Core/Encode/Internal.hs +46/−21
- Raaz/Core/Memory.hs +47/−16
- Raaz/Core/Primitives.hs +1/−1
- Raaz/Core/Types.hs +53/−26
- Raaz/Core/Types/Endian.hs +1/−1
- Raaz/Core/Types/Equality.hs +75/−9
- Raaz/Hash/Internal/HMAC.hs +3/−3
- raaz.cabal +7/−4
- spec/Common/Imports.hs +19/−0
- spec/Common/Instances.hs +3/−0
- spec/Raaz/Core/Encode/Base16Spec.hs +0/−13
- spec/Raaz/Core/EncodeSpec.hs +41/−0
- spec/Raaz/Core/SystemPRGSpec.hs +12/−0
Raaz.hs view
@@ -2,18 +2,18 @@ -- By importing this module you get a rather high-level access to the -- primitives provided by the library. module Raaz- ( version- , module Raaz.Cipher+ ( module Raaz.Cipher , module Raaz.Core , module Raaz.Hash+ , version ) where import Data.Version (Version) import qualified Paths_raaz as P -import Raaz.Core-import Raaz.Hash-import Raaz.Cipher+import Raaz.Core+import Raaz.Hash+import Raaz.Cipher -- | Raaz library version number.
Raaz/Cipher/AES/CBC/Implementation/CPortable.hs view
@@ -70,11 +70,11 @@ ------------------- 128-bit CBC Implementation ---------------- -- | Implementation of 128-bit AES in CBC mode using Portable C.-aes128cbcI :: Implementation (AES 128 CBC)+aes128cbcI :: Implementation (AES 128 'CBC) aes128cbcI = SomeCipherI cbc128CPortable -- | 128-bit AES in CBC mode using Portable C.-cbc128CPortable :: CipherI (AES 128 CBC) M128 M128+cbc128CPortable :: CipherI (AES 128 'CBC) M128 M128 cbc128CPortable = CipherI { cipherIName = "aes128cbc-cportable" , cipherIDescription =@@ -84,14 +84,14 @@ } -- | The encryption action.-cbc128Encrypt :: Pointer -> BLOCKS (AES 128 CBC) -> MT M128 ()+cbc128Encrypt :: Pointer -> BLOCKS (AES 128 'CBC) -> MT M128 () cbc128Encrypt buf nBlocks = do eKeyPtr <- liftSubMT m128ekey getMemoryPointer ivPtr <- liftSubMT m128iv getMemoryPointer liftIO $ c_aes_cbc_e buf (fromEnum nBlocks) 10 eKeyPtr ivPtr -- | The decryption action.-cbc128Decrypt :: Pointer -> BLOCKS (AES 128 CBC) -> MT M128 ()+cbc128Decrypt :: Pointer -> BLOCKS (AES 128 'CBC) -> MT M128 () cbc128Decrypt buf nBlocks = do eKeyPtr <- liftSubMT m128ekey getMemoryPointer ivPtr <- liftSubMT m128iv getMemoryPointer@@ -102,11 +102,11 @@ ------------------- 192-bit CBC Implementation ---------------- -- | Implementation of 192-bit AES in CBC mode using Portable C.-aes192cbcI :: Implementation (AES 192 CBC)+aes192cbcI :: Implementation (AES 192 'CBC) aes192cbcI = SomeCipherI cbc192CPortable -- | 192-bit AES in CBC mode using Portable C.-cbc192CPortable :: CipherI (AES 192 CBC) M192 M192+cbc192CPortable :: CipherI (AES 192 'CBC) M192 M192 cbc192CPortable = CipherI { cipherIName = "aes192cbc-cportable" , cipherIDescription =@@ -116,14 +116,14 @@ } -- | The encryption action.-cbc192Encrypt :: Pointer -> BLOCKS (AES 192 CBC) -> MT M192 ()+cbc192Encrypt :: Pointer -> BLOCKS (AES 192 'CBC) -> MT M192 () cbc192Encrypt buf nBlocks = do eKeyPtr <- liftSubMT m192ekey getMemoryPointer ivPtr <- liftSubMT m192iv getMemoryPointer liftIO $ c_aes_cbc_e buf (fromEnum nBlocks) 12 eKeyPtr ivPtr -- | The decryption action.-cbc192Decrypt :: Pointer -> BLOCKS (AES 192 CBC) -> MT M192 ()+cbc192Decrypt :: Pointer -> BLOCKS (AES 192 'CBC) -> MT M192 () cbc192Decrypt buf nBlocks = do eKeyPtr <- liftSubMT m192ekey getMemoryPointer ivPtr <- liftSubMT m192iv getMemoryPointer@@ -132,11 +132,11 @@ ------------------- 256-bit CBC Implementation ---------------- -- | Implementation of 256-bit AES in CBC mode using Portable C.-aes256cbcI :: Implementation (AES 256 CBC)+aes256cbcI :: Implementation (AES 256 'CBC) aes256cbcI = SomeCipherI cbc256CPortable -- | 256-bit AES in CBC mode using Portable C.-cbc256CPortable :: CipherI (AES 256 CBC) M256 M256+cbc256CPortable :: CipherI (AES 256 'CBC) M256 M256 cbc256CPortable = CipherI { cipherIName = "aes256cbc-cportable" , cipherIDescription =@@ -146,14 +146,14 @@ } -- | The encryption action.-cbc256Encrypt :: Pointer -> BLOCKS (AES 256 CBC) -> MT M256 ()+cbc256Encrypt :: Pointer -> BLOCKS (AES 256 'CBC) -> MT M256 () cbc256Encrypt buf nBlocks = do eKeyPtr <- liftSubMT m256ekey getMemoryPointer ivPtr <- liftSubMT m256iv getMemoryPointer liftIO $ c_aes_cbc_e buf (fromEnum nBlocks) 14 eKeyPtr ivPtr -- | The decryption action.-cbc256Decrypt :: Pointer -> BLOCKS (AES 256 CBC) -> MT M256 ()+cbc256Decrypt :: Pointer -> BLOCKS (AES 256 'CBC) -> MT M256 () cbc256Decrypt buf nBlocks = do eKeyPtr <- liftSubMT m256ekey getMemoryPointer ivPtr <- liftSubMT m256iv getMemoryPointer
Raaz/Cipher/AES/Internal.hs view
@@ -102,59 +102,59 @@ ----------------- AES 128 CBC ------------------------------ -- | 128-bit aes cipher in `CBC` mode.-aes128cbc :: AES 128 CBC+aes128cbc :: AES 128 'CBC aes128cbc = AES -- | The 128-bit aes cipher in cbc mode.-instance Primitive (AES 128 CBC) where+instance Primitive (AES 128 'CBC) where blockSize _ = BYTES 16- type Implementation (AES 128 CBC) = SomeCipherI (AES 128 CBC)+ type Implementation (AES 128 'CBC) = SomeCipherI (AES 128 'CBC) -- | Key is @(`KEY128`,`IV`)@ pair.-instance Symmetric (AES 128 CBC) where- type Key (AES 128 CBC) = (KEY128,IV)+instance Symmetric (AES 128 'CBC) where+ type Key (AES 128 'CBC) = (KEY128,IV) -instance Cipher (AES 128 CBC)+instance Cipher (AES 128 'CBC) ----------------- AES 192 CBC -------------------------------- -- | 128-bit aes cipher in `CBC` mode.-aes192cbc :: AES 192 CBC+aes192cbc :: AES 192 'CBC aes192cbc = AES -- | The 192-bit aes cipher in cbc mode.-instance Primitive (AES 192 CBC) where+instance Primitive (AES 192 'CBC) where blockSize _ = BYTES 16- type Implementation (AES 192 CBC) = SomeCipherI (AES 192 CBC)+ type Implementation (AES 192 'CBC) = SomeCipherI (AES 192 'CBC) -- | Key is @(`KEY192`,`IV`)@ pair.-instance Symmetric (AES 192 CBC) where- type Key (AES 192 CBC) = (KEY192,IV)+instance Symmetric (AES 192 'CBC) where+ type Key (AES 192 'CBC) = (KEY192,IV) -instance Cipher (AES 192 CBC)+instance Cipher (AES 192 'CBC) ------------------- AES 256 CBC ----------------------------- -- | 128-bit aes cipher in `CBC` mode.-aes256cbc :: AES 256 CBC+aes256cbc :: AES 256 'CBC aes256cbc = AES -- | The 256-bit aes cipher in cbc mode.-instance Primitive (AES 256 CBC) where+instance Primitive (AES 256 'CBC) where blockSize _ = BYTES 16- type Implementation (AES 256 CBC) = SomeCipherI (AES 256 CBC)+ type Implementation (AES 256 'CBC) = SomeCipherI (AES 256 'CBC) -- | Key is @(`KEY256`,`IV`)@ pair.-instance Symmetric (AES 256 CBC) where- type Key (AES 256 CBC) = (KEY256,IV)+instance Symmetric (AES 256 'CBC) where+ type Key (AES 256 'CBC) = (KEY256,IV) -instance Cipher (AES 256 CBC)+instance Cipher (AES 256 'CBC) ------------------- AES CTR mode --------------------------- -- | Smart constructors for AES 128 ctr.-aes128ctr :: AES 128 CTR+aes128ctr :: AES 128 'CTR aes128ctr = AES -------------- Memory for storing extended keys ---------
Raaz/Core/ByteSource.hs view
@@ -2,10 +2,12 @@ {-# LANGUAGE DefaultSignatures #-} -- | Module define byte sources. module Raaz.Core.ByteSource- ( ByteSource(..), fill, processChunks- , InfiniteSource(..), slurp- , PureByteSource+ ( -- * Byte sources.+ -- $bytesource$+ InfiniteSource(..)+ , ByteSource(..), PureByteSource , FillResult(..)+ , fill, slurp, processChunks , withFillResult ) where @@ -26,6 +28,23 @@ ) import Raaz.Core.Types.Pointer (hFillBuf) +-- $bytesource$+--+-- Cryptographic input come from various sources; they can come from+-- network sockets or might be just a string in the Haskell. To give a+-- uniform interfaces for all such inputs, we define the abstract+-- concept of a /byte source/. Essentially a byte source is one from+-- which we can fill a buffer with bytes. Depending on the nature of+-- the source we have two classes: `ByteSource` which captures bounded+-- sources and `InfiniteSource` that captures never ending source of+-- bytes.+--+-- Among instances of `ByteSource`, some like for example+-- `B.ByteString` are /pure/ in the sense filling a buffer with bytes+-- from such a source has no other side-effects. This is in contrast+-- to a source like a sockets. The type class `PureByteSource`+-- captures such byte sources.+-- -- | This type captures the result of a fill operation. data FillResult a = Remaining a -- ^ the buffer is filled completely@@ -77,6 +96,7 @@ fill = fillBytes . inBytes {-# INLINE fill #-} +-- | A version of slurp that takes type safe lengths as input. slurp :: ( LengthUnit len , InfiniteSource src )
Raaz/Core/Encode.hs view
@@ -1,40 +1,55 @@--- module Raaz.Core.Encode- ( -- * The encodable type+ ( -- * Encoding of binary data. -- $encodable$ Encodable(..)- -- * Encoding formats- -- $encodingformat$ , Format(..)- , encode, decode, unsafeDecode- -- ** The base 16 encoding fromat- , Base16, fromBase16, showBase16+ , encode, decode, translate, unsafeDecode+ -- ** The base 16 encoding format+ , Base16+ , fromBase16, showBase16+ -- ** Other binary formats.+ , Base64 ) where import Raaz.Core.Encode.Internal import Raaz.Core.Encode.Base16+import Raaz.Core.Encode.Base64 -- $encodable$ ----- Many types like cryptographic hashes, secret keys etc can be--- encoded into bytes. This module gives an interface to such objects--- using the `Encodable` type class. To ease their printing most types--- of this class have a `Show` instances. Similarly, to make it easy--- to defines constants of these types in source code, they often are--- instances of `Data.String.IsString`. Typically for cryptographic--- types like hashes, secret keys etc the `Show` and--- `Data.String.IsString` instances correspond to the base-16 encoding--- of these types.+-- Often one wants to represent cryptographic hashes, secret keys or+-- just binary data into various enocoding formats like base64,+-- hexadecimal etc. This module gives a generic interface for all such+-- operations. There are two main classes that capture the essence of+-- encoding.+--+-- [`Format`] Each encoding supported by this module is an instance of+-- this class. For printing and for easy inclusion in source code+-- appropriate instances of `Show` and `Data.String.IsString` is+-- provided for these types.+--+-- [`Encodable`] Instances of this class are those that can be encoded+-- into any of the available formats. Actual encoding and decoding+-- of elements of this class can be done by the combinators+-- `encode` and `decode`+--+-- The raaz library exposes many instances of `Format` which are all+-- some form of encoding of binary data.+-- +-- | Encode in a given format.+encode :: (Encodable a, Format fmt) => a -> fmt+encode = encodeByteString . toByteString +-- | Decode from a given format. It results in Nothing if there is a+-- parse error.+decode :: (Format fmt, Encodable a) => fmt -> Maybe a+decode = fromByteString . decodeFormat +-- | The unsafe version of `decode`.+unsafeDecode :: (Format fmt, Encodable a) => fmt -> a+unsafeDecode = unsafeFromByteString . decodeFormat --- $encodingformat$------ We also give facilities to encode any instance of `Encodable` into--- multiple formats. For type safety, encoding formats are--- distinguished by their types. All such formats have to be members--- of the `Format` type class and this allows encoding and decoding--- any type that is an instance of `Encodable` into any of the desired--- format.---+-- | Translate from one format to another.+translate :: (Format fmt1, Format fmt2) => fmt1 -> fmt2+translate = encodeByteString . decodeFormat
Raaz/Core/Encode/Base16.hs view
@@ -1,6 +1,9 @@ -- | Base 16 or hexadecimal encoding of objects. {-# LANGUAGE GeneralizedNewtypeDeriving #-}-module Raaz.Core.Encode.Base16( Base16, fromBase16, showBase16 ) where+module Raaz.Core.Encode.Base16+ ( Base16+ , fromBase16, showBase16+ ) where import Data.Char import Data.Bits@@ -15,7 +18,12 @@ import Data.Word import Raaz.Core.Encode.Internal --- | The base16 type.+-- | The type corresponding to base-16 or hexadecimal encoding. The+-- `Base16` encoding has a special place in this library: most+-- cryptographic types use `Base16` encoding for their `Show` and+-- `IsString` instance. The combinators `fromBase16` and `showBase16`+-- are exposed mainly to make these definitions easy.+-- newtype Base16 = Base16 {unBase16 :: ByteString} deriving (Eq, Monoid) -- Developers note: Internally base16 just stores the bytestring as@@ -29,7 +37,7 @@ | odd (B.length bs) = Nothing | badCharacter bs = Nothing | otherwise = Just $ Base16 $ unsafeFromHex bs- where badCharacter = C8.all (not . isHexDigit)+ where badCharacter = C8.any (not . isHexDigit) unsafeFromByteString = Base16 . unsafeFromHex @@ -66,8 +74,9 @@ unsafeFromHex :: ByteString -> ByteString-unsafeFromHex bs | odd (B.length bs) = error "base16 encoding is always of even size"- | otherwise = fst $ B.unfoldrN len gen 0+unsafeFromHex bs+ | odd (B.length bs) = error "base16 encoding is always of even size"+ | otherwise = fst $ B.unfoldrN len gen 0 where len = B.length bs `quot` 2 gen i = Just (shiftL w0 4 .|. w1, i + 1) where w0 = fromHexWord $ unsafeIndex bs (2 * i)@@ -83,8 +92,8 @@ -- `IsString` instances as well as in cases where the default -- `IsString` instance does not parse from a base16 encoding. fromBase16 :: Encodable a => String -> a-fromBase16 str = unsafeDecode (fromString str :: Base16)+fromBase16 = unsafeFromByteString . unBase16 . fromString -- | Base16 variant of `show`. showBase16 :: Encodable a => a -> String-showBase16 a = show (encode a :: Base16)+showBase16 = show . Base16 . toByteString
+ Raaz/Core/Encode/Base64.hs view
@@ -0,0 +1,171 @@+-- | Base 64 encoding of objects.+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+module Raaz.Core.Encode.Base64( Base64 ) where++import Data.Char+import Data.Bits+import Data.String++import Data.ByteString as B+import Data.ByteString.Char8 as C8+import Data.ByteString.Internal (c2w, w2c)++import Data.ByteString.Unsafe(unsafeIndex)+import Data.Monoid+import Data.Word+import Raaz.Core.Encode.Internal+++-- | The type corresponding to the standard padded base-64 binary+-- encoding.+newtype Base64 = Base64 {unBase64 :: ByteString} deriving (Eq, Monoid)++-- Developers note: Internally base16 just stores the bytestring as+-- is. The conversion happens when we do an encode and decode of+-- actual base16.++instance Encodable Base64 where+ toByteString = toB64 . unBase64++ fromByteString bs+ | B.null bs = Just $ Base64 B.empty+ | B.length bs `rem` 4 /= 0 = Nothing+ | badCharacter bs' = Nothing+ | not (isB64OrPad pl) = Nothing+ | not (isB64OrPad pf) = Nothing+ | otherwise = Just $ Base64 $ unsafeFromB64 bs+ where pl = C8.last bs+ pf = C8.last $ C8.init bs+ bs' = C8.init $ C8.init bs+ badCharacter = C8.any (not . isB64Char)+ isB64Char c = isAlpha c || isDigit c || c == '+' || c == '/'+ isB64OrPad c = isB64Char c || c == '='++ unsafeFromByteString bs | B.null bs = Base64 B.empty+ | otherwise = Base64 $ unsafeFromB64 bs+++instance Show Base64 where+ show = C8.unpack . toByteString++instance IsString Base64 where+ fromString = unsafeFromByteString . fromString+++instance Format Base64 where+ encodeByteString = Base64+ {-# INLINE encodeByteString #-}++ decodeFormat = unBase64+ {-# INLINE decodeFormat #-}++++------------- Base 64 encoding -------------------------++-- NOTE: The topN functions ensure that the top N bits of a word are present+-- in the least N significant bits. The botN ensures that there++top6 :: Word8 -> Word8; bot2 :: Word8 -> Word8+top4 :: Word8 -> Word8; bot4 :: Word8 -> Word8+top2 :: Word8 -> Word8; bot6 :: Word8 -> Word8++top6 w = w `shiftR` 2; bot2 w = w .&. 0x03+top4 w = w `shiftR` 4; bot4 w = w .&. 0x0F+top2 w = w `shiftR` 6; bot6 w = w .&. 0x3F++--------------- Combining bytes -----------------------------------++byte0 :: Word8 -> Word8+byte1 :: Word8 -> Word8 -> Word8+byte2 :: Word8 -> Word8 -> Word8+byte3 :: Word8 -> Word8+pad :: Word8+++byte0 = b64 . top6+byte1 t p = b64 $ shiftL (bot2 p) 4 .|. top4 t+byte2 t p = b64 $ shiftL (bot4 p) 2 .|. top2 t+byte3 = b64 . bot6+pad = c2w '='++-- | Encoding word.+b64 :: Word8 -> Word8+b64 w | 0 <= w && w <= 25 = c2w 'A' + w+ | 26 <= w && w <= 51 = c2w 'a' + w - 26+ | 52 <= w && w <= 61 = c2w '0' + w - 52+ | w == 62 = c2w '+'+ | w == 63 = c2w '/'+ | otherwise = error "oops: b64"+++unB64 :: Word8 -> Word8+unB64 w | c2w 'A' <= w && w <= c2w 'Z' = w - c2w 'A'+ | c2w 'a' <= w && w <= c2w 'z' = w - c2w 'a' + 26+ | c2w '0' <= w && w <= c2w '9' = w - c2w '0' + 52+ | w == c2w '+' = 62+ | w == c2w '/' = 63+ | otherwise = error $ "oops unB64:" ++ [w2c w]+++-- TODO: Since the encoding to base16 is usually used for user interaction+-- we can afford to be slower here.+toB64 :: ByteString -> ByteString+toB64 bs = fst (B.unfoldrN (4*n) gen 0) <> padding+ where gen i = Just (byte i, i + 1)+ at blk i = unsafeIndex bs $ 3 * blk + i++ byte i = case r of+ 0 -> byte0 $ at q 0+ 1 -> byte1 (at q 1) $ at q 0+ 2 -> byte2 (at q 2) $ at q 1+ 3 -> byte3 $ at q 2+ _ -> error "base64 bad index"+ where (q, r) = quotRem i 4++ (n,p) = B.length bs `quotRem` 3++ padding = case p of+ 0 -> mempty+ 1 -> B.pack [ byte0 $ at n 0+ , byte1 0 $ at n 0+ , pad, pad+ ]+ 2 -> B.pack [ byte0 $ at n 0+ , byte1 (at n 1) $ at n 0+ , byte2 0 $ at n 1+ , pad+ ]+ _ -> error "base64 pad bad index"++-- Notes: Merge is used to convert from base64 digits, which are+-- words of 6-bits.+merg0 :: Word8 -> Word8 -> Word8+merg1 :: Word8 -> Word8 -> Word8+merg2 :: Word8 -> Word8 -> Word8+merg0 a b = (unB64 a `shiftL` 2) .|. top4 (unB64 b)+merg1 a b = (unB64 a `shiftL` 4) .|. top6 (unB64 b)+merg2 a b = (unB64 a `shiftL` 6) .|. unB64 b++unsafeFromB64 :: ByteString -> ByteString+unsafeFromB64 bs = fst (B.unfoldrN (3*n) gen 0) <> unPad+ where n = B.length bs `quot` 4 - 1+ gen i = Just (byte i, i + 1)+ at blk i = unsafeIndex bs $ 4 * blk + i++ byte i = case r of+ 0 -> merg0 (at q 0) $ at q 1+ 1 -> merg1 (at q 1) $ at q 2+ 2 -> merg2 (at q 2) $ at q 3+ _ -> error "base64 bad index"+ where (q, r) = quotRem i 3++ unPad+ | at n 2 == c2w '=' = B.singleton $ merg0 (at n 0) $ at n 1+ | at n 3 == c2w '=' = B.pack [ merg0 (at n 0) $ at n 1+ , merg1 (at n 1) $ at n 2+ ]+ | otherwise = B.pack [ merg0 (at n 0) $ at n 1+ , merg1 (at n 1) $ at n 2+ , merg2 (at n 2) $ at n 3+ ]
Raaz/Core/Encode/Internal.hs view
@@ -5,10 +5,8 @@ -- | Internal module that has the encode class and some utility functions. module Raaz.Core.Encode.Internal ( Encodable(..), Format(..)- , encode, decode, unsafeDecode ) where - import Data.Maybe import Data.ByteString (ByteString)@@ -25,7 +23,21 @@ import Raaz.Core.Util.ByteString(length, withByteString) --- | The type class `Encodable` captures all the types can be encoding into `ByteString`.+-- | The type class `Encodable` captures all the types that can be+-- encoded into a stream of bytes. By making a type say @Foo@ an+-- instance of the `Encodable` class, we get for free methods to+-- encode it in any of the supported formats (i.e. instances of the+-- class `Format`).+--+-- Minimum complete definition for this class is `toByteString` and+-- `fromByteString`. Instances of `EndianStore` have default+-- definitions for both these functions and hence a trivial instance+-- declaration is sufficient for such types.+--+-- >+-- > instance Encodable Foo+-- >+-- class Encodable a where -- | Convert stuff to bytestring toByteString :: a -> ByteString@@ -75,12 +87,39 @@ unsafeFromByteString = BYTES . unsafeFromByteString --- | A binary encoding format is something for which there is a 1:1--- correspondence with bytestrings. We also insist that it is an--- instance of `IsString`, so that it can be easily included in source--- code, and `Show`, so that it can be easily printed out.++-- | A binary format is a representation of binary data often in+-- printable form. We distinguish between various binary formats at+-- the type level and each supported format corresponds to an instance+-- of the the class `Format`. The `encodeByteString` and+-- `decodeFormat` are required to satisfy the laws+--+-- > decodeFormat . encodeByteString = id+--+-- For type safety, the formats themselves are opaque types and hence+-- it is not possible to obtain the underlying binary data directly.+-- We require binary formats to be instances of the class `Encodable`,+-- with the combinators `toByteString` and `fromByteString` of the+-- `Encodable` class performing the actual encoding and decoding.+--+-- Instances of `Format` are required to be instances of `Show` and so+-- that the encoded format can be easily printed. They are also+-- required to be instances of `IsString` so that they can be easily+-- represented in Haskell source using the @OverloadedStrings@+-- extension. However, be careful when using this due to the fact+-- that invalid encodings can lead to runtime errors.+-- class (IsString fmt, Show fmt, Encodable fmt) => Format fmt where++ -- | Encode binary data into the format. The return type gurantees+ -- that any binary data can indeed be encoded into a format. encodeByteString :: ByteString -> fmt++ -- | Decode the format to its associated binary+ -- representation. Notice that this function always succeeds: we+ -- assume that elements of the type `fmt` are valid encodings and+ -- hence the return type is `ByteString` instead of @`Maybe`+ -- ByteString@. decodeFormat :: fmt -> ByteString -- | Bytestring itself is an encoding format (namely binary format).@@ -89,17 +128,3 @@ {-# INLINE encodeByteString #-} decodeFormat = id {-# INLINE decodeFormat #-}----- | Encode in a given format.-encode :: (Encodable a, Format fmt) => a -> fmt-encode = encodeByteString . toByteString---- | Decode from a given format. It results in Nothing if there is a--- parse error.-decode :: (Format fmt, Encodable a) => fmt -> Maybe a-decode = fromByteString . decodeFormat---- | The unsafe version of `decode`.-unsafeDecode :: (Format fmt, Encodable a) => fmt -> a-unsafeDecode = unsafeFromByteString . decodeFormat
Raaz/Core/Memory.hs view
@@ -13,21 +13,22 @@ module Raaz.Core.Memory (- -- * The Memory subsystem+ -- * The Memory subsystem. -- $memorysubsystem$-- -- ** Memory monads- MonadMemory(..)- , MT, execute, getMemory, liftSubMT- , MemoryM, runMT- -- *** Some low level functions.+ -- ** Memory elements+ Memory(..), copyMemory+ -- *** A basic memory cell.+ , MemoryCell+ -- *** Initialising and extracting.+ , Initialisable(..), Extractable(..)+ -- *** Actions on memory elements.+ , MT, execute, getMemory, liftSubMT, modify+ -- **** Some low level `MT` actions. , getMemoryPointer, withPointer , allocate- -- ** Memory elements.- , Memory(..), copyMemory- , Initialisable(..), Extractable(..), modify- -- *** Some basic memory elements.- , MemoryCell+ -- ** Generic memory monads.+ , MonadMemory(..)+ , MemoryM, runMT -- ** Memory allocation , Alloc, pointerAlloc ) where@@ -44,10 +45,33 @@ -- -- The memory subsystem consists of two main components. ----- 1. Abstract elements captured by the `Memory` type class.+-- [The `Memory` type class] A memory element is some type that holds+-- an internal buffer inside it. The operations that are allowed on+-- the element is controlled by the associated type. Certain memory+-- element have a default way in which it can be initialised by values+-- of type @a@. An instance declaration @`Initialisable` mem a@ for+-- the memory type @mem@ is done in such case. Similary, if values of+-- type @b@ can be extracted out of a memory element @mem@, we can+-- indicate it with an instance of @`Extractable` mem a@. ----- 2. Abstract memory actions captured by the type class `MonadMemory`.+-- [The `Alloc` type and memory allocation] The most important and+-- often error prone operation while using low level memory buffers is+-- its allocation. The `Alloc` types gives the allocation strategy for+-- a memory element keeping track of the necessary book keeping+-- involved in it. The `Alloc` type is an instance of `Applicative`+-- which helps build the allocation strategy for a compound memory+-- type from its components in a modular fashion without any explicit+-- size calculation or offset computation. --+-- [The `MonadMemory` class] Instances of these classes are actions+-- that use some kind of memory elements, i.e. instances of the class+-- `Memory`, inside it. Any such monad can either be run using the+-- combinator `securely` or the combinator `insecurely`. If one use+-- the combinator `securely`, then all allocations done during the run+-- is from a locked memory pool which is wiped clean before+-- de-allocation. The types `MT` and `MemoryM` are two instances that+-- we expose from this library.+-- -- | A class that captures monads that use an internal memory element. --@@ -338,7 +362,7 @@ -- essentially a limitation of the bracket which is used internally. withSecureMemory :: Memory m => (m -> IO a) -> IO a withSecureMemory = withSM memoryAlloc- where withSM :: Memory m => Alloc m -> (m -> IO a) -> IO a+ where -- withSM :: Memory m => Alloc m -> (m -> IO a) -> IO a withSM alctr action = allocaSecure sz $ action . getM where sz = getSum $ twistMonoidValue alctr getM = computeField $ twistFunctorValue alctr@@ -356,7 +380,14 @@ withCell fp = execute $ fp . unMemoryCell {-# INLINE withCell #-} --- | Apply the given function to the value in the cell.+-- | Apply the given function to the value in the cell. For a function @f :: b -> a@,+-- the action @modify f@ first extracts a value of type @b@ from the+-- memory element, applies @f@ to it and puts the result back into the+-- memory.+--+-- > modify f = do b <- extract+-- > initialise $ f b+-- modify :: (Initialisable m a, Extractable m b) => (b -> a) -> MT m () modify f = extract >>= initialise . f
Raaz/Core/Primitives.hs view
@@ -91,5 +91,5 @@ -- | The expression @n `blocksOf` p@ specifies the message lengths in -- units of the block length of the primitive @p@. This expression is -- sometimes required to make the type checker happy.-blocksOf :: Primitive p => Int -> p -> BLOCKS p+blocksOf :: Int -> p -> BLOCKS p blocksOf n _ = BLOCKS n
Raaz/Core/Types.hs view
@@ -3,38 +3,16 @@ -- use the type safety of Haskell to catch some common bugs at compile -- time. As of now we address three kinds of errors ----- [Timing safe equality:] We need a consistent way to build timing--- safe equality comparisons. The type class `Equality` plays the--- role of `Eq` for us. The comparison result is of type `Result`--- and not `Bool` so as to avoid timing attacks due to--- short-circuting of the AND-operation. Instance for basic word--- types are given here and users are expected to build the--- `Equality` instances of compound types by combine the results--- of comparisons using the monoid instance of `Result`. We also--- give timing safe equality comparisons for `Vector` types using--- the `eqVector` and `oftenCorrectEqVector` functions. Once an--- instance for `Equality` is defined for a cryptographically--- sensitive data type, we define the `Eq` for it indirectly using--- the `Equality` instance and the operation `===`.------ [Endianness aware types:] When serialising data, we need to be--- careful about the endianness of the machine. Instance of the--- `EndianStore` type class correctly stores and loads data from--- memory, irrespective of the endianness of the machine. We--- define endian aware variants of `Word32` and `Word64` here and--- expect other cryptographic types to use such endian explicit--- types in their definition.------ [Pointer and Length units:] We have the generic pointer type--- `Pointer` and distinguish between different length units at the--- type level. This helps in to avoid a lot of length conversion--- errors.+ module Raaz.Core.Types ( -- * Timing safe equality checking.+ -- $timingSafeEquality$ module Raaz.Core.Types.Equality -- * Endianess aware types.+ -- $endianness$ , module Raaz.Core.Types.Endian -- * The pointer type and Length offsets.+ -- $typesafeLength$ , module Raaz.Core.Types.Pointer -- * Tuples with length encoded in their types. , module Raaz.Core.Types.Tuple@@ -46,5 +24,54 @@ import Raaz.Core.Types.Endian import Raaz.Core.Types.Pointer import Raaz.Core.Types.Tuple++-- $timingSafeEquality$+--+-- We need a consistent way to build timing safe equality+-- comparisons. The type class `Equality` plays the role of `Eq` for+-- us. The comparison result is of type `Result` and not `Bool` so as+-- to avoid timing attacks due to short-circuting of the+-- AND-operation.+--+-- The `Result` type is an opaque type to avoid the user from+-- compromising the equality comparisons by pattern matching on it. To+-- combine the results of two comparisons one can use the monoid+-- instance of `Result`, i.e. if @r1@ and @r2@ are the results of two+-- comparisons then @r1 `mappend` r2@ essentially takes the AND of+-- these results but this and is not short-circuited and is timing+-- independent.+--+-- Instance for basic word types are provided by the library and users+-- are expected to build the `Equality` instances of compound types by+-- combine the results of comparisons using the monoid instance of+-- `Result`. We also give timing safe equality comparisons for+-- `Vector` types using the `eqVector` and `oftenCorrectEqVector`+-- functions. Once an instance for `Equality` is defined for a+-- cryptographically sensitive data type, we define the `Eq` for it+-- indirectly using the `Equality` instance and the operation `===`.+++-- $endianness$+--+-- Cryptographic primitives often consider their input as an array of+-- words of a particular endianness. Endianness is only relevant when+-- the data is being read or written to. It makes sense therefore to+-- keep track of the endianness in the type and perform necessary+-- transformations depending on the endianness of the+-- machine. Such types are captured by the type class `EndianStore`. They+-- support the `load` and `store` combinators that automatically compensates+-- for the endianness of the machine.+--+-- This libraray exposes endian aware variants of `Word32` and+-- `Word64` here and expect other cryptographic types to use such+-- endian explicit types in their definition.+++-- $typesafeLength$+--+-- We have the generic pointer type `Pointer` and distinguish between+-- different length units at the type level. This helps in to avoid a+-- lot of length conversion errors.+ {-# ANN module "HLint: ignore Use import/export shortcut" #-}
Raaz/Core/Types/Endian.hs view
@@ -86,7 +86,7 @@ -> IO w {-# INLINE loadFromIndex #-} loadFromIndex cptr index = loadP undefined- where loadP :: (EndianStore w, Storable w) => w -> IO w+ where loadP :: EndianStore w => w -> IO w loadP w = loadFrom cptr offset where offset = toEnum index * byteSize w
Raaz/Core/Types/Equality.hs view
@@ -5,7 +5,7 @@ module Raaz.Core.Types.Equality ( Equality(..), (===) -- ** The result of comparion.- , Result, isSuccessful+ , Result -- ** Comparing vectors. , oftenCorrectEqVector, eqVector ) where@@ -22,17 +22,13 @@ import Data.Vector.Unboxed ( MVector(..), Vector, Unbox ) import Data.Word --- | An opaque type that captures the result of a comparison. The monoid--- instances allows us to combine the results of two equality comparisons--- in a timing independent manner. We have the following properties.------ > isSuccessful mempty = True--- > isSuccessful (r `mappend` s) = isSuccessful r && isSuccessful s---+-- | The result of a comparison. This is an opaque type and the monoid instance essentially takes+-- AND of two comparisons in a timing safe way. newtype Result = Result { unResult :: Word } -- | Checks whether a given equality comparison is successful. isSuccessful :: Result -> Bool+{-# INLINE isSuccessful #-} isSuccessful = (==0) . unResult instance Monoid Result where@@ -99,7 +95,7 @@ --- | In a cryptographic setting, naive equality checking+-- | In a cryptographic setting, naive equality checking is -- dangerous. This class is the timing safe way of doing equality -- checking. The recommended method of defining equality checking for -- cryptographically sensitive data is as follows.@@ -155,6 +151,76 @@ #else eq w1 w2 = Result $ fromIntegral $ xor w1 w2 #endif++-- Now comes the boring instances for tuples.++instance ( Equality a+ , Equality b+ ) => Equality (a , b) where+ eq (a1,a2) (b1,b2) = eq a1 b1 `mappend` eq a2 b2+++instance ( Equality a+ , Equality b+ , Equality c+ ) => Equality (a , b, c) where+ eq (a1,a2,a3) (b1,b2,b3) = eq a1 b1 `mappend`+ eq a2 b2 `mappend`+ eq a3 b3+++instance ( Equality a+ , Equality b+ , Equality c+ , Equality d+ ) => Equality (a , b, c, d) where+ eq (a1,a2,a3,a4) (b1,b2,b3,b4) = eq a1 b1 `mappend`+ eq a2 b2 `mappend`+ eq a3 b3 `mappend`+ eq a4 b4++instance ( Equality a+ , Equality b+ , Equality c+ , Equality d+ , Equality e+ ) => Equality (a , b, c, d, e) where+ eq (a1,a2,a3,a4,a5) (b1,b2,b3,b4,b5) = eq a1 b1 `mappend`+ eq a2 b2 `mappend`+ eq a3 b3 `mappend`+ eq a4 b4 `mappend`+ eq a5 b5+++instance ( Equality a+ , Equality b+ , Equality c+ , Equality d+ , Equality e+ , Equality f+ ) => Equality (a , b, c, d, e, f) where+ eq (a1,a2,a3,a4,a5,a6) (b1,b2,b3,b4,b5,b6) = eq a1 b1 `mappend`+ eq a2 b2 `mappend`+ eq a3 b3 `mappend`+ eq a4 b4 `mappend`+ eq a5 b5 `mappend`+ eq a6 b6++instance ( Equality a+ , Equality b+ , Equality c+ , Equality d+ , Equality e+ , Equality f+ , Equality g+ ) => Equality (a , b, c, d, e, f, g) where+ eq (a1,a2,a3,a4,a5,a6,a7) (b1,b2,b3,b4,b5,b6,b7) = eq a1 b1 `mappend`+ eq a2 b2 `mappend`+ eq a3 b3 `mappend`+ eq a4 b4 `mappend`+ eq a5 b5 `mappend`+ eq a6 b6 `mappend`+ eq a7 b7 -- | Timing independent equality checks for vector of values. /Do not/
Raaz/Hash/Internal/HMAC.hs view
@@ -80,13 +80,13 @@ theHash :: HMACKey h -> h theHash _ = undefined -instance (Hash h, Recommendation h, Encodable h) => EndianStore (HMACKey h) where+instance (Hash h, Recommendation h) => EndianStore (HMACKey h) where store = poke . castPtr load = peek . castPtr -instance (Hash h, Recommendation h, Encodable h) => Random (HMACKey h)+instance (Hash h, Recommendation h) => Random (HMACKey h) -instance (Hash h, Recommendation h, Encodable h) => Encodable (HMACKey h)+instance (Hash h, Recommendation h) => Encodable (HMACKey h) -- | Base16 representation of the string. instance IsString (HMACKey h) where
raaz.cabal view
@@ -1,5 +1,5 @@ name: raaz-version: 0.0.1+version: 0.0.2 synopsis: The raaz cryptographic library. @@ -103,6 +103,7 @@ other-modules: Raaz.Core.Constants , Raaz.Core.Encode.Internal , Raaz.Core.Encode.Base16+ , Raaz.Core.Encode.Base64 , Raaz.Core.Util.ByteString , Raaz.Core.Types.Pointer , Raaz.Core.Types.Tuple@@ -173,7 +174,7 @@ hs-source-dirs: bin main-is: checksum.lhs build-depends: base >= 4.5 && < 5.0- , raaz == 0.0.1+ , raaz == 0.0.2 test-Suite spec type: exitcode-stdio-1.0@@ -183,11 +184,13 @@ other-modules: Common , Common.Cipher , Common.Hash+ , Common.Imports , Common.Instances , Common.Utils , Raaz.Cipher.AESSpec- , Raaz.Core.Encode.Base16Spec+ , Raaz.Core.EncodeSpec , Raaz.Core.MemorySpec+ , Raaz.Core.SystemPRGSpec , Raaz.Core.Types.WordSpec , Raaz.Core.Util.ByteStringSpec , Raaz.Hash.Sha1Spec@@ -204,7 +207,7 @@ , QuickCheck >= 2.4 , hspec , transformers- , raaz == 0.0.1+ , raaz == 0.0.2 , vector benchmark blaze-vs-write
+ spec/Common/Imports.hs view
@@ -0,0 +1,19 @@+-- Common imports.+module Common.Imports( module E ) where+import Control.Applicative as E+import Data.ByteString as E (ByteString, pack)+import Data.ByteString.Char8 () -- import IsString instance for+ -- byte string.+import Data.String as E+import Data.Monoid as E+import Data.Word as E+import Foreign.Storable as E (Storable(..))+import Test.Hspec as E+import Test.Hspec.QuickCheck as E+import Test.QuickCheck as E+import Test.QuickCheck.Monadic as E++import Raaz.Core as E hiding ((===), Result)+import Raaz.Hash as E+import Raaz.Cipher as E+import Raaz.Cipher.Internal as E ( Cipher, unsafeEncrypt, unsafeDecrypt )
spec/Common/Instances.hs view
@@ -51,6 +51,9 @@ instance Arbitrary Base16 where arbitrary = (encodeByteString . pack) <$> listOf arbitrary +instance Arbitrary Base64 where+ arbitrary = (encodeByteString . pack) <$> listOf arbitrary+ ------------------ Arbitrary instances for Keys --------------- instance Arbitrary AES.KEY128 where
− spec/Raaz/Core/Encode/Base16Spec.hs
@@ -1,13 +0,0 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE OverloadedStrings #-}-module Raaz.Core.Encode.Base16Spec where--import Common--spec :: Spec-spec = do- prop "unsafeFromByteString . toByteString = id" $ \ (x :: Base16) ->- unsafeFromByteString (toByteString x) `shouldBe` x- prop "correctly encodes a 64-bit big endian word." $ \ (w :: Word64) ->- (read $ "0x" ++ showBase16 (bigEndian w)) == w
+ spec/Raaz/Core/EncodeSpec.hs view
@@ -0,0 +1,41 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE OverloadedStrings #-}+module Raaz.Core.EncodeSpec where++import Common+import qualified Data.ByteString as B++shouldBeAMultipleOf :: Int -> Int -> Bool+shouldBeAMultipleOf m x = m `rem` x == 0++shouldEncodeTo :: (Format fmt, Eq fmt) => ByteString -> fmt -> Spec+shouldEncodeTo bs e = it msg $ encodeByteString bs `shouldBe` e+ where msg = show bs ++ " should encode to " ++ show e++spec :: Spec+spec = do+ describe "Base16" $ do+ prop "encoded string is always of even length" $ \ (x :: Base16) ->+ B.length (toByteString x) `shouldBeAMultipleOf` 2++ prop "unsafeFromByteString . toByteString = id" $ \ (x :: Base16) ->+ unsafeFromByteString (toByteString x) `shouldBe` x++ prop "correctly encodes a 64-bit big endian word." $ \ (w :: Word64) ->+ (read $ "0x" ++ showBase16 (bigEndian w)) == w+++ describe "Base64" $ do+ prop "encoded string is always divisible by 4" $ \ (x :: Base64) ->+ B.length (toByteString x) `shouldBeAMultipleOf` 4++ prop "unsafeFromByteString . toByteString = id" $ \ (x :: Base16) ->+ unsafeFromByteString (toByteString x) `shouldBe` x++ describe "examples" $ do+ "pleasure." `shouldEncodeTo` ("cGxlYXN1cmUu" :: Base64)+ "leasure." `shouldEncodeTo` ("bGVhc3VyZS4=" :: Base64)+ "easure." `shouldEncodeTo` ("ZWFzdXJlLg==" :: Base64)+ "asure." `shouldEncodeTo` ("YXN1cmUu" :: Base64)+ "sure." `shouldEncodeTo` ("c3VyZS4=" :: Base64)
+ spec/Raaz/Core/SystemPRGSpec.hs view
@@ -0,0 +1,12 @@+module Raaz.Core.SystemPRGSpec where++import Common++spec :: Spec+spec = it "system prg should return different words on distinct calls"+ $ compareWords `shouldReturn` False+ where randomWord :: SystemPRG -> IO Word+ randomWord = random+ compareWords = do systemPRG <- newPRG ()+ (==) <$> randomWord systemPRG+ <*> randomWord systemPRG