saltine 0.0.0.1 → 0.0.0.2
raw patch · 11 files changed
+279/−267 lines, 11 files
Files
- saltine.cabal +3/−3
- src/Crypto/Saltine/Class.hs +5/−5
- src/Crypto/Saltine/Core/Auth.hs +23/−23
- src/Crypto/Saltine/Core/Box.hs +66/−62
- src/Crypto/Saltine/Core/Hash.hs +18/−18
- src/Crypto/Saltine/Core/OneTimeAuth.hs +20/−19
- src/Crypto/Saltine/Core/ScalarMult.hs +13/−13
- src/Crypto/Saltine/Core/SecretBox.hs +31/−29
- src/Crypto/Saltine/Core/Sign.hs +28/−28
- src/Crypto/Saltine/Core/Stream.hs +23/−23
- src/Crypto/Saltine/Internal/Util.hs +49/−44
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 ()