packages feed

saltine 0.0.0.1 → 0.0.0.2

raw patch · 11 files changed

+279/−267 lines, 11 files

Files

saltine.cabal view
@@ -1,6 +1,6 @@ name:                saltine-version:             0.0.0.1-synopsis:            A Haskell libsodium binding+version:             0.0.0.2+synopsis:            Cryptography that's easy to digest (NaCl/libsodium bindings). description:    /NaCl/ (pronounced \"salt\") is a new easy-to-use high-speed software@@ -55,7 +55,7 @@   default-language:   Haskell2010   build-depends:            base >= 4.5 && < 4.7,-    vector,+    bytestring,     profunctors      test-suite tests
src/Crypto/Saltine/Class.hs view
@@ -14,8 +14,8 @@   ) where  import Data.Profunctor-import Data.Word-import qualified Data.Vector.Storable as V+import qualified Data.ByteString as S+import           Data.ByteString (ByteString) import Control.Applicative  -- | Class for all keys and nonces in Saltine which have a@@ -23,10 +23,10 @@ -- type @Prism' (V.Vector Word8) a@ compatible with "Control.Lens" and -- is automatically deduced. class IsEncoding a where-  encode  :: a -> V.Vector Word8-  decode  :: V.Vector Word8 -> Maybe a+  encode  :: a -> ByteString+  decode  :: ByteString -> Maybe a   encoded :: (Choice p, Applicative f)-             => p a (f a) -> p (V.Vector Word8) (f (V.Vector Word8))+             => p a (f a) -> p ByteString (f ByteString)   encoded = prism' encode decode   {-# INLINE encoded #-} 
src/Crypto/Saltine/Core/Auth.hs view
@@ -10,7 +10,7 @@ -- Secret-key message authentication:  -- "Crypto.Saltine.Core.Auth" -- --- The 'auth' function authenticates a message 'V.Vector' using a+-- The 'auth' function authenticates a message 'ByteString' using a -- secret key The function returns an authenticator. The 'verify' -- function checks if it's passed a correct authenticator of a message -- under the given secret key.@@ -49,21 +49,21 @@  import Foreign.C import Foreign.Ptr-import Data.Word-import qualified Data.Vector.Storable as V+import qualified Data.ByteString as S+import           Data.ByteString (ByteString)  import Control.Applicative  -- $types  -- | An opaque 'auth' cryptographic key.-newtype Key = Key (V.Vector Word8) deriving (Eq, Ord)+newtype Key = Key ByteString deriving (Eq, Ord)  -- | An opaque 'auth' authenticator.-newtype Authenticator = Au (V.Vector Word8) deriving (Eq, Ord)+newtype Authenticator = Au ByteString deriving (Eq, Ord)  instance IsEncoding Key where-  decode v = case V.length v == Bytes.authKey of+  decode v = case S.length v == Bytes.authKey of     True -> Just (Key v)     False -> Nothing   {-# INLINE decode #-}@@ -71,7 +71,7 @@   {-# INLINE encode #-}  instance IsEncoding Authenticator where-  decode v = case V.length v == Bytes.auth of+  decode v = case S.length v == Bytes.auth of     True -> Just (Au v)     False -> Nothing   {-# INLINE decode #-}@@ -82,39 +82,39 @@ newKey :: IO Key newKey = Key <$> randomVector Bytes.authKey --- | Computes an keyed authenticator 'V.Vector' from a message. It is--- infeasible to forge these authenticators without the key, even if--- an attacker observes many authenticators and messages and has the--- ability to influence the messages sent.+-- | Computes an keyed authenticator 'ByteString' from a message. It+-- is infeasible to forge these authenticators without the key, even+-- if an attacker observes many authenticators and messages and has+-- the ability to influence the messages sent. auth :: Key -        -> V.Vector Word8+        -> ByteString         -- ^ Message         -> Authenticator auth (Key key) msg =   Au . snd . buildUnsafeCVector Bytes.auth $ \pa ->-    constVectors [key, msg] $ \[pk, pm] ->-    c_auth pa pm (fromIntegral $ V.length msg) pk+    constVectors [key, msg] $ \[(pk, _), (pm, mlen)] ->+    c_auth pa pm (fromIntegral mlen) pk  -- | Checks to see if an authenticator is a correct proof that a -- message was signed by some key. verify :: Key           -> Authenticator-          -> V.Vector Word8+          -> ByteString           -- ^ Message           -> Bool           -- ^ Is this message authentic? verify (Key key) (Au a) msg =-  unsafeDidSucceed $ constVectors [key, msg, a] $ \[pk, pm, pa] ->-  return $ c_auth_verify pa pm (fromIntegral $ V.length msg) pk+  unsafeDidSucceed $ constVectors [key, msg, a] $ \[(pk, _), (pm, mlen), (pa, _)] ->+  return $ c_auth_verify pa pm (fromIntegral mlen) pk  foreign import ccall "crypto_auth"-  c_auth :: Ptr Word8+  c_auth :: Ptr CChar             -- ^ Authenticator output buffer-            -> Ptr Word8+            -> Ptr CChar             -- ^ Constant message buffer             -> CULLong             -- ^ Length of message buffer-            -> Ptr Word8+            -> Ptr CChar             -- ^ Constant key buffer             -> IO CInt             -- ^ Always 0@@ -122,13 +122,13 @@ -- | We don't even include this in the IO monad since all of the -- buffers are constant. foreign import ccall "crypto_auth_verify"-  c_auth_verify :: Ptr Word8+  c_auth_verify :: Ptr CChar                    -- ^ Constant authenticator buffer-                   -> Ptr Word8+                   -> Ptr CChar                    -- ^ Constant message buffer                    -> CULLong                    -- ^ Length of message buffer-                   -> Ptr Word8+                   -> Ptr CChar                    -- ^ Constant key buffer                    -> CInt                    -- ^ Success if 0, failure if -1
src/Crypto/Saltine/Core/Box.hs view
@@ -10,12 +10,12 @@ -- Public-key authenticated encryption: -- "Crypto.Saltine.Core.Box" -- --- The 'box' function encrypts and authenticates a message 'V.Vector'--- using the sender's secret key, the receiver's public key, and a--- nonce. The 'boxOpen' function verifies and decrypts a ciphertext--- 'V.Vector' using the receiver's secret key, the sender's public--- key, and a nonce. If the ciphertext fails verification, 'boxOpen'--- returns 'Nothing'.+-- The 'box' function encrypts and authenticates a message+-- 'ByteString' using the sender's secret key, the receiver's public+-- key, and a nonce. The 'boxOpen' function verifies and decrypts a+-- ciphertext 'ByteString' using the receiver's secret key, the+-- sender's public key, and a nonce. If the ciphertext fails+-- verification, 'boxOpen' returns 'Nothing'. --  -- The "Crypto.Saltine.Core.Box" module is designed to meet the -- standard notions of privacy and third-party unforgeability for a@@ -77,18 +77,18 @@  import Foreign.C import Foreign.Ptr-import Data.Word-import qualified Data.Vector.Storable as V+import qualified Data.ByteString as S+import           Data.ByteString (ByteString)  import Control.Applicative  -- $types  -- | An opaque 'box' cryptographic secret key.-newtype SecretKey = SK (V.Vector Word8) deriving (Eq, Ord)+newtype SecretKey = SK ByteString deriving (Eq, Ord)  instance IsEncoding SecretKey where-  decode v = case V.length v == Bytes.boxSK of+  decode v = case S.length v == Bytes.boxSK of     True -> Just (SK v)     False -> Nothing   {-# INLINE decode #-}@@ -96,10 +96,10 @@   {-# INLINE encode #-}  -- | An opaque 'box' cryptographic public key.-newtype PublicKey = PK (V.Vector Word8) deriving (Eq, Ord)+newtype PublicKey = PK ByteString deriving (Eq, Ord)  instance IsEncoding PublicKey where-  decode v = case V.length v == Bytes.boxPK of+  decode v = case S.length v == Bytes.boxPK of     True -> Just (PK v)     False -> Nothing   {-# INLINE decode #-}@@ -110,10 +110,10 @@ type Keypair = (SecretKey, PublicKey)  -- | An opaque 'boxAfterNM' cryptographic combined key.-newtype CombinedKey = CK (V.Vector Word8) deriving (Eq, Ord)+newtype CombinedKey = CK ByteString deriving (Eq, Ord)  instance IsEncoding CombinedKey where-  decode v = case V.length v == Bytes.boxBeforeNM of+  decode v = case S.length v == Bytes.boxBeforeNM of     True -> Just (CK v)     False -> Nothing   {-# INLINE decode #-}@@ -121,10 +121,10 @@   {-# INLINE encode #-}  -- | An opaque 'box' nonce.-newtype Nonce = Nonce (V.Vector Word8) deriving (Eq, Ord)+newtype Nonce = Nonce ByteString deriving (Eq, Ord)  instance IsEncoding Nonce where-  decode v = case V.length v == Bytes.boxNonce of+  decode v = case S.length v == Bytes.boxNonce of     True -> Just (Nonce v)     False -> Nothing   {-# INLINE decode #-}@@ -132,8 +132,8 @@   {-# INLINE encode #-}  instance IsNonce Nonce where-  zero = Nonce (V.replicate Bytes.boxNonce 0)-  nudge (Nonce n) = Nonce (nudgeVector n)+  zero = Nonce (S.replicate Bytes.boxNonce 0)+  nudge (Nonce n) = Nonce (nudgeBS n)  -- | Randomly generates a secret key and a corresponding public key. newKeypair :: IO Keypair@@ -154,7 +154,7 @@ -- later encryption calls. beforeNM :: SecretKey -> PublicKey -> CombinedKey beforeNM (SK sk) (PK pk) = CK $ snd $ buildUnsafeCVector Bytes.boxBeforeNM $ \ckbuf ->-  constVectors [pk, sk] $ \[ppk, psk] ->+  constVectors [pk, sk] $ \[(ppk, _), (psk, _)] ->   c_box_beforenm ckbuf ppk psk  -- | Encrypts a message for sending to the owner of the public@@ -162,15 +162,16 @@ -- message. It is infeasible for an attacker to decrypt the message so -- long as the 'Nonce' is not repeated. box :: PublicKey -> SecretKey -> Nonce-       -> V.Vector Word8+       -> ByteString        -- ^ Message-       -> V.Vector Word8+       -> ByteString        -- ^ Ciphertext box (PK pk) (SK sk) (Nonce nonce) msg =   unpad' . snd . buildUnsafeCVector len $ \pc ->-    constVectors [pk, sk, pad' msg, nonce] $ \[ppk, psk, pm, pn] ->-    c_box pc pm (fromIntegral len) pn ppk psk-  where len    = V.length msg + Bytes.boxZero+    constVectors [pk, sk, pad' msg, nonce] $ \+      [(ppk, _), (psk, _), (pm, _), (pn, _)] ->+      c_box pc pm (fromIntegral len) pn ppk psk+  where len    = S.length msg + Bytes.boxZero         pad'   = pad Bytes.boxZero         unpad' = unpad Bytes.boxBoxZero @@ -178,129 +179,132 @@ -- must have encrypted it using your secret key. Returns 'Nothing' if -- the keys and message do not match. boxOpen :: PublicKey -> SecretKey -> Nonce-           -> V.Vector Word8+           -> ByteString            -- ^ Ciphertext-           -> Maybe (V.Vector Word8)+           -> Maybe ByteString            -- ^ Message boxOpen (PK pk) (SK sk) (Nonce nonce) cipher =   let (err, vec) = buildUnsafeCVector len $ \pm ->-        constVectors [pk, sk, pad' cipher, nonce] $ \[ppk, psk, pc, pn] ->-        c_box_open pm pc (fromIntegral len) pn ppk psk+        constVectors [pk, sk, pad' cipher, nonce] $ \+          [(ppk, _), (psk, _), (pc, _), (pn, _)] ->+          c_box_open pm pc (fromIntegral len) pn ppk psk   in hush . handleErrno err $ unpad' vec-  where len    = V.length cipher + Bytes.boxBoxZero+  where len    = S.length cipher + Bytes.boxBoxZero         pad'   = pad Bytes.boxBoxZero         unpad' = unpad Bytes.boxZero  -- | 'box' using a 'CombinedKey' and is thus faster. boxAfterNM :: CombinedKey -> Nonce-              -> V.Vector Word8+              -> ByteString               -- ^ Message-              -> V.Vector Word8+              -> ByteString               -- ^ Ciphertext boxAfterNM (CK ck) (Nonce nonce) msg =   unpad' . snd . buildUnsafeCVector len $ \pc ->-    constVectors [ck, pad' msg, nonce] $ \[pck, pm, pn] ->-    c_box_afternm pc pm (fromIntegral len) pn pck-  where len    = V.length msg + Bytes.boxZero+    constVectors [ck, pad' msg, nonce] $ \+      [(pck, _), (pm, _), (pn, _)] ->+      c_box_afternm pc pm (fromIntegral len) pn pck+  where len    = S.length msg + Bytes.boxZero         pad'   = pad Bytes.boxZero         unpad' = unpad Bytes.boxBoxZero  -- | 'boxOpen' using a 'CombinedKey' and is thus faster. boxOpenAfterNM :: CombinedKey -> Nonce-           -> V.Vector Word8+           -> ByteString            -- ^ Ciphertext-           -> Maybe (V.Vector Word8)+           -> Maybe ByteString            -- ^ Message boxOpenAfterNM (CK ck) (Nonce nonce) cipher =   let (err, vec) = buildUnsafeCVector len $ \pm ->-        constVectors [ck, pad' cipher, nonce] $ \[pck, pc, pn] ->-        c_box_open_afternm pm pc (fromIntegral len) pn pck+        constVectors [ck, pad' cipher, nonce] $ \+          [(pck, _), (pc, _), (pn, _)] ->+          c_box_open_afternm pm pc (fromIntegral len) pn pck   in hush . handleErrno err $ unpad' vec-  where len    = V.length cipher + Bytes.boxBoxZero+  where len    = S.length cipher + Bytes.boxBoxZero         pad'   = pad Bytes.boxBoxZero         unpad' = unpad Bytes.boxZero   -- | Should always return a 0. foreign import ccall "crypto_box_keypair"-  c_box_keypair :: Ptr Word8+  c_box_keypair :: Ptr CChar                    -- ^ Public key-                   -> Ptr Word8+                   -> Ptr CChar                    -- ^ Secret key                    -> IO CInt                    -- ^ Always 0  -- | The secretbox C API uses 0-padded C strings. foreign import ccall "crypto_box"-  c_box :: Ptr Word8+  c_box :: Ptr CChar            -- ^ Cipher 0-padded output buffer-           -> Ptr Word8+           -> Ptr CChar            -- ^ Constant 0-padded message input buffer            -> CULLong            -- ^ Length of message input buffer (incl. 0s)-           -> Ptr Word8+           -> Ptr CChar            -- ^ Constant nonce buffer-           -> Ptr Word8+           -> Ptr CChar            -- ^ Constant public key buffer-           -> Ptr Word8+           -> Ptr CChar            -- ^ Constant secret key buffer            -> IO CInt            -- ^ Always 0  -- | The secretbox C API uses 0-padded C strings. foreign import ccall "crypto_box_open"-  c_box_open :: Ptr Word8+  c_box_open :: Ptr CChar                 -- ^ Message 0-padded output buffer-                -> Ptr Word8+                -> Ptr CChar                 -- ^ Constant 0-padded ciphertext input buffer                 -> CULLong                 -- ^ Length of message input buffer (incl. 0s)-                -> Ptr Word8+                -> Ptr CChar                 -- ^ Constant nonce buffer-                -> Ptr Word8+                -> Ptr CChar                 -- ^ Constant public key buffer-                -> Ptr Word8+                -> Ptr CChar                 -- ^ Constant secret key buffer                 -> IO CInt                 -- ^ 0 for success, -1 for failure to verify  -- | Single target key precompilation. foreign import ccall "crypto_box_beforenm"-  c_box_beforenm :: Ptr Word8+  c_box_beforenm :: Ptr CChar                     -- ^ Combined key output buffer-                    -> Ptr Word8+                    -> Ptr CChar                     -- ^ Constant public key buffer-                    -> Ptr Word8+                    -> Ptr CChar                     -- ^ Constant secret key buffer                     -> IO CInt                     -- ^ Always 0  -- | Precompiled key crypto box. Uses 0-padded C strings. foreign import ccall "crypto_box_afternm"-  c_box_afternm :: Ptr Word8+  c_box_afternm :: Ptr CChar                    -- ^ Cipher 0-padded output buffer-                   -> Ptr Word8+                   -> Ptr CChar                    -- ^ Constant 0-padded message input buffer                    -> CULLong                    -- ^ Length of message input buffer (incl. 0s)-                   -> Ptr Word8+                   -> Ptr CChar                    -- ^ Constant nonce buffer-                   -> Ptr Word8+                   -> Ptr CChar                    -- ^ Constant combined key buffer                    -> IO CInt                    -- ^ Always 0  -- | The secretbox C API uses 0-padded C strings. foreign import ccall "crypto_box_open_afternm"-  c_box_open_afternm :: Ptr Word8+  c_box_open_afternm :: Ptr CChar                         -- ^ Message 0-padded output buffer-                        -> Ptr Word8+                        -> Ptr CChar                         -- ^ Constant 0-padded ciphertext input buffer                         -> CULLong                         -- ^ Length of message input buffer (incl. 0s)-                        -> Ptr Word8+                        -> Ptr CChar                         -- ^ Constant nonce buffer-                        -> Ptr Word8+                        -> Ptr CChar                         -- ^ Constant combined key buffer                         -> IO CInt                         -- ^ 0 for success, -1 for failure to verify
src/Crypto/Saltine/Core/Hash.hs view
@@ -9,9 +9,9 @@ --  -- Hashing: "Crypto.Saltine.Core.Hash" -- --- The 'hash' function hashes a message 'V.Vector' and returns a+-- The 'hash' function hashes a message 'ByteString' and returns a -- hash. Hashes are always of length 'Bytes.hash'. The 'shorthash'--- function hashes a message 'V.Vector' with respect to a secret key+-- function hashes a message 'ByteString' with respect to a secret key -- and returns a very short hash. Short hashes are always of length -- 'Bytes.shorthash'. -- @@ -52,26 +52,26 @@  import Foreign.C import Foreign.Ptr-import Data.Word-import qualified Data.Vector.Storable as V+import qualified Data.ByteString as S+import           Data.ByteString (ByteString)  import Control.Applicative  -- | Computes a cryptographically collision-resistant hash making -- @hash m == hash m' ==> m == m'@ highly likely even when under -- attack.-hash :: V.Vector Word8+hash :: ByteString         -- ^ Message-        -> V.Vector Word8+        -> ByteString         -- ^ Hash hash m = snd . buildUnsafeCVector Bytes.hash $ \ph ->-  constVectors [m] $ \[pm] -> c_hash ph pm (fromIntegral $ V.length m)+  constVectors [m] $ \[(pm, _)] -> c_hash ph pm (fromIntegral $ S.length m)  -- | An opaque 'shorthash' cryptographic secret key.-newtype ShorthashKey = ShK (V.Vector Word8) deriving (Eq, Ord)+newtype ShorthashKey = ShK ByteString deriving (Eq, Ord)  instance IsEncoding ShorthashKey where-  decode v = case V.length v == Bytes.shorthashKey of+  decode v = case S.length v == Bytes.shorthashKey of     True -> Just (ShK v)     False -> Nothing   {-# INLINE decode #-}@@ -84,18 +84,18 @@  -- | Computes a very short, fast keyed hash. shorthash :: ShorthashKey-             -> V.Vector Word8+             -> ByteString              -- ^ Message-             -> V.Vector Word8+             -> ByteString              -- ^ Hash shorthash (ShK k) m = snd . buildUnsafeCVector Bytes.shorthash $ \ph ->-  constVectors [k, m] $ \[pk, pm] ->-  c_shorthash ph pm (fromIntegral $ V.length m) pk+  constVectors [k, m] $ \[(pk, _), (pm, _)] ->+  c_shorthash ph pm (fromIntegral $ S.length m) pk               foreign import ccall "crypto_hash"-  c_hash :: Ptr Word8+  c_hash :: Ptr CChar             -- ^ Output hash buffer-            -> Ptr Word8+            -> Ptr CChar             -- ^ Constant message buffer             -> CULLong             -- ^ Constant message buffer length@@ -103,13 +103,13 @@             -- ^ Always 0  foreign import ccall "crypto_shorthash"-  c_shorthash :: Ptr Word8+  c_shorthash :: Ptr CChar                  -- ^ Output hash buffer-                 -> Ptr Word8+                 -> Ptr CChar                  -- ^ Constant message buffer                  -> CULLong                  -- ^ Message buffer length-                 -> Ptr Word8+                 -> Ptr CChar                  -- ^ Constant Key buffer                  -> IO CInt                  -- ^ Always 0
src/Crypto/Saltine/Core/OneTimeAuth.hs view
@@ -10,7 +10,7 @@ -- Secret-key single-message authentication: -- "Crypto.Saltine.Core.OneTimeAuth" -- --- The 'auth' function authenticates a message 'V.Vector' using a+-- The 'auth' function authenticates a message 'ByteString' using a -- secret key The function returns an authenticator. The 'verify' -- function checks if it's passed a correct authenticator of a message -- under the given secret key.@@ -45,21 +45,21 @@  import Foreign.C import Foreign.Ptr-import Data.Word-import qualified Data.Vector.Storable as V+import qualified Data.ByteString as S+import           Data.ByteString (ByteString)  import Control.Applicative  -- $types  -- | An opaque 'auth' cryptographic key.-newtype Key = Key (V.Vector Word8) deriving (Eq, Ord)+newtype Key = Key ByteString deriving (Eq, Ord)  -- | An opaque 'auth' authenticator.-newtype Authenticator = Au (V.Vector Word8) deriving (Eq, Ord)+newtype Authenticator = Au ByteString deriving (Eq, Ord)  instance IsEncoding Key where-  decode v = case V.length v == Bytes.onetimeKey of+  decode v = case S.length v == Bytes.onetimeKey of     True -> Just (Key v)     False -> Nothing   {-# INLINE decode #-}@@ -67,7 +67,7 @@   {-# INLINE encode #-}  instance IsEncoding Authenticator where-  decode v = case V.length v == Bytes.onetime of+  decode v = case S.length v == Bytes.onetime of     True -> Just (Au v)     False -> Nothing   {-# INLINE decode #-}@@ -82,33 +82,34 @@ -- 'Authenticator' is /impossible/ to forge so long as the 'Key' is -- never used twice. auth :: Key-        -> V.Vector Word8+        -> ByteString         -- ^ Message         -> Authenticator auth (Key key) msg =   Au . snd . buildUnsafeCVector Bytes.onetime $ \pa ->-    constVectors [key, msg] $ \[pk, pm] ->-    c_onetimeauth pa pm (fromIntegral $ V.length msg) pk+    constVectors [key, msg] $ \[(pk, _), (pm, _)] ->+    c_onetimeauth pa pm (fromIntegral $ S.length msg) pk  -- | Verifies that an 'Authenticator' matches a given message and key. verify :: Key           -> Authenticator-          -> V.Vector Word8+          -> ByteString           -- ^ Message           -> Bool           -- ^ Is this message authentic? verify (Key key) (Au a) msg =-  unsafeDidSucceed $ constVectors [key, msg, a] $ \[pk, pm, pa] ->-  return $ c_onetimeauth_verify pa pm (fromIntegral $ V.length msg) pk+  unsafeDidSucceed $ constVectors [key, msg, a] $ \+    [(pk, _), (pm, _), (pa, _)] ->+    return $ c_onetimeauth_verify pa pm (fromIntegral $ S.length msg) pk  foreign import ccall "crypto_onetimeauth"-  c_onetimeauth :: Ptr Word8+  c_onetimeauth :: Ptr CChar                    -- ^ Authenticator output buffer-                   -> Ptr Word8+                   -> Ptr CChar                    -- ^ Constant message buffer                    -> CULLong                    -- ^ Length of message buffer-                   -> Ptr Word8+                   -> Ptr CChar                    -- ^ Constant key buffer                    -> IO CInt                    -- ^ Always 0@@ -116,13 +117,13 @@ -- | We don't even include this in the IO monad since all of the -- buffers are constant. foreign import ccall "crypto_onetimeauth_verify"-  c_onetimeauth_verify :: Ptr Word8+  c_onetimeauth_verify :: Ptr CChar                           -- ^ Constant authenticator buffer-                          -> Ptr Word8+                          -> Ptr CChar                           -- ^ Constant message buffer                           -> CULLong                           -- ^ Length of message buffer-                          -> Ptr Word8+                          -> Ptr CChar                           -- ^ Constant key buffer                           -> CInt                           -- ^ Success if 0, failure if -1
src/Crypto/Saltine/Core/ScalarMult.hs view
@@ -61,19 +61,19 @@  import Foreign.C import Foreign.Ptr-import Data.Word-import qualified Data.Vector.Storable as V+import qualified Data.ByteString as S+import           Data.ByteString (ByteString)  -- $types  -- | A group element.-newtype GroupElement = GE (V.Vector Word8) deriving (Eq)+newtype GroupElement = GE ByteString deriving (Eq)  -- | A scalar integer.-newtype Scalar = Sc (V.Vector Word8) deriving (Eq)+newtype Scalar = Sc ByteString deriving (Eq)  instance IsEncoding GroupElement where-  decode v = case V.length v == Bytes.mult of+  decode v = case S.length v == Bytes.mult of     True -> Just (GE v)     False -> Nothing   {-# INLINE decode #-}@@ -81,7 +81,7 @@   {-# INLINE encode #-}  instance IsEncoding Scalar where-  decode v = case V.length v == Bytes.multScalar of+  decode v = case S.length v == Bytes.multScalar of     True -> Just (Sc v)     False -> Nothing   {-# INLINE decode #-}@@ -90,28 +90,28 @@  mult :: Scalar -> GroupElement -> GroupElement mult (Sc n) (GE p) = GE . snd . buildUnsafeCVector Bytes.mult $ \pq ->-  constVectors [n, p] $ \[pn, pp] ->+  constVectors [n, p] $ \[(pn, _), (pp, _)] ->   c_scalarmult pq pn pp  multBase :: Scalar -> GroupElement multBase (Sc n) = GE . snd . buildUnsafeCVector Bytes.mult $ \pq ->-  constVectors [n] $ \[pn] ->+  constVectors [n] $ \[(pn, _)] ->   c_scalarmult_base pq pn  foreign import ccall "crypto_scalarmult"-  c_scalarmult :: Ptr Word8+  c_scalarmult :: Ptr CChar                   -- ^ Output group element buffer-                  -> Ptr Word8+                  -> Ptr CChar                   -- ^ Input integer buffer-                  -> Ptr Word8+                  -> Ptr CChar                   -- ^ Input group element buffer                   -> IO CInt                   -- ^ Always 0  foreign import ccall "crypto_scalarmult"-  c_scalarmult_base :: Ptr Word8+  c_scalarmult_base :: Ptr CChar                        -- ^ Output group element buffer-                       -> Ptr Word8+                       -> Ptr CChar                        -- ^ Input integer buffer                        -> IO CInt                        -- ^ Always 0
src/Crypto/Saltine/Core/SecretBox.hs view
@@ -11,9 +11,9 @@ -- "Crypto.Saltine.Core.SecretBox" --  -- The 'secretbox' function encrypts and authenticates a message--- 'V.Vector' using a secret key and a nonce. The 'secretboxOpen'--- function verifies and decrypts a ciphertext 'V.Vector' using a secret--- key and a nonce. If the ciphertext fails validation,+-- 'ByteString' using a secret key and a nonce. The 'secretboxOpen'+-- function verifies and decrypts a ciphertext 'ByteString' using a+-- secret key and a nonce. If the ciphertext fails validation, -- 'secretboxOpen' returns 'Nothing'. --  -- The "Crypto.Saltine.Core.SecretBox" module is designed to meet@@ -49,18 +49,18 @@  import Foreign.C import Foreign.Ptr-import Data.Word-import qualified Data.Vector.Storable as V+import qualified Data.ByteString as S+import           Data.ByteString (ByteString)  import Control.Applicative  -- $types  -- | An opaque 'secretbox' cryptographic key.-newtype Key = Key (V.Vector Word8) deriving (Eq, Ord)+newtype Key = Key ByteString deriving (Eq, Ord)  instance IsEncoding Key where-  decode v = case V.length v == Bytes.secretBoxKey of+  decode v = case S.length v == Bytes.secretBoxKey of     True -> Just (Key v)     False -> Nothing   {-# INLINE decode #-}@@ -68,10 +68,10 @@   {-# INLINE encode #-}  -- | An opaque 'secretbox' nonce.-newtype Nonce = Nonce (V.Vector Word8) deriving (Eq, Ord)+newtype Nonce = Nonce ByteString deriving (Eq, Ord)  instance IsEncoding Nonce where-  decode v = case V.length v == Bytes.secretBoxNonce of+  decode v = case S.length v == Bytes.secretBoxNonce of     True -> Just (Nonce v)     False -> Nothing   {-# INLINE decode #-}@@ -79,8 +79,8 @@   {-# INLINE encode #-}  instance IsNonce Nonce where-  zero = Nonce (V.replicate Bytes.secretBoxNonce 0)-  nudge (Nonce n) = Nonce (nudgeVector n)+  zero = Nonce (S.replicate Bytes.secretBoxNonce 0)+  nudge (Nonce n) = Nonce (nudgeBS n)  -- | Creates a random key of the correct size for 'secretbox'. newKey :: IO Key@@ -93,59 +93,61 @@ -- | Encrypts a message. It is infeasible for an attacker to decrypt -- the message so long as the 'Nonce' is never repeated. secretbox :: Key -> Nonce-             -> V.Vector Word8+             -> ByteString              -- ^ Message-             -> V.Vector Word8+             -> ByteString              -- ^ Ciphertext secretbox (Key key) (Nonce nonce) msg =   unpad' . snd . buildUnsafeCVector len $ \pc ->-    constVectors [key, pad' msg, nonce] $ \[pk, pm, pn] ->-    c_secretbox pc pm (fromIntegral len) pn pk-  where len    = V.length msg + Bytes.secretBoxZero+    constVectors [key, pad' msg, nonce] $ \+      [(pk, _), (pm, _), (pn, _)] ->+      c_secretbox pc pm (fromIntegral len) pn pk+  where len    = S.length msg + Bytes.secretBoxZero         pad'   = pad Bytes.secretBoxZero         unpad' = unpad Bytes.secretBoxBoxZero  -- | Decrypts a message. Returns 'Nothing' if the keys and message do -- not match. secretboxOpen :: Key -> Nonce -                 -> V.Vector Word8+                 -> ByteString                  -- ^ Ciphertext-                 -> Maybe (V.Vector Word8)+                 -> Maybe ByteString                  -- ^ Message secretboxOpen (Key key) (Nonce nonce) cipher =   let (err, vec) = buildUnsafeCVector len $ \pm ->-        constVectors [key, pad' cipher, nonce] $ \[pk, pc, pn] ->-        c_secretbox_open pm pc (fromIntegral len) pn pk+        constVectors [key, pad' cipher, nonce] $ \+          [(pk, _), (pc, _), (pn, _)] ->+          c_secretbox_open pm pc (fromIntegral len) pn pk   in hush . handleErrno err $ unpad' vec-  where len    = V.length cipher + Bytes.secretBoxBoxZero+  where len    = S.length cipher + Bytes.secretBoxBoxZero         pad'   = pad Bytes.secretBoxBoxZero         unpad' = unpad Bytes.secretBoxZero  -- | The secretbox C API uses 0-padded C strings. Always returns 0. foreign import ccall "crypto_secretbox"-  c_secretbox :: Ptr Word8+  c_secretbox :: Ptr CChar                  -- ^ Cipher 0-padded output buffer-                 -> Ptr Word8+                 -> Ptr CChar                  -- ^ Constant 0-padded message input buffer                  -> CULLong                  -- ^ Length of message input buffer (incl. 0s)-                 -> Ptr Word8+                 -> Ptr CChar                  -- ^ Constant nonce buffer-                 -> Ptr Word8+                 -> Ptr CChar                  -- ^ Constant key buffer                  -> IO CInt  -- | The secretbox C API uses 0-padded C strings. Returns 0 if -- successful or -1 if verification failed. foreign import ccall "crypto_secretbox_open"-  c_secretbox_open :: Ptr Word8+  c_secretbox_open :: Ptr CChar                       -- ^ Message 0-padded output buffer-                      -> Ptr Word8+                      -> Ptr CChar                       -- ^ Constant 0-padded message input buffer                       -> CULLong                       -- ^ Length of message input buffer (incl. 0s)-                      -> Ptr Word8+                      -> Ptr CChar                       -- ^ Constant nonce buffer-                      -> Ptr Word8+                      -> Ptr CChar                       -- ^ Constant key buffer                       -> IO CInt
src/Crypto/Saltine/Core/Sign.hs view
@@ -11,10 +11,10 @@ --  -- The 'newKeypair' function randomly generates a secret key and a -- corresponding public key. The 'sign' function signs a message--- 'V.Vector' using the signer's secret key and returns the resulting--- signed message. The 'signOpen' function verifies the signature in a--- signed message using the signer's public key then returns the--- message without its signature.+-- 'ByteString' using the signer's secret key and returns the+-- resulting signed message. The 'signOpen' function verifies the+-- signature in a signed message using the signer's public key then+-- returns the message without its signature. --  -- "Crypto.Saltine.Core.Sign" is an EdDSA signature using -- elliptic-curve Curve25519 (see: <http://ed25519.cr.yp.to/>). See@@ -40,16 +40,16 @@ import Foreign.Marshal.Alloc import Foreign.Storable import System.IO.Unsafe-import Data.Word-import qualified Data.Vector.Storable as V+import qualified Data.ByteString as S+import           Data.ByteString (ByteString)  -- $types  -- | An opaque 'box' cryptographic secret key.-newtype SecretKey = SK (V.Vector Word8) deriving (Eq, Ord)+newtype SecretKey = SK ByteString deriving (Eq, Ord)  instance IsEncoding SecretKey where-  decode v = case V.length v == Bytes.signSK of+  decode v = case S.length v == Bytes.signSK of     True -> Just (SK v)     False -> Nothing   {-# INLINE decode #-}@@ -57,10 +57,10 @@   {-# INLINE encode #-}  -- | An opaque 'box' cryptographic public key.-newtype PublicKey = PK (V.Vector Word8) deriving (Eq, Ord)+newtype PublicKey = PK ByteString deriving (Eq, Ord)  instance IsEncoding PublicKey where-  decode v = case V.length v == Bytes.signPK of+  decode v = case S.length v == Bytes.signPK of     True -> Just (PK v)     False -> Nothing   {-# INLINE decode #-}@@ -84,71 +84,71 @@ -- | Augments a message with a signature forming a \"signed -- message\". sign :: SecretKey-        -> V.Vector Word8+        -> ByteString         -- ^ Message-        -> V.Vector Word8+        -> ByteString         -- ^ Signed message sign (SK k) m = unsafePerformIO $    alloca $ \psmlen -> do     (_err, sm) <- buildUnsafeCVector' (len + Bytes.sign) $ \psmbuf ->-      constVectors [k, m] $ \[pk, pm] ->+      constVectors [k, m] $ \[(pk, _), (pm, _)] ->       c_sign psmbuf psmlen pm (fromIntegral len) pk     smlen <- peek psmlen-    return $ V.take (fromIntegral smlen) sm-  where len = V.length m+    return $ S.take (fromIntegral smlen) sm+  where len = S.length m  -- | Checks a \"signed message\" returning 'Just' the original message -- iff the signature was generated using the 'SecretKey' corresponding -- to the given 'PublicKey'. Returns 'Nothing' otherwise. signOpen :: PublicKey-            -> V.Vector Word8+            -> ByteString             -- ^ Signed message-            -> Maybe (V.Vector Word8)+            -> Maybe ByteString             -- ^ Maybe the restored message signOpen (PK k) sm = unsafePerformIO $   alloca $ \pmlen -> do     (err, m) <- buildUnsafeCVector' smlen $ \pmbuf ->-      constVectors [k, sm] $ \[pk, psm] ->+      constVectors [k, sm] $ \[(pk, _), (psm, _)] ->       c_sign_open pmbuf pmlen psm (fromIntegral smlen) pk     mlen <- peek pmlen     case err of-      0 -> return $ Just $ V.take (fromIntegral mlen) m+      0 -> return $ Just $ S.take (fromIntegral mlen) m       _ -> return $ Nothing-  where smlen = V.length sm+  where smlen = S.length sm   foreign import ccall "crypto_sign_keypair"-  c_sign_keypair :: Ptr Word8+  c_sign_keypair :: Ptr CChar                     -- ^ Public key output buffer-                    -> Ptr Word8+                    -> Ptr CChar                     -- ^ Secret key output buffer                     -> IO CInt                     -- ^ Always 0  foreign import ccall "crypto_sign"-  c_sign :: Ptr Word8+  c_sign :: Ptr CChar             -- ^ Signed message output buffer             -> Ptr CULLong             -- ^ Length of signed message-            -> Ptr Word8+            -> Ptr CChar             -- ^ Constant message buffer             -> CULLong             -- ^ Length of message input buffer-            -> Ptr Word8+            -> Ptr CChar             -- ^ Constant secret key buffer             -> IO CInt             -- ^ Always 0  foreign import ccall "crypto_sign_open"-  c_sign_open :: Ptr Word8+  c_sign_open :: Ptr CChar                  -- ^ Message output buffer                  -> Ptr CULLong                  -- ^ Length of message-                 -> Ptr Word8+                 -> Ptr CChar                  -- ^ Constant signed message buffer                  -> CULLong                  -- ^ Length of signed message buffer-                 -> Ptr Word8+                 -> Ptr CChar                  -- ^ Public key buffer                  -> IO CInt                  -- ^ 0 if signature is verifiable, -1 otherwise
src/Crypto/Saltine/Core/Stream.hs view
@@ -10,9 +10,9 @@ -- Secret-key encryption: -- "Crypto.Saltine.Core.Stream" -- --- The 'stream' function produces a sized stream 'V.Vector' as a+-- The 'stream' function produces a sized stream 'ByteString' as a -- function of a secret key and a nonce. The 'xor' function encrypts a--- message 'V.Vector' using a secret key and a nonce.  The 'xor'+-- message 'ByteString' using a secret key and a nonce.  The 'xor' -- function guarantees that the ciphertext has the same length as the -- plaintext, and is the @plaintext `xor` stream k n@. Consequently -- 'xor' can also be used to decrypt.@@ -59,18 +59,18 @@  import Foreign.C import Foreign.Ptr-import Data.Word-import qualified Data.Vector.Storable as V+import qualified Data.ByteString as S+import           Data.ByteString (ByteString)  import Control.Applicative  -- $types  -- | An opaque 'stream' cryptographic key.-newtype Key = Key (V.Vector Word8) deriving (Eq, Ord)+newtype Key = Key ByteString deriving (Eq, Ord)  instance IsEncoding Key where-  decode v = case V.length v == Bytes.streamKey of+  decode v = case S.length v == Bytes.streamKey of     True -> Just (Key v)     False -> Nothing   {-# INLINE decode #-}@@ -78,14 +78,14 @@   {-# INLINE encode #-}  -- | An opaque 'stream' nonce.-newtype Nonce = Nonce (V.Vector Word8) deriving (Eq, Ord)+newtype Nonce = Nonce ByteString deriving (Eq, Ord)  instance IsNonce Nonce where-  zero = Nonce (V.replicate Bytes.streamNonce 0)-  nudge (Nonce n) = Nonce (nudgeVector n)+  zero = Nonce (S.replicate Bytes.streamNonce 0)+  nudge (Nonce n) = Nonce (nudgeBS n)  instance IsEncoding Nonce where-  decode v = case V.length v == Bytes.streamNonce of+  decode v = case S.length v == Bytes.streamNonce of     True -> Just (Nonce v)     False -> Nothing   {-# INLINE decode #-}@@ -105,11 +105,11 @@ -- 'Nonce'. These streams are indistinguishable from random noise so -- long as the 'Nonce' is not used more than once. stream :: Key -> Nonce -> Int-          -> V.Vector Word8+          -> ByteString           -- ^ Cryptographic stream stream (Key key) (Nonce nonce) n =   snd . buildUnsafeCVector n $ \ps ->-    constVectors [key, nonce] $ \[pk, pn] ->+    constVectors [key, nonce] $ \[(pk, _), (pn, _)] ->     c_stream ps (fromIntegral n) pn pk  -- | Computes the exclusive-or between a message and a cryptographic@@ -120,38 +120,38 @@ -- /manipulate the message in transit without detection/. USE AT YOUR -- OWN RISK. xor :: Key -> Nonce -       -> V.Vector Word8+       -> ByteString        -- ^ Message-       -> V.Vector Word8+       -> ByteString        -- ^ Ciphertext xor (Key key) (Nonce nonce) msg =   snd . buildUnsafeCVector len $ \pc ->-    constVectors [key, nonce, msg] $ \[pk, pn, pm] ->+    constVectors [key, nonce, msg] $ \[(pk, _), (pn, _), (pm, _)] ->     c_stream_xor pc pm (fromIntegral len) pn pk-  where len = V.length msg+  where len = S.length msg  foreign import ccall "crypto_stream"-  c_stream :: Ptr Word8+  c_stream :: Ptr CChar               -- ^ Stream output buffer               -> CULLong               -- ^ Length of stream to generate-              -> Ptr Word8+              -> Ptr CChar               -- ^ Constant nonce buffer-              -> Ptr Word8+              -> Ptr CChar               -- ^ Constant key buffer               -> IO CInt               -- ^ Always 0  foreign import ccall "crypto_stream_xor"-  c_stream_xor :: Ptr Word8+  c_stream_xor :: Ptr CChar                   -- ^ Ciphertext output buffer-                  -> Ptr Word8+                  -> Ptr CChar                   -- ^ Constant message buffer                   -> CULLong                   -- ^ Length of message buffer-                  -> Ptr Word8+                  -> Ptr CChar                   -- ^ Constant nonce buffer-                  -> Ptr Word8+                  -> Ptr CChar                   -- ^ Constant key buffer                   -> IO CInt                   -- ^ Always 0
src/Crypto/Saltine/Internal/Util.hs view
@@ -2,43 +2,46 @@  import Foreign.C import Foreign.Ptr-import Foreign.ForeignPtr import System.IO.Unsafe-import Data.Word+ import Data.Monoid-import qualified Data.Vector.Storable as V-import qualified Data.Vector.Storable.Mutable as VM+import qualified Data.ByteString as S+import Data.ByteString (ByteString)+import Data.ByteString.Unsafe -import Data.STRef+-- | @snd . cycleSucc@ computes the 'succ' of a 'Bounded', 'Eq' 'Enum'+-- with wraparound. The @fst . cycleSuc@ is whether the wraparound+-- occurred (i.e. @fst . cycleSucc == (== maxBound)@).+cycleSucc :: (Bounded a, Enum a, Eq a) => a -> (Bool, a)+cycleSucc a = (top, if top then minBound else succ a)+  where top = a == maxBound -foreign import ccall "randombytes_buf"-  c_randombytes_buf :: Ptr Word8 -> CInt -> IO ()+-- | Treats a 'ByteString' as a little endian bitstring and increments+-- it.+nudgeBS :: ByteString -> ByteString+nudgeBS i = fst $ S.unfoldrN (S.length i) go (True, i) where+  go (toSucc, bs) =+    do (hd, tl) <- S.uncons bs+       let (top, hd') = cycleSucc hd+       if toSucc+         then return (hd', (top, tl))+         else return (hd, (top && toSucc, tl)) --- | Increments a 'V.Vector' with 0 as the least-significant index.-nudgeVector :: V.Vector Word8 -> V.Vector Word8-nudgeVector v = V.modify go v-  where go mv = do-          iref <- newSTRef 0-          loop iref mv-        loop iref mv = do-          i <- readSTRef iref-          if i < len-            then do val <- VM.read mv i-                    if val == maxBound-                       then do VM.write mv i minBound-                               modifySTRef iref succ-                               loop iref mv-                      else VM.write mv i (succ val)-            else return ()-        len = V.length v+-- | Computes the orbit of a endomorphism... in a very brute force+-- manner. Exists just for the below property.+-- +-- prop> length . orbit nudgeBS . S.pack . replicate 0 == (256^)+orbit :: Eq a => (a -> a) -> a -> [a]+orbit f a0 = orbit' (f a0) where+  orbit' a = if a == a0 then [a0] else a : orbit' (f a) --- | 0-pad a vector-pad :: (VM.Storable a, Num a) => Int -> V.Vector a -> V.Vector a-pad n = mappend (V.replicate n 0)+-- | 0-pad a 'ByteString'+pad :: Int -> ByteString -> ByteString+pad n = mappend (S.replicate n 0) --- | Remove a 0-padding from a vector-unpad :: VM.Storable a => Int -> V.Vector a -> V.Vector a-unpad = V.drop+-- | Remove a 0-padding from a 'ByteString'+unpad :: Int -> ByteString -> ByteString+unpad = S.drop  -- | Converts a C-convention errno to an Either handleErrno :: CInt -> (a -> Either String a)@@ -53,33 +56,35 @@         go _ = False  -- | Convenience function for accessing constant C vectors-constVectors :: VM.Storable a => [V.Vector a] -> ([Ptr a] -> IO b) -> IO b -- Manual unfold of: @constVectors = runContT . mapM (ContT . V.unsafeWith)@-constVectors = foldr (\v kk -> \k -> (V.unsafeWith v) (\a -> kk (\as -> k (a:as)))) ($ [])+constVectors :: [ByteString] -> ([CStringLen] -> IO b) -> IO b+constVectors =+  foldr (\v kk -> \k -> (unsafeUseAsCStringLen v) (\a -> kk (\as -> k (a:as)))) ($ [])  -- | Slightly safer cousin to 'buildUnsafeCVector' that remains in the -- 'IO' monad.-buildUnsafeCVector' :: VM.Storable a => Int -> (Ptr a -> IO b) -> IO (b, V.Vector a)+buildUnsafeCVector' :: Int -> (Ptr CChar -> IO b) -> IO (b, ByteString) buildUnsafeCVector' n k = do-  buf <- mallocForeignPtrArray n-  b <- withForeignPtr buf k-  vec <- V.unsafeFreeze (VM.unsafeFromForeignPtr buf 0 n)-  return (b, vec)+  let bs = S.replicate n 0+  out <- unsafeUseAsCString bs k+  return (out, bs)  -- | Extremely unsafe function, use with utmost care! Builds a new -- Vector using a ccall which is given access to the raw underlying -- pointer. Overwrites are UNCHECKED and 'unsafePerformIO' is used so--- it's difficult to predict the timing of the 'Vector' creation.-buildUnsafeCVector :: VM.Storable a => Int -> (Ptr a -> IO b) -> (b, V.Vector a)+-- it's difficult to predict the timing of the 'ByteString' creation.+buildUnsafeCVector :: Int -> (Ptr CChar -> IO b) -> (b, ByteString) buildUnsafeCVector n = unsafePerformIO . buildUnsafeCVector' n --- | Build a sized random 'V.Vector' using Sodium's bindings to+-- | Build a sized random 'ByteString' using Sodium's bindings to -- @/dev/urandom@.-randomVector :: Int -> IO (V.Vector Word8)-randomVector n = do-  (_, vec) <- buildUnsafeCVector' n (`c_randombytes_buf` fromIntegral n)-  return vec+randomVector :: Int -> IO ByteString+randomVector n =+  fmap snd $ buildUnsafeCVector' n (`c_randombytes_buf` fromIntegral n)  -- | To prevent a dependency on package 'errors' hush :: Either s a -> Maybe a hush = either (const Nothing) Just++foreign import ccall "randombytes_buf"+  c_randombytes_buf :: Ptr CChar -> CInt -> IO ()