saltine (empty) → 0.0.0.1
raw patch · 16 files changed
+1965/−0 lines, 16 filesdep +QuickCheckdep +basedep +bytestringsetup-changed
Dependencies added: QuickCheck, base, bytestring, profunctors, saltine, test-framework, test-framework-quickcheck2, vector
Files
- LICENSE +21/−0
- Setup.hs +3/−0
- saltine.cabal +74/−0
- src/Crypto/Saltine.hs +29/−0
- src/Crypto/Saltine/Class.hs +55/−0
- src/Crypto/Saltine/Core/Auth.hs +134/−0
- src/Crypto/Saltine/Core/Box.hs +306/−0
- src/Crypto/Saltine/Core/Hash.hs +115/−0
- src/Crypto/Saltine/Core/OneTimeAuth.hs +128/−0
- src/Crypto/Saltine/Core/ScalarMult.hs +117/−0
- src/Crypto/Saltine/Core/SecretBox.hs +151/−0
- src/Crypto/Saltine/Core/Sign.hs +154/−0
- src/Crypto/Saltine/Core/Stream.hs +157/−0
- src/Crypto/Saltine/Internal/ByteSizes.hs +414/−0
- src/Crypto/Saltine/Internal/Util.hs +85/−0
- tests/Main.hs +22/−0
+ LICENSE view
@@ -0,0 +1,21 @@+The MIT License (MIT)++Copyright (c) 2013 Joseph Abrahamson++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in+all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+THE SOFTWARE.
+ Setup.hs view
@@ -0,0 +1,3 @@+#!/usr/bin/env runhaskell+import Distribution.Simple+main = defaultMain
+ saltine.cabal view
@@ -0,0 +1,74 @@+name: saltine+version: 0.0.0.1+synopsis: A Haskell libsodium binding+description:++ /NaCl/ (pronounced \"salt\") is a new easy-to-use high-speed software+ library for network communica tion, encryption, decryption,+ signatures, etc. NaCl's goal is to provide all of the core+ operations needed to build higher-level cryptographic tools.+ .+ <http://nacl.cr.yp.to/>+ .+ /Sodium/ is a portable, cross-compilable, installable, packageable+ crypto library based on NaCl, with a compatible API.+ .+ <https://github.com/jedisct1/libsodium>+ .+ /Saltine/ is a Haskell binding to the NaCl primitives going through+ Sodium for build convenience and, eventually, portability.++license: MIT+license-file: LICENSE+author: Joseph Abrahamson+maintainer: Joseph Abrahamson <me@jspha.com>+bug-reports: http://github.com/tel/saltine/issues+copyright: Copyright (c) Joseph Abrahamson 2013+category: Cryptography+build-type: Simple+cabal-version: >=1.10+tested-with: GHC==7.6.3++source-repository head+ type: git+ location: https://github.com/tel/saltine.git++library+ hs-source-dirs: src+ exposed-modules:+ Crypto.Saltine+ Crypto.Saltine.Internal.ByteSizes+ Crypto.Saltine.Core.SecretBox+ Crypto.Saltine.Core.Box+ Crypto.Saltine.Core.Stream+ Crypto.Saltine.Core.Auth+ Crypto.Saltine.Core.OneTimeAuth+ Crypto.Saltine.Core.Sign+ Crypto.Saltine.Core.Hash+ Crypto.Saltine.Core.ScalarMult+ Crypto.Saltine.Class+ other-modules:+ Crypto.Saltine.Internal.Util+ extra-libraries: sodium+ cc-options: -Wall+ ghc-options: -Wall -funbox-strict-fields+ default-language: Haskell2010+ build-depends: + base >= 4.5 && < 4.7,+ vector,+ profunctors+ +test-suite tests+ type: exitcode-stdio-1.0+ main-is: Main.hs+ ghc-options: -Wall -threaded -O0 -rtsopts+ hs-source-dirs: tests+ default-language: Haskell2010+ build-depends:+ base >= 4.5 && < 4.7,+ saltine,+ bytestring,+ vector,+ QuickCheck,+ test-framework-quickcheck2,+ test-framework
+ src/Crypto/Saltine.hs view
@@ -0,0 +1,29 @@+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE TypeFamilies #-}++module Crypto.Saltine (+ optimize,+ module Crypto.Saltine.Core.SecretBox+ ) where++import Foreign.C+import Crypto.Saltine.Core.SecretBox++-- | Runs Sodiums's optimizer. This has no semantic effect, but both+-- may boost the speed of Sodium after running it. It is recommended+-- in production environments. It is, however, NOT thread-safe so no+-- other Sodium functions should be called until it successfully+-- returns.+optimize :: IO ()+optimize = do+ err <- c_sodiumInit+ case err of+ 0 -> -- everything went well+ return ()+ 1 -> -- already initialized, we're good+ return ()+ _ -> -- some kind of failure+ error "Crypto.Saltine.optimize"++foreign import ccall "sodium_init" c_sodiumInit :: IO CInt
+ src/Crypto/Saltine/Class.hs view
@@ -0,0 +1,55 @@+-- |+-- Module : Crypto.Saltine.Class+-- Copyright : (c) Joseph Abrahamson 2013+-- License : MIT+-- +-- Maintainer : me@jspha.com+-- Stability : experimental+-- Portability : non-portable+-- +-- Saltine type classes+module Crypto.Saltine.Class (+ IsEncoding (..),+ IsNonce (..)+ ) where++import Data.Profunctor+import Data.Word+import qualified Data.Vector.Storable as V+import Control.Applicative++-- | Class for all keys and nonces in Saltine which have a+-- representation as 'V.Vector' of 'Word8'. 'encoded' is a 'Prism' of+-- 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+ encoded :: (Choice p, Applicative f)+ => p a (f a) -> p (V.Vector Word8) (f (V.Vector Word8))+ encoded = prism' encode decode+ {-# INLINE encoded #-}++-- | A generic class for interacting with nonces.+class IsNonce n where+ zero :: n+ -- ^ Some privileged nonce value.+ nudge :: n -> n+ -- ^ Some perturbation on nonces such that @n /= nudge n@ with high+ -- probability. Since nonces are finite, repeats may happen in+ -- particularly small cases, but no nonces in Saltine are so+ -- small. This is not guaranteed to be difficult to predict---if a+ -- nonce had an `Enum` instance `succ` would be a good+ -- implementation excepting that `succ` is partial.++-- Copied over from Control.Lens++prism' :: (Applicative f, Choice p) =>+ (a1 -> a) -> (a -> Maybe a2) -> p a2 (f a1) -> p a (f a)+prism' bs sma = prism bs (\s -> maybe (Left s) Right (sma s))+{-# INLINE prism' #-}++prism :: (Applicative f, Choice p) =>+ (a2 -> a1) -> (a -> Either a1 a3) -> p a3 (f a2) -> p a (f a1)+prism bt seta = dimap seta (either pure (fmap bt)) . right'+{-# INLINE prism #-}
+ src/Crypto/Saltine/Core/Auth.hs view
@@ -0,0 +1,134 @@+-- |+-- Module : Crypto.Saltine.Core.Auth+-- Copyright : (c) Joseph Abrahamson 2013+-- License : MIT+-- +-- Maintainer : me@jspha.com+-- Stability : experimental+-- Portability : non-portable+-- +-- Secret-key message authentication: +-- "Crypto.Saltine.Core.Auth"+-- +-- The 'auth' function authenticates a message 'V.Vector' 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.+-- +-- The 'auth' function, viewed as a function of the message for a+-- uniform random key, is designed to meet the standard notion of+-- unforgeability. This means that an attacker cannot find+-- authenticators for any messages not authenticated by the sender,+-- even if the attacker has adaptively influenced the messages+-- authenticated by the sender. For a formal definition see, e.g.,+-- Section 2.4 of Bellare, Kilian, and Rogaway, \"The security of the+-- cipher block chaining message authentication code,\" Journal of+-- Computer and System Sciences 61 (2000), 362–399;+-- <http://www-cse.ucsd.edu/~mihir/papers/cbc.html>.+-- +-- Saltine does not make any promises regarding \"strong\"+-- unforgeability; perhaps one valid authenticator can be converted+-- into another valid authenticator for the same message. NaCl also+-- does not make any promises regarding \"truncated unforgeability.\"+-- +-- "Crypto.Saltine.Core.Auth" is currently an implementation of+-- HMAC-SHA-512-256, i.e., the first 256 bits of+-- HMAC-SHA-512. HMAC-SHA-512-256 is conjectured to meet the standard+-- notion of unforgeability.+-- +-- This is version 2010.08.30 of the auth.html web page.+module Crypto.Saltine.Core.Auth (+ Key, Authenticator,+ newKey,+ auth, verify+ ) where++import Crypto.Saltine.Class+import Crypto.Saltine.Internal.Util+import qualified Crypto.Saltine.Internal.ByteSizes as Bytes++import Foreign.C+import Foreign.Ptr+import Data.Word+import qualified Data.Vector.Storable as V++import Control.Applicative++-- $types++-- | An opaque 'auth' cryptographic key.+newtype Key = Key (V.Vector Word8) deriving (Eq, Ord)++-- | An opaque 'auth' authenticator.+newtype Authenticator = Au (V.Vector Word8) deriving (Eq, Ord)++instance IsEncoding Key where+ decode v = case V.length v == Bytes.authKey of+ True -> Just (Key v)+ False -> Nothing+ {-# INLINE decode #-}+ encode (Key v) = v+ {-# INLINE encode #-}++instance IsEncoding Authenticator where+ decode v = case V.length v == Bytes.auth of+ True -> Just (Au v)+ False -> Nothing+ {-# INLINE decode #-}+ encode (Au v) = v+ {-# INLINE encode #-}++-- | Creates a random key of the correct size for 'auth' and 'verify'.+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.+auth :: Key + -> V.Vector Word8+ -- ^ 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++-- | Checks to see if an authenticator is a correct proof that a+-- message was signed by some key.+verify :: Key+ -> Authenticator+ -> V.Vector Word8+ -- ^ 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++foreign import ccall "crypto_auth"+ c_auth :: Ptr Word8+ -- ^ Authenticator output buffer+ -> Ptr Word8+ -- ^ Constant message buffer+ -> CULLong+ -- ^ Length of message buffer+ -> Ptr Word8+ -- ^ Constant key buffer+ -> IO CInt+ -- ^ Always 0++-- | 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+ -- ^ Constant authenticator buffer+ -> Ptr Word8+ -- ^ Constant message buffer+ -> CULLong+ -- ^ Length of message buffer+ -> Ptr Word8+ -- ^ Constant key buffer+ -> CInt+ -- ^ Success if 0, failure if -1
+ src/Crypto/Saltine/Core/Box.hs view
@@ -0,0 +1,306 @@+-- |+-- Module : Crypto.Saltine.Core.Box+-- Copyright : (c) Joseph Abrahamson 2013+-- License : MIT+-- +-- Maintainer : me@jspha.com+-- Stability : experimental+-- Portability : non-portable+-- +-- 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 "Crypto.Saltine.Core.Box" module is designed to meet the+-- standard notions of privacy and third-party unforgeability for a+-- public-key authenticated-encryption scheme using nonces. For formal+-- definitions see, e.g., Jee Hea An, "Authenticated encryption in the+-- public-key setting: security notions and analyses,"+-- <http://eprint.iacr.org/2001/079>.+-- +-- Distinct messages between the same @{sender, receiver}@ set are+-- required to have distinct nonces. For example, the+-- lexicographically smaller public key can use nonce 1 for its first+-- message to the other key, nonce 3 for its second message, nonce 5+-- for its third message, etc., while the lexicographically larger+-- public key uses nonce 2 for its first message to the other key,+-- nonce 4 for its second message, nonce 6 for its third message,+-- etc. Nonces are long enough that randomly generated nonces have+-- negligible risk of collision.+-- +-- There is no harm in having the same nonce for different messages if+-- the @{sender, receiver}@ sets are different. This is true even if+-- the sets overlap. For example, a sender can use the same nonce for+-- two different messages if the messages are sent to two different+-- public keys.+-- +-- The "Crypto.Saltine.Core.Box" module is not meant to provide+-- non-repudiation. On the contrary: the crypto_box function+-- guarantees repudiability. A receiver can freely modify a boxed+-- message, and therefore cannot convince third parties that this+-- particular message came from the sender. The sender and receiver+-- are nevertheless protected against forgeries by other parties. In+-- the terminology of+-- <http://groups.google.com/group/sci.crypt/msg/ec5c18b23b11d82c>,+-- crypto_box uses "public-key authenticators" rather than "public-key+-- signatures."+-- +-- Users who want public verifiability (or receiver-assisted public+-- verifiability) should instead use signatures (or+-- signcryption). Signatures are documented in the+-- "Crypto.Saltine.Core.Sign" module.+-- +-- "Crypto.Saltine.Core.Box" is @curve25519xsalsa20poly1305@, a+-- particular combination of Curve25519, Salsa20, and Poly1305+-- specified in "Cryptography in NaCl"+-- (<http://nacl.cr.yp.to/valid.html>). This function is conjectured+-- to meet the standard notions of privacy and third-party+-- unforgeability.+-- +-- This is version 2010.08.30 of the box.html web page.+module Crypto.Saltine.Core.Box (+ SecretKey, PublicKey, Keypair, CombinedKey, Nonce,+ newKeypair, beforeNM, newNonce,+ box, boxOpen,+ boxAfterNM, boxOpenAfterNM + ) where++import Crypto.Saltine.Class+import Crypto.Saltine.Internal.Util+import qualified Crypto.Saltine.Internal.ByteSizes as Bytes++import Foreign.C+import Foreign.Ptr+import Data.Word+import qualified Data.Vector.Storable as V++import Control.Applicative++-- $types++-- | An opaque 'box' cryptographic secret key.+newtype SecretKey = SK (V.Vector Word8) deriving (Eq, Ord)++instance IsEncoding SecretKey where+ decode v = case V.length v == Bytes.boxSK of+ True -> Just (SK v)+ False -> Nothing+ {-# INLINE decode #-}+ encode (SK v) = v+ {-# INLINE encode #-}++-- | An opaque 'box' cryptographic public key.+newtype PublicKey = PK (V.Vector Word8) deriving (Eq, Ord)++instance IsEncoding PublicKey where+ decode v = case V.length v == Bytes.boxPK of+ True -> Just (PK v)+ False -> Nothing+ {-# INLINE decode #-}+ encode (PK v) = v+ {-# INLINE encode #-}++-- | A convenience type for keypairs+type Keypair = (SecretKey, PublicKey)++-- | An opaque 'boxAfterNM' cryptographic combined key.+newtype CombinedKey = CK (V.Vector Word8) deriving (Eq, Ord)++instance IsEncoding CombinedKey where+ decode v = case V.length v == Bytes.boxBeforeNM of+ True -> Just (CK v)+ False -> Nothing+ {-# INLINE decode #-}+ encode (CK v) = v+ {-# INLINE encode #-}++-- | An opaque 'box' nonce.+newtype Nonce = Nonce (V.Vector Word8) deriving (Eq, Ord)++instance IsEncoding Nonce where+ decode v = case V.length v == Bytes.boxNonce of+ True -> Just (Nonce v)+ False -> Nothing+ {-# INLINE decode #-}+ encode (Nonce v) = v+ {-# INLINE encode #-}++instance IsNonce Nonce where+ zero = Nonce (V.replicate Bytes.boxNonce 0)+ nudge (Nonce n) = Nonce (nudgeVector n)++-- | Randomly generates a secret key and a corresponding public key.+newKeypair :: IO Keypair+newKeypair = do+ -- This is a little bizarre and a likely source of errors.+ -- _err ought to always be 0.+ ((_err, sk), pk) <- buildUnsafeCVector' Bytes.boxPK $ \pkbuf ->+ buildUnsafeCVector' Bytes.boxSK $ \skbuf ->+ c_box_keypair pkbuf skbuf+ return (SK sk, PK pk)++-- | Randomly generates a nonce for usage with 'box' and 'boxOpen'.+newNonce :: IO Nonce+newNonce = Nonce <$> randomVector Bytes.boxNonce++-- | Build a 'CombinedKey' for sending from 'SecretKey' to+-- 'PublicKey'. This is a precomputation step which can accelerate+-- later encryption calls.+beforeNM :: SecretKey -> PublicKey -> CombinedKey+beforeNM (SK sk) (PK pk) = CK $ snd $ buildUnsafeCVector Bytes.boxBeforeNM $ \ckbuf ->+ constVectors [pk, sk] $ \[ppk, psk] ->+ c_box_beforenm ckbuf ppk psk++-- | Encrypts a message for sending to the owner of the public+-- key. They must have your public key in order to decrypt the+-- 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+ -- ^ Message+ -> V.Vector Word8+ -- ^ 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+ pad' = pad Bytes.boxZero+ unpad' = unpad Bytes.boxBoxZero++-- | Decrypts a message sent from the owner of the public key. They+-- 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+ -- ^ Ciphertext+ -> Maybe (V.Vector Word8)+ -- ^ 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+ in hush . handleErrno err $ unpad' vec+ where len = V.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+ -- ^ Message+ -> V.Vector Word8+ -- ^ 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+ pad' = pad Bytes.boxZero+ unpad' = unpad Bytes.boxBoxZero++-- | 'boxOpen' using a 'CombinedKey' and is thus faster.+boxOpenAfterNM :: CombinedKey -> Nonce+ -> V.Vector Word8+ -- ^ Ciphertext+ -> Maybe (V.Vector Word8)+ -- ^ 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+ in hush . handleErrno err $ unpad' vec+ where len = V.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+ -- ^ Public key+ -> Ptr Word8+ -- ^ Secret key+ -> IO CInt+ -- ^ Always 0++-- | The secretbox C API uses 0-padded C strings.+foreign import ccall "crypto_box"+ c_box :: Ptr Word8+ -- ^ Cipher 0-padded output buffer+ -> Ptr Word8+ -- ^ Constant 0-padded message input buffer+ -> CULLong+ -- ^ Length of message input buffer (incl. 0s)+ -> Ptr Word8+ -- ^ Constant nonce buffer+ -> Ptr Word8+ -- ^ Constant public key buffer+ -> Ptr Word8+ -- ^ 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+ -- ^ Message 0-padded output buffer+ -> Ptr Word8+ -- ^ Constant 0-padded ciphertext input buffer+ -> CULLong+ -- ^ Length of message input buffer (incl. 0s)+ -> Ptr Word8+ -- ^ Constant nonce buffer+ -> Ptr Word8+ -- ^ Constant public key buffer+ -> Ptr Word8+ -- ^ 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+ -- ^ Combined key output buffer+ -> Ptr Word8+ -- ^ Constant public key buffer+ -> Ptr Word8+ -- ^ 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+ -- ^ Cipher 0-padded output buffer+ -> Ptr Word8+ -- ^ Constant 0-padded message input buffer+ -> CULLong+ -- ^ Length of message input buffer (incl. 0s)+ -> Ptr Word8+ -- ^ Constant nonce buffer+ -> Ptr Word8+ -- ^ 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+ -- ^ Message 0-padded output buffer+ -> Ptr Word8+ -- ^ Constant 0-padded ciphertext input buffer+ -> CULLong+ -- ^ Length of message input buffer (incl. 0s)+ -> Ptr Word8+ -- ^ Constant nonce buffer+ -> Ptr Word8+ -- ^ Constant combined key buffer+ -> IO CInt+ -- ^ 0 for success, -1 for failure to verify
+ src/Crypto/Saltine/Core/Hash.hs view
@@ -0,0 +1,115 @@+-- |+-- Module : Crypto.Saltine.Core.Hash+-- Copyright : (c) Joseph Abrahamson 2013+-- License : MIT+-- +-- Maintainer : me@jspha.com+-- Stability : experimental+-- Portability : non-portable+-- +-- Hashing: "Crypto.Saltine.Core.Hash"+-- +-- The 'hash' function hashes a message 'V.Vector' 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+-- and returns a very short hash. Short hashes are always of length+-- 'Bytes.shorthash'.+-- +-- The 'hash' function is designed to be usable as a strong component+-- of DSA, RSA-PSS, key derivation, hash-based message-authentication+-- codes, hash-based ciphers, and various other common+-- applications. "Strong" means that the security of these+-- applications, when instantiated with 'hash', is the same as the+-- security of the applications against generic attacks. In+-- particular, the 'hash' function is designed to make finding+-- collisions difficult.+-- +-- 'hash' is currently an implementation of SHA-512. 'shorthash' is+-- currently an implementation of SipHash-2-4+-- (<https://131002.net/siphash/>).+-- +-- There has been considerable degradation of public confidence in the+-- security conjectures for many hash functions, including+-- SHA-512. However, for the moment, there do not appear to be+-- alternatives that inspire satisfactory levels of confidence. One+-- can hope that NIST's SHA-3 competition will improve the situation.+-- +-- Sodium includes an implementation of the Blake2 hash+-- (<https://blake2.net/>) but since this is not standard NaCl nor was+-- Blake2 selected to be SHA-3 the library doesn't bind it.+-- +-- This is version 2010.08.30 of the hash.html web page. Information+-- about SipHash has been added.+module Crypto.Saltine.Core.Hash (+ ShorthashKey,+ hash,+ shorthash, newShorthashKey+ ) where++import Crypto.Saltine.Class+import Crypto.Saltine.Internal.Util+import qualified Crypto.Saltine.Internal.ByteSizes as Bytes++import Foreign.C+import Foreign.Ptr+import Data.Word+import qualified Data.Vector.Storable as V++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+ -- ^ Message+ -> V.Vector Word8+ -- ^ Hash+hash m = snd . buildUnsafeCVector Bytes.hash $ \ph ->+ constVectors [m] $ \[pm] -> c_hash ph pm (fromIntegral $ V.length m)++-- | An opaque 'shorthash' cryptographic secret key.+newtype ShorthashKey = ShK (V.Vector Word8) deriving (Eq, Ord)++instance IsEncoding ShorthashKey where+ decode v = case V.length v == Bytes.shorthashKey of+ True -> Just (ShK v)+ False -> Nothing+ {-# INLINE decode #-}+ encode (ShK v) = v+ {-# INLINE encode #-}++-- | Randomly generates a new key for 'shorthash'.+newShorthashKey :: IO ShorthashKey+newShorthashKey = ShK <$> randomVector Bytes.shorthashKey++-- | Computes a very short, fast keyed hash.+shorthash :: ShorthashKey+ -> V.Vector Word8+ -- ^ Message+ -> V.Vector Word8+ -- ^ Hash+shorthash (ShK k) m = snd . buildUnsafeCVector Bytes.shorthash $ \ph ->+ constVectors [k, m] $ \[pk, pm] ->+ c_shorthash ph pm (fromIntegral $ V.length m) pk+ +foreign import ccall "crypto_hash"+ c_hash :: Ptr Word8+ -- ^ Output hash buffer+ -> Ptr Word8+ -- ^ Constant message buffer+ -> CULLong+ -- ^ Constant message buffer length+ -> IO CInt+ -- ^ Always 0++foreign import ccall "crypto_shorthash"+ c_shorthash :: Ptr Word8+ -- ^ Output hash buffer+ -> Ptr Word8+ -- ^ Constant message buffer+ -> CULLong+ -- ^ Message buffer length+ -> Ptr Word8+ -- ^ Constant Key buffer+ -> IO CInt+ -- ^ Always 0
+ src/Crypto/Saltine/Core/OneTimeAuth.hs view
@@ -0,0 +1,128 @@+-- |+-- Module : Crypto.Saltine.Core.OneTimeAuth+-- Copyright : (c) Joseph Abrahamson 2013+-- License : MIT+-- +-- Maintainer : me@jspha.com+-- Stability : experimental+-- Portability : non-portable+-- +-- Secret-key single-message authentication:+-- "Crypto.Saltine.Core.OneTimeAuth"+-- +-- The 'auth' function authenticates a message 'V.Vector' 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.+-- +-- The 'auth' function, viewed as a function of the message for a+-- uniform random key, is designed to meet the standard notion of+-- unforgeability after a single message. After the sender+-- authenticates one message, an attacker cannot find authenticators+-- for any other messages.+-- +-- The sender must not use 'auth' to authenticate more than one+-- message under the same key. Authenticators for two messages under+-- the same key should be expected to reveal enough information to+-- allow forgeries of authenticators on other messages.+-- +-- "Crypto.Saltine.Core.OneTimeAuth" is+-- @crypto_onetimeauth_poly1305@, an authenticator specified in+-- "Cryptography in NaCl" (<http://nacl.cr.yp.to/valid.html>), Section+-- 9. This authenticator is proven to meet the standard notion of+-- unforgeability after a single message.+-- +-- This is version 2010.08.30 of the onetimeauth.html web page.+module Crypto.Saltine.Core.OneTimeAuth (+ Key, Authenticator,+ newKey,+ auth, verify+ ) where++import Crypto.Saltine.Class+import Crypto.Saltine.Internal.Util+import qualified Crypto.Saltine.Internal.ByteSizes as Bytes++import Foreign.C+import Foreign.Ptr+import Data.Word+import qualified Data.Vector.Storable as V++import Control.Applicative++-- $types++-- | An opaque 'auth' cryptographic key.+newtype Key = Key (V.Vector Word8) deriving (Eq, Ord)++-- | An opaque 'auth' authenticator.+newtype Authenticator = Au (V.Vector Word8) deriving (Eq, Ord)++instance IsEncoding Key where+ decode v = case V.length v == Bytes.onetimeKey of+ True -> Just (Key v)+ False -> Nothing+ {-# INLINE decode #-}+ encode (Key v) = v+ {-# INLINE encode #-}++instance IsEncoding Authenticator where+ decode v = case V.length v == Bytes.onetime of+ True -> Just (Au v)+ False -> Nothing+ {-# INLINE decode #-}+ encode (Au v) = v+ {-# INLINE encode #-}++-- | Creates a random key of the correct size for 'auth' and 'verify'.+newKey :: IO Key+newKey = Key <$> randomVector Bytes.onetimeKey++-- | Builds a keyed 'Authenticator' for a message. This+-- 'Authenticator' is /impossible/ to forge so long as the 'Key' is+-- never used twice.+auth :: Key+ -> V.Vector Word8+ -- ^ 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++-- | Verifies that an 'Authenticator' matches a given message and key.+verify :: Key+ -> Authenticator+ -> V.Vector Word8+ -- ^ 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++foreign import ccall "crypto_onetimeauth"+ c_onetimeauth :: Ptr Word8+ -- ^ Authenticator output buffer+ -> Ptr Word8+ -- ^ Constant message buffer+ -> CULLong+ -- ^ Length of message buffer+ -> Ptr Word8+ -- ^ Constant key buffer+ -> IO CInt+ -- ^ Always 0++-- | 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+ -- ^ Constant authenticator buffer+ -> Ptr Word8+ -- ^ Constant message buffer+ -> CULLong+ -- ^ Length of message buffer+ -> Ptr Word8+ -- ^ Constant key buffer+ -> CInt+ -- ^ Success if 0, failure if -1
+ src/Crypto/Saltine/Core/ScalarMult.hs view
@@ -0,0 +1,117 @@+-- |+-- Module : Crypto.Saltine.Core.ScalarMult+-- Copyright : (c) Joseph Abrahamson 2013+-- License : MIT+-- +-- Maintainer : me@jspha.com+-- Stability : experimental+-- Portability : non-portable+-- +-- Scalar multiplication: "Crypto.Saltine.Core.ScalarMult"+-- +-- The 'mult' function multiplies a group element by an integer of+-- length 'Bytes.multScalar'. It returns the resulting group element+-- of length 'Bytes.mult'. The 'multBase' function multiplies a+-- standard group element by an integer of length+-- 'Bytes.multScalar'. It returns the resulting group element of+-- length 'Bytes.mult'.+-- +-- The correspondence between strings and group elements depends on+-- the primitive implemented by 'mult'. The correspondence is not+-- necessarily injective in either direction, but it is compatible+-- with scalar multiplication in the group. The correspondence does+-- not necessarily include all group elements, but it does include all+-- strings; i.e., every string represents at least one group element.+-- +-- The correspondence between strings and integers also depends on the+-- primitive implemented by 'mult'. Every string represents at least+-- one integer.+-- +-- 'mult' is designed to be strong as a component of various+-- well-known \"hashed Diffie–Hellman\" applications. In particular,+-- it is designed to make the \"computational Diffie–Hellman\" problem+-- (CDH) difficult with respect to the standard base. 'mult' is also+-- designed to make CDH difficult with respect to other nontrivial+-- bases. In particular, if a represented group element has small+-- order, then it is annihilated by all represented scalars. This+-- feature allows protocols to avoid validating membership in the+-- subgroup generated by the standard base.+-- +-- NaCl does not make any promises regarding the \"decisional+-- Diffie–Hellman\" problem (DDH), the \"static Diffie–Hellman\"+-- problem (SDH), etc. Users are responsible for hashing group+-- elements.+-- +-- 'mult' is the function @crypto_scalarmult_curve25519@ specified in+-- \"Cryptography in NaCl\", Sections 2, 3, and 4+-- (<http://nacl.cr.yp.to/valid.html>). This function is conjectured+-- to be strong. For background see Bernstein, \"Curve25519: new+-- Diffie-Hellman speed records,\" Lecture Notes in Computer Science+-- 3958 (2006), 207–228, <http://cr.yp.to/papers.html#curve25519>.+-- +-- This is version 2010.08.30 of the scalarmult.html web page.+module Crypto.Saltine.Core.ScalarMult (+ Scalar, GroupElement,+ mult, multBase+ ) where++import Crypto.Saltine.Class+import Crypto.Saltine.Internal.Util+import qualified Crypto.Saltine.Internal.ByteSizes as Bytes++import Foreign.C+import Foreign.Ptr+import Data.Word+import qualified Data.Vector.Storable as V++-- $types++-- | A group element.+newtype GroupElement = GE (V.Vector Word8) deriving (Eq)++-- | A scalar integer.+newtype Scalar = Sc (V.Vector Word8) deriving (Eq)++instance IsEncoding GroupElement where+ decode v = case V.length v == Bytes.mult of+ True -> Just (GE v)+ False -> Nothing+ {-# INLINE decode #-}+ encode (GE v) = v+ {-# INLINE encode #-}++instance IsEncoding Scalar where+ decode v = case V.length v == Bytes.multScalar of+ True -> Just (Sc v)+ False -> Nothing+ {-# INLINE decode #-}+ encode (Sc v) = v+ {-# INLINE encode #-}++mult :: Scalar -> GroupElement -> GroupElement+mult (Sc n) (GE p) = GE . snd . buildUnsafeCVector Bytes.mult $ \pq ->+ 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] ->+ c_scalarmult_base pq pn++foreign import ccall "crypto_scalarmult"+ c_scalarmult :: Ptr Word8+ -- ^ Output group element buffer+ -> Ptr Word8+ -- ^ Input integer buffer+ -> Ptr Word8+ -- ^ Input group element buffer+ -> IO CInt+ -- ^ Always 0++foreign import ccall "crypto_scalarmult"+ c_scalarmult_base :: Ptr Word8+ -- ^ Output group element buffer+ -> Ptr Word8+ -- ^ Input integer buffer+ -> IO CInt+ -- ^ Always 0
+ src/Crypto/Saltine/Core/SecretBox.hs view
@@ -0,0 +1,151 @@+-- |+-- Module : Crypto.Saltine.Core.SecretBox+-- Copyright : (c) Joseph Abrahamson 2013+-- License : MIT+-- +-- Maintainer : me@jspha.com+-- Stability : experimental+-- Portability : non-portable+-- +-- Secret-key authenticated encryption:+-- "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,+-- 'secretboxOpen' returns 'Nothing'.+-- +-- The "Crypto.Saltine.Core.SecretBox" module is designed to meet+-- the standard notions of privacy and authenticity for a secret-key+-- authenticated-encryption scheme using nonces. For formal+-- definitions see, e.g., Bellare and Namprempre, "Authenticated+-- encryption: relations among notions and analysis of the generic+-- composition paradigm," Lecture Notes in Computer Science 1976+-- (2000), 531–545, <http://www-cse.ucsd.edu/~mihir/papers/oem.html>.+-- +-- Note that the length is not hidden. Note also that it is the+-- caller's responsibility to ensure the uniqueness of nonces—for+-- example, by using nonce 1 for the first message, nonce 2 for the+-- second message, etc. Nonces are long enough that randomly generated+-- nonces have negligible risk of collision.+-- +-- "Crypto.Saltine.Core.SecretBox" is+-- @crypto_secretbox_xsalsa20poly1305@, a particular combination of+-- Salsa20 and Poly1305 specified in \"Cryptography in NaCl\"+-- (<http://nacl.cr.yp.to/valid.html>). This function is conjectured+-- to meet the standard notions of privacy and authenticity.+-- +-- This is version 2010.08.30 of the secretbox.html web page.+module Crypto.Saltine.Core.SecretBox (+ Key, Nonce,+ secretbox, secretboxOpen,+ newKey, newNonce+ ) where++import Crypto.Saltine.Class+import Crypto.Saltine.Internal.Util+import qualified Crypto.Saltine.Internal.ByteSizes as Bytes++import Foreign.C+import Foreign.Ptr+import Data.Word+import qualified Data.Vector.Storable as V++import Control.Applicative++-- $types++-- | An opaque 'secretbox' cryptographic key.+newtype Key = Key (V.Vector Word8) deriving (Eq, Ord)++instance IsEncoding Key where+ decode v = case V.length v == Bytes.secretBoxKey of+ True -> Just (Key v)+ False -> Nothing+ {-# INLINE decode #-}+ encode (Key v) = v+ {-# INLINE encode #-}++-- | An opaque 'secretbox' nonce.+newtype Nonce = Nonce (V.Vector Word8) deriving (Eq, Ord)++instance IsEncoding Nonce where+ decode v = case V.length v == Bytes.secretBoxNonce of+ True -> Just (Nonce v)+ False -> Nothing+ {-# INLINE decode #-}+ encode (Nonce v) = v+ {-# INLINE encode #-}++instance IsNonce Nonce where+ zero = Nonce (V.replicate Bytes.secretBoxNonce 0)+ nudge (Nonce n) = Nonce (nudgeVector n)++-- | Creates a random key of the correct size for 'secretbox'.+newKey :: IO Key+newKey = Key <$> randomVector Bytes.secretBoxKey++-- | Creates a random nonce of the correct size for 'secretbox'.+newNonce :: IO Nonce+newNonce = Nonce <$> randomVector Bytes.secretBoxNonce++-- | 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+ -- ^ Message+ -> V.Vector Word8+ -- ^ 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+ 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+ -- ^ Ciphertext+ -> Maybe (V.Vector Word8)+ -- ^ 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+ in hush . handleErrno err $ unpad' vec+ where len = V.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+ -- ^ Cipher 0-padded output buffer+ -> Ptr Word8+ -- ^ Constant 0-padded message input buffer+ -> CULLong+ -- ^ Length of message input buffer (incl. 0s)+ -> Ptr Word8+ -- ^ Constant nonce buffer+ -> Ptr Word8+ -- ^ 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+ -- ^ Message 0-padded output buffer+ -> Ptr Word8+ -- ^ Constant 0-padded message input buffer+ -> CULLong+ -- ^ Length of message input buffer (incl. 0s)+ -> Ptr Word8+ -- ^ Constant nonce buffer+ -> Ptr Word8+ -- ^ Constant key buffer+ -> IO CInt
+ src/Crypto/Saltine/Core/Sign.hs view
@@ -0,0 +1,154 @@+-- |+-- Module : Crypto.Saltine.Core.Sign+-- Copyright : (c) Joseph Abrahamson 2013+-- License : MIT+-- +-- Maintainer : me@jspha.com+-- Stability : experimental+-- Portability : non-portable+-- +-- Signatures: "Crypto.Saltine.Core.Sign"+-- +-- 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.+-- +-- "Crypto.Saltine.Core.Sign" is an EdDSA signature using+-- elliptic-curve Curve25519 (see: <http://ed25519.cr.yp.to/>). See+-- also, \"Daniel J. Bernstein, Niels Duif, Tanja Lange, Peter+-- Schwabe, Bo-Yin Yang. High-speed high-security signatures. Journal+-- of Cryptographic Engineering 2 (2012), 77–89.\"+-- <http://ed25519.cr.yp.to/ed25519-20110926.pdf>.+--+-- This is current information as of 2013 June 6.++module Crypto.Saltine.Core.Sign (+ SecretKey, PublicKey, Keypair,+ newKeypair,+ sign, signOpen+ ) where++import Crypto.Saltine.Class+import Crypto.Saltine.Internal.Util+import qualified Crypto.Saltine.Internal.ByteSizes as Bytes++import Foreign.C+import Foreign.Ptr+import Foreign.Marshal.Alloc+import Foreign.Storable+import System.IO.Unsafe+import Data.Word+import qualified Data.Vector.Storable as V++-- $types++-- | An opaque 'box' cryptographic secret key.+newtype SecretKey = SK (V.Vector Word8) deriving (Eq, Ord)++instance IsEncoding SecretKey where+ decode v = case V.length v == Bytes.signSK of+ True -> Just (SK v)+ False -> Nothing+ {-# INLINE decode #-}+ encode (SK v) = v+ {-# INLINE encode #-}++-- | An opaque 'box' cryptographic public key.+newtype PublicKey = PK (V.Vector Word8) deriving (Eq, Ord)++instance IsEncoding PublicKey where+ decode v = case V.length v == Bytes.signPK of+ True -> Just (PK v)+ False -> Nothing+ {-# INLINE decode #-}+ encode (PK v) = v+ {-# INLINE encode #-}++-- | A convenience type for keypairs+type Keypair = (SecretKey, PublicKey)++-- | Creates a random key of the correct size for 'sign' and+-- 'signOpen' of form @(secretKey, publicKey)@.+newKeypair :: IO Keypair+newKeypair = do+ -- This is a little bizarre and a likely source of errors.+ -- _err ought to always be 0.+ ((_err, sk), pk) <- buildUnsafeCVector' Bytes.signPK $ \pkbuf ->+ buildUnsafeCVector' Bytes.signSK $ \skbuf ->+ c_sign_keypair pkbuf skbuf+ return (SK sk, PK pk)++-- | Augments a message with a signature forming a \"signed+-- message\".+sign :: SecretKey+ -> V.Vector Word8+ -- ^ Message+ -> V.Vector Word8+ -- ^ Signed message+sign (SK k) m = unsafePerformIO $ + alloca $ \psmlen -> do+ (_err, sm) <- buildUnsafeCVector' (len + Bytes.sign) $ \psmbuf ->+ 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++-- | 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+ -- ^ Signed message+ -> Maybe (V.Vector Word8)+ -- ^ Maybe the restored message+signOpen (PK k) sm = unsafePerformIO $+ alloca $ \pmlen -> do+ (err, m) <- buildUnsafeCVector' smlen $ \pmbuf ->+ 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+ _ -> return $ Nothing+ where smlen = V.length sm+++foreign import ccall "crypto_sign_keypair"+ c_sign_keypair :: Ptr Word8+ -- ^ Public key output buffer+ -> Ptr Word8+ -- ^ Secret key output buffer+ -> IO CInt+ -- ^ Always 0++foreign import ccall "crypto_sign"+ c_sign :: Ptr Word8+ -- ^ Signed message output buffer+ -> Ptr CULLong+ -- ^ Length of signed message+ -> Ptr Word8+ -- ^ Constant message buffer+ -> CULLong+ -- ^ Length of message input buffer+ -> Ptr Word8+ -- ^ Constant secret key buffer+ -> IO CInt+ -- ^ Always 0++foreign import ccall "crypto_sign_open"+ c_sign_open :: Ptr Word8+ -- ^ Message output buffer+ -> Ptr CULLong+ -- ^ Length of message+ -> Ptr Word8+ -- ^ Constant signed message buffer+ -> CULLong+ -- ^ Length of signed message buffer+ -> Ptr Word8+ -- ^ Public key buffer+ -> IO CInt+ -- ^ 0 if signature is verifiable, -1 otherwise
+ src/Crypto/Saltine/Core/Stream.hs view
@@ -0,0 +1,157 @@+-- |+-- Module : Crypto.Saltine.Core.Stream+-- Copyright : (c) Joseph Abrahamson 2013+-- License : MIT+-- +-- Maintainer : me@jspha.com+-- Stability : experimental+-- Portability : non-portable+-- +-- Secret-key encryption:+-- "Crypto.Saltine.Core.Stream"+-- +-- The 'stream' function produces a sized stream 'V.Vector' 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'+-- 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.+-- +-- The 'stream' function, viewed as a function of the nonce for a+-- uniform random key, is designed to meet the standard notion of+-- unpredictability (\"PRF\"). For a formal definition see, e.g.,+-- Section 2.3 of Bellare, Kilian, and Rogaway, \"The security of the+-- cipher block chaining message authentication code,\" Journal of+-- Computer and System Sciences 61 (2000), 362–399;+-- <http://www-cse.ucsd.edu/~mihir/papers/cbc.html>. This means that+-- an attacker cannot distinguish this function from a uniform random+-- function. Consequently, if a series of messages is encrypted by+-- 'xor' with /a different nonce for each message/, the ciphertexts+-- are indistinguishable from uniform random strings of the same+-- length.+-- +-- Note that the length is not hidden. Note also that it is the+-- caller's responsibility to ensure the uniqueness of nonces—for+-- example, by using nonce 1 for the first message, nonce 2 for the+-- second message, etc. Nonces are long enough that randomly generated+-- nonces have negligible risk of collision.+-- +-- Saltine does not make any promises regarding the resistance of+-- crypto_stream to \"related-key attacks.\" It is the caller's+-- responsibility to use proper key-derivation functions.+-- +-- "Crypto.Saltine.Core.Stream" is @crypto_stream_xsalsa20@, a+-- particular cipher specified in \"Cryptography in NaCl\"+-- (<http://nacl.cr.yp.to/valid.html>), Section 7. This cipher is+-- conjectured to meet the standard notion of unpredictability.+-- +-- This is version 2010.08.30 of the stream.html web page.++module Crypto.Saltine.Core.Stream (+ Key, Nonce,+ newKey, newNonce,+ stream, xor+ ) where++import Crypto.Saltine.Class+import Crypto.Saltine.Internal.Util+import qualified Crypto.Saltine.Internal.ByteSizes as Bytes++import Foreign.C+import Foreign.Ptr+import Data.Word+import qualified Data.Vector.Storable as V++import Control.Applicative++-- $types++-- | An opaque 'stream' cryptographic key.+newtype Key = Key (V.Vector Word8) deriving (Eq, Ord)++instance IsEncoding Key where+ decode v = case V.length v == Bytes.streamKey of+ True -> Just (Key v)+ False -> Nothing+ {-# INLINE decode #-}+ encode (Key v) = v+ {-# INLINE encode #-}++-- | An opaque 'stream' nonce.+newtype Nonce = Nonce (V.Vector Word8) deriving (Eq, Ord)++instance IsNonce Nonce where+ zero = Nonce (V.replicate Bytes.streamNonce 0)+ nudge (Nonce n) = Nonce (nudgeVector n)++instance IsEncoding Nonce where+ decode v = case V.length v == Bytes.streamNonce of+ True -> Just (Nonce v)+ False -> Nothing+ {-# INLINE decode #-}+ encode (Nonce v) = v+ {-# INLINE encode #-}++-- | Creates a random key of the correct size for 'stream' and 'xor'.+newKey :: IO Key+newKey = Key <$> randomVector Bytes.streamKey++-- | Creates a random nonce of the correct size for 'stream' and+-- 'xor'.+newNonce :: IO Nonce+newNonce = Nonce <$> randomVector Bytes.streamNonce++-- | Generates a cryptographic random stream indexed by the 'Key' and+-- '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+ -- ^ Cryptographic stream+stream (Key key) (Nonce nonce) n =+ snd . buildUnsafeCVector n $ \ps ->+ constVectors [key, nonce] $ \[pk, pn] ->+ c_stream ps (fromIntegral n) pn pk++-- | Computes the exclusive-or between a message and a cryptographic+-- random stream indexed by the 'Key' and the 'Nonce'. This renders+-- the output indistinguishable from random noise so long as the+-- 'Nonce' is not used more than once. /Note:/ while this can be used+-- for encryption and decryption, it is /possible for an attacker to/+-- /manipulate the message in transit without detection/. USE AT YOUR+-- OWN RISK.+xor :: Key -> Nonce + -> V.Vector Word8+ -- ^ Message+ -> V.Vector Word8+ -- ^ Ciphertext+xor (Key key) (Nonce nonce) msg =+ snd . buildUnsafeCVector len $ \pc ->+ constVectors [key, nonce, msg] $ \[pk, pn, pm] ->+ c_stream_xor pc pm (fromIntegral len) pn pk+ where len = V.length msg++foreign import ccall "crypto_stream"+ c_stream :: Ptr Word8+ -- ^ Stream output buffer+ -> CULLong+ -- ^ Length of stream to generate+ -> Ptr Word8+ -- ^ Constant nonce buffer+ -> Ptr Word8+ -- ^ Constant key buffer+ -> IO CInt+ -- ^ Always 0++foreign import ccall "crypto_stream_xor"+ c_stream_xor :: Ptr Word8+ -- ^ Ciphertext output buffer+ -> Ptr Word8+ -- ^ Constant message buffer+ -> CULLong+ -- ^ Length of message buffer+ -> Ptr Word8+ -- ^ Constant nonce buffer+ -> Ptr Word8+ -- ^ Constant key buffer+ -> IO CInt+ -- ^ Always 0
+ src/Crypto/Saltine/Internal/ByteSizes.hs view
@@ -0,0 +1,414 @@+{-# LANGUAGE ForeignFunctionInterface #-}+-- |+-- Module : Crypto.Saltine.Core.ScalarMult+-- Copyright : (c) Joseph Abrahamson 2013+-- License : MIT+-- +-- Maintainer : me@jspha.com+-- Stability : experimental+-- Portability : non-portable+-- +-- Various sizes+-- +-- While technically these sizes are hidden behind opaque newtype+-- wrappers, they can be useful for computation and sizing and are+-- thus exposed.+-- +-- As of @libsodium-4.1@ some of these sizes are not exported and thus+-- are hardcoded here. This limitation should be removed in later+-- versions of @libsodium@.+module Crypto.Saltine.Internal.ByteSizes (++ auth,+ authKey,+ boxPK,+ boxSK,+ boxNonce,+ boxZero,+ boxBoxZero,+ boxMac,+ boxBeforeNM,+ onetime,+ onetimeKey,+ mult,+ multScalar,+ secretBoxKey,+ secretBoxNonce,+ secretBoxZero,+ secretBoxBoxZero,+ sign,+ signPK,+ signSK,+ streamKey,+ streamNonce,+ hash,+ shorthash,+ shorthashKey+ + ) where++import Foreign.C++-- Constants for++auth, authKey :: Int+boxPK, boxSK, boxNonce, boxZero, boxBoxZero, boxMac, boxBeforeNM :: Int+onetime, onetimeKey :: Int+mult, multScalar :: Int+secretBoxKey, secretBoxNonce, secretBoxZero, secretBoxBoxZero :: Int+sign, signPK, signSK :: Int+streamKey, streamNonce :: Int+hash, shorthash, shorthashKey :: Int+++-- Authentication+-- | Size of a @crypto_auth@ authenticator.+auth = fromIntegral c_crypto_auth_bytes+-- | Size of a @crypto_auth@ authenticator key. +authKey = fromIntegral c_crypto_auth_keybytes++-- Box+-- | Size of a @crypto_box@ public key+boxPK = fromIntegral c_crypto_box_publickeybytes+-- | Size of a @crypto_box@ secret key+boxSK = fromIntegral c_crypto_box_secretkeybytes+-- | Size of a @crypto_box@ nonce+boxNonce = fromIntegral c_crypto_box_noncebytes+-- | Size of 0-padding prepended to messages before using @crypto_box@+-- or after using @crypto_box_open@+boxZero = fromIntegral c_crypto_box_zerobytes+-- | Size of 0-padding prepended to ciphertext before using+-- @crypto_box_open@ or after using @crypto_box@.+boxBoxZero = fromIntegral c_crypto_box_boxzerobytes+boxMac = fromIntegral c_crypto_box_macbytes+-- | Size of a @crypto_box_beforenm@-generated combined key+boxBeforeNM =+ fromIntegral c_crypto_box_beforenmbytes++-- OneTimeAuth+-- | Size of a @crypto_onetimeauth@ authenticator.+onetime = fromIntegral c_crypto_onetimeauth_bytes+-- | Size of a @crypto_onetimeauth@ authenticator key.+onetimeKey = fromIntegral c_crypto_onetimeauth_keybytes++-- ScalarMult+-- | Size of a group element string representation for+-- @crypto_scalarmult@.+mult = fromIntegral c_crypto_scalarmult_bytes+-- | Size of a integer string representation for @crypto_scalarmult@.+multScalar = fromIntegral c_crypto_scalarmult_scalarbytes++-- SecretBox+-- | Size of a @crypto_secretbox@ secret key+secretBoxKey = fromIntegral c_crypto_secretbox_keybytes+-- | Size of a @crypto_secretbox@ nonce+secretBoxNonce = fromIntegral c_crypto_secretbox_noncebytes+-- | Size of 0-padding prepended to messages before using+-- @crypto_secretbox@ or after using @crypto_secretbox_open@+secretBoxZero = fromIntegral c_crypto_secretbox_zerobytes+-- | Size of 0-padding prepended to ciphertext before using+-- @crypto_secretbox_open@ or after using @crypto_secretbox@+secretBoxBoxZero = fromIntegral c_crypto_secretbox_boxzerobytes++-- Signatures+-- | The maximum size of a signature prepended to a message to form a+-- signed message.+sign = fromIntegral c_crypto_sign_bytes+-- | The size of a public key for signing verification+signPK = fromIntegral c_crypto_sign_publickeybytes+-- | The size of a secret key for signing+signSK = fromIntegral c_crypto_sign_secretkeybytes++-- Streams+-- | The size of a key for the cryptographic stream generation+streamKey = fromIntegral c_crypto_stream_keybytes+-- | The size of a nonce for the cryptographic stream generation+streamNonce = fromIntegral c_crypto_stream_noncebytes++-- Hashes+-- | The size of a hash resulting from+-- 'Crypto.Saltine.Internal.Hash.hash'.+hash = fromIntegral c_crypto_hash_bytes+-- | The size of a keyed hash resulting from+-- 'Crypto.Saltine.Internal.Hash.shorthash'.+shorthash = fromIntegral c_crypto_shorthash_bytes+-- | The size of a hashing key for the keyed hash function+-- 'Crypto.Saltine.Internal.Hash.shorthash'.+shorthashKey = fromIntegral c_crypto_shorthash_keybytes++-- src/libsodium/crypto_auth/crypto_auth.c+foreign import ccall "crypto_auth_bytes"+ c_crypto_auth_bytes :: CSize+foreign import ccall "crypto_auth_keybytes"+ c_crypto_auth_keybytes :: CSize++-- src/libsodium/crypto_box/crypto_box.c+foreign import ccall "crypto_box_publickeybytes"+ c_crypto_box_publickeybytes :: CSize+foreign import ccall "crypto_box_secretkeybytes"+ c_crypto_box_secretkeybytes :: CSize+foreign import ccall "crypto_box_beforenmbytes"+ c_crypto_box_beforenmbytes :: CSize+foreign import ccall "crypto_box_noncebytes"+ c_crypto_box_noncebytes :: CSize+foreign import ccall "crypto_box_zerobytes"+ c_crypto_box_zerobytes :: CSize+foreign import ccall "crypto_box_boxzerobytes"+ c_crypto_box_boxzerobytes :: CSize+foreign import ccall "crypto_box_macbytes"+ c_crypto_box_macbytes :: CSize+ +-- src/libsodium/crypto_onetimeauth/crypto_onetimeauth.c+foreign import ccall "crypto_onetimeauth_bytes"+ c_crypto_onetimeauth_bytes :: CSize+foreign import ccall "crypto_onetimeauth_keybytes"+ c_crypto_onetimeauth_keybytes :: CSize++-- src/libsodium/crypto_scalarmult/crypto_scalarmult.c+foreign import ccall "crypto_scalarmult_bytes"+ c_crypto_scalarmult_bytes :: CSize+foreign import ccall "crypto_scalarmult_scalarbytes"+ c_crypto_scalarmult_scalarbytes :: CSize++-- src/libsodium/crypto_secretbox/crypto_secretbox.c+foreign import ccall "crypto_secretbox_keybytes"+ c_crypto_secretbox_keybytes :: CSize+foreign import ccall "crypto_secretbox_noncebytes"+ c_crypto_secretbox_noncebytes :: CSize+foreign import ccall "crypto_secretbox_zerobytes"+ c_crypto_secretbox_zerobytes :: CSize+foreign import ccall "crypto_secretbox_boxzerobytes"+ c_crypto_secretbox_boxzerobytes :: CSize++-- src/libsodium/crypto_sign/crypto_sign.c+foreign import ccall "crypto_sign_bytes"+ c_crypto_sign_bytes :: CSize+foreign import ccall "crypto_sign_publickeybytes"+ c_crypto_sign_publickeybytes :: CSize+foreign import ccall "crypto_sign_secretkeybytes"+ c_crypto_sign_secretkeybytes :: CSize++-- HARDCODED+-- ---------++-- | The size of a @crypto_stream@ or @crypto_stream_xor@+-- key. HARDCODED to be @crypto_stream_xsalsa20@ for now until Sodium+-- exports the C constant.+c_crypto_stream_keybytes :: CSize+c_crypto_stream_keybytes = 32++-- | The size of a @crypto_stream@ or @crypto_stream_xor@+-- nonce. HARDCODED to be @crypto_stream_xsalsa20@ for now until+-- Sodium exports the C constant.+c_crypto_stream_noncebytes :: CSize+c_crypto_stream_noncebytes = 24++-- | The size of a @crypto_hash@ output hash. HARDCODED to be+-- @crypto_hash_sha512@ for now until Sodium exports the C constant.+c_crypto_hash_bytes :: CSize+c_crypto_hash_bytes = 64++-- | The size of a @crypto_shorthash@ output hash. HARDCODED to be+-- @crypto_shorthash_siphash24@ for now until Sodium exports the C+-- constant.+c_crypto_shorthash_bytes :: CSize+c_crypto_shorthash_bytes = 8++-- | The size of a @crypto_shorthash@ key. HARDCODED to be+-- @crypto_shorthash_siphash24@ for now until Sodium exports the C+-- constant.+c_crypto_shorthash_keybytes :: CSize+c_crypto_shorthash_keybytes = 16+++-- src/libsodium/crypto_stream/crypto_stream.c+-- foreign import ccall "crypto_stream_keybytes"+-- c_crypto_stream_keybytes :: CSize+-- foreign import ccall "crypto_stream_noncebytes"+-- c_crypto_stream_noncebytes :: CSize++-- src/libsodium/crypto_shorthash/crypto_shorthash.c+-- foreign import ccall "crypto_shorthash_bytes"+-- c_crypto_shorthash_bytes :: CSize+-- foreign import ccall "crypto_shorthash_keybytes"+-- c_crypto_shorthash_keybytes :: CSize++-- Others+-- ------++-- src/libsodium/crypto_auth/hmacsha256/auth_hmacsha256_api.c+-- foreign import ccall "crypto_auth_hmacsha256_bytes"+-- c_crypto_auth_hmacsha256_bytes :: CSize+-- foreign import ccall "crypto_auth_hmacsha256_keybytes"+-- c_crypto_auth_hmacsha256_keybytes :: CSize++-- src/libsodium/crypto_auth/hmacsha512256/auth_hmacsha512256_api.c+-- foreign import ccall "crypto_auth_hmacsha512256_bytes"+-- c_crypto_auth_hmacsha512256_bytes :: CSize+-- foreign import ccall "crypto_auth_hmacsha512256_keybytes"+-- c_crypto_auth_hmacsha512256_keybytes :: CSize++-- src/libsodium/crypto_box/curve25519xsalsa20poly1305/box_curve25519xsalsa20poly1305_api.c+-- foreign import ccall "crypto_box_curve25519xsalsa20poly1305_publickeybytes"+-- c_crypto_box_curve25519xsalsa20poly1305_publickeybytes :: CSize+-- foreign import ccall "crypto_box_curve25519xsalsa20poly1305_secretkeybytes"+-- c_crypto_box_curve25519xsalsa20poly1305_secretkeybytes :: CSize+-- foreign import ccall "crypto_box_curve25519xsalsa20poly1305_beforenmbytes"+-- c_crypto_box_curve25519xsalsa20poly1305_beforenmbytes :: CSize+-- foreign import ccall "crypto_box_curve25519xsalsa20poly1305_noncebytes"+-- c_crypto_box_curve25519xsalsa20poly1305_noncebytes :: CSize+-- foreign import ccall "crypto_box_curve25519xsalsa20poly1305_zerobytes"+-- c_crypto_box_curve25519xsalsa20poly1305_zerobytes :: CSize+-- foreign import ccall "crypto_box_curve25519xsalsa20poly1305_boxzerobytes"+-- c_crypto_box_curve25519xsalsa20poly1305_boxzerobytes :: CSize+-- foreign import ccall "crypto_box_curve25519xsalsa20poly1305_macbytes"+-- c_crypto_box_curve25519xsalsa20poly1305_macbytes :: CSize++-- src/libsodium/crypto_core/hsalsa20/core_hsalsa20_api.c+-- foreign import ccall "crypto_core_hsalsa20_outputbytes"+-- c_crypto_core_hsalsa20_outputbytes :: CSize+-- foreign import ccall "crypto_core_hsalsa20_inputbytes"+-- c_crypto_core_hsalsa20_inputbytes :: CSize+-- foreign import ccall "crypto_core_hsalsa20_keybytes"+-- c_crypto_core_hsalsa20_keybytes :: CSize+-- foreign import ccall "crypto_core_hsalsa20_constbytes"+-- c_crypto_core_hsalsa20_constbytes :: CSize++-- src/libsodium/crypto_core/salsa20/core_salsa20_api.c+-- foreign import ccall "crypto_core_salsa20_outputbytes"+-- c_crypto_core_salsa20_outputbytes :: CSize+-- foreign import ccall "crypto_core_salsa20_inputbytes"+-- c_crypto_core_salsa20_inputbytes :: CSize+-- foreign import ccall "crypto_core_salsa20_keybytes"+-- c_crypto_core_salsa20_keybytes :: CSize+-- foreign import ccall "crypto_core_salsa20_constbytes"+-- c_crypto_core_salsa20_constbytes :: CSize++-- src/libsodium/crypto_core/salsa2012/core_salsa2012_api.c+-- foreign import ccall "crypto_core_salsa2012_outputbytes"+-- c_crypto_core_salsa2012_outputbytes :: CSize+-- foreign import ccall "crypto_core_salsa2012_inputbytes"+-- c_crypto_core_salsa2012_inputbytes :: CSize+-- foreign import ccall "crypto_core_salsa2012_keybytes"+-- c_crypto_core_salsa2012_keybytes :: CSize+-- foreign import ccall "crypto_core_salsa2012_constbytes"+-- c_crypto_core_salsa2012_constbytes :: CSize++-- src/libsodium/crypto_core/salsa208/core_salsa208_api.c+-- foreign import ccall "crypto_core_salsa208_outputbytes"+-- c_crypto_core_salsa208_outputbytes :: CSize+-- foreign import ccall "crypto_core_salsa208_inputbytes"+-- c_crypto_core_salsa208_inputbytes :: CSize+-- foreign import ccall "crypto_core_salsa208_keybytes"+-- c_crypto_core_salsa208_keybytes :: CSize+-- foreign import ccall "crypto_core_salsa208_constbytes"+-- c_crypto_core_salsa208_constbytes :: CSize++-- src/libsodium/crypto_generichash/blake2/generichash_blake2_api.c+-- foreign import ccall "crypto_generichash_blake2b_blockbytes"+-- c_crypto_generichash_blake2b_blockbytes :: CSize++-- src/libsodium/crypto_generichash/crypto_generichash.c+-- foreign import ccall "crypto_generichash_bytes"+-- c_crypto_generichash_bytes :: CSize+-- foreign import ccall "crypto_generichash_keybytes"+-- c_crypto_generichash_keybytes :: CSize+-- foreign import ccall "crypto_generichash_blockbytes"+-- c_crypto_generichash_blockbytes :: CSize++-- src/libsodium/crypto_hash/sha256/hash_sha256_api.c+-- foreign import ccall "crypto_hash_sha256_bytes"+-- c_crypto_hash_sha256_bytes :: CSize++-- src/libsodium/crypto_hash/sha512/hash_sha512_api.c+-- foreign import ccall "crypto_hash_sha512_bytes"+-- c_crypto_hash_sha512_bytes :: CSize++-- src/libsodium/crypto_hashblocks/sha256/hashblocks_sha256_api.c+-- foreign import ccall "crypto_hashblocks_sha256_statebytes"+-- c_crypto_hashblocks_sha256_statebytes :: CSize+-- foreign import ccall "crypto_hashblocks_sha256_blockbytes"+-- c_crypto_hashblocks_sha256_blockbytes :: CSize++-- src/libsodium/crypto_hashblocks/sha512/hashblocks_sha512_api.c+-- foreign import ccall "crypto_hashblocks_sha512_statebytes"+-- c_crypto_hashblocks_sha512_statebytes :: CSize+-- foreign import ccall "crypto_hashblocks_sha512_blockbytes"+-- c_crypto_hashblocks_sha512_blockbytes :: CSize++-- src/libsodium/crypto_onetimeauth/poly1305/onetimeauth_poly1305_api.c+-- foreign import ccall "crypto_onetimeauth_poly1305_bytes"+-- c_crypto_onetimeauth_poly1305_bytes :: CSize+-- foreign import ccall "crypto_onetimeauth_poly1305_keybytes"+-- c_crypto_onetimeauth_poly1305_keybytes :: CSize++-- src/libsodium/crypto_secretbox/xsalsa20poly1305/secretbox_xsalsa20poly1305_api.c+-- foreign import ccall "crypto_secretbox_xsalsa20poly1305_keybytes"+-- c_crypto_secretbox_xsalsa20poly1305_keybytes :: CSize+-- foreign import ccall "crypto_secretbox_xsalsa20poly1305_noncebytes"+-- c_crypto_secretbox_xsalsa20poly1305_noncebytes :: CSize+-- foreign import ccall "crypto_secretbox_xsalsa20poly1305_zerobytes"+-- c_crypto_secretbox_xsalsa20poly1305_zerobytes :: CSize+-- foreign import ccall "crypto_secretbox_xsalsa20poly1305_boxzerobytes"+-- c_crypto_secretbox_xsalsa20poly1305_boxzerobytes :: CSize++-- foreign import ccall "crypto_shorthash_siphash24_bytes"+-- c_crypto_shorthash_siphash24_bytes :: CSize++-- src/libsodium/crypto_sign/ed25519/sign_ed25519_api.c+-- foreign import ccall "crypto_sign_ed25519_bytes"+-- c_crypto_sign_ed25519_bytes :: CSize+-- foreign import ccall "crypto_sign_ed25519_publickeybytes"+-- c_crypto_sign_ed25519_publickeybytes :: CSize+-- foreign import ccall "crypto_sign_ed25519_secretkeybytes"+-- c_crypto_sign_ed25519_secretkeybytes :: CSize++-- src/libsodium/crypto_sign/edwards25519sha512batch/sign_edwards25519sha512batch_api.c+-- foreign import ccall "crypto_sign_edwards25519sha512batch_bytes"+-- c_crypto_sign_edwards25519sha512batch_bytes :: CSize+-- foreign import ccall "crypto_sign_edwards25519sha512batch_publickeybytes"+-- c_crypto_sign_edwards25519sha512batch_publickeybytes :: CSize+-- foreign import ccall "crypto_sign_edwards25519sha512batch_secretkeybytes"+-- c_crypto_sign_edwards25519sha512batch_secretkeybytes :: CSize++-- src/libsodium/crypto_stream/aes128ctr/stream_aes128ctr_api.c+-- foreign import ccall "crypto_stream_aes128ctr_keybytes"+-- c_crypto_stream_aes128ctr_keybytes :: CSize+-- foreign import ccall "crypto_stream_aes128ctr_noncebytes"+-- c_crypto_stream_aes128ctr_noncebytes :: CSize+-- foreign import ccall "crypto_stream_aes128ctr_beforenmbytes"+-- c_crypto_stream_aes128ctr_beforenmbytes :: CSize++-- src/libsodium/crypto_stream/aes256estream/stream_aes256estream_api.c+-- foreign import ccall "crypto_stream_aes256estream_keybytes"+-- c_crypto_stream_aes256estream_keybytes :: CSize+-- foreign import ccall "crypto_stream_aes256estream_noncebytes"+-- c_crypto_stream_aes256estream_noncebytes :: CSize+-- foreign import ccall "crypto_stream_aes256estream_beforenmbytes"+-- c_crypto_stream_aes256estream_beforenmbytes :: CSize++-- src/libsodium/crypto_stream/salsa2012/stream_salsa2012_api.c+-- foreign import ccall "crypto_stream_salsa2012_keybytes"+-- c_crypto_stream_salsa2012_keybytes :: CSize+-- foreign import ccall "crypto_stream_salsa2012_noncebytes"+-- c_crypto_stream_salsa2012_noncebytes :: CSize++-- src/libsodium/crypto_stream/salsa208/stream_salsa208_api.c+-- foreign import ccall "crypto_stream_salsa208_keybytes"+-- c_crypto_stream_salsa208_keybytes :: CSize+-- foreign import ccall "crypto_stream_salsa208_noncebytes"+-- c_crypto_stream_salsa208_noncebytes :: CSize++-- src/libsodium/crypto_stream/xsalsa20/stream_xsalsa20_api.c+-- foreign import ccall "crypto_stream_xsalsa20_keybytes"+-- c_crypto_stream_xsalsa20_keybytes :: CSize+-- foreign import ccall "crypto_stream_xsalsa20_noncebytes"+-- c_crypto_stream_xsalsa20_noncebytes :: CSize++-- src/libsodium/crypto_verify/16/verify_16_api.c+-- foreign import ccall "crypto_verify_16_bytes"+-- c_crypto_verify_16_bytes :: CSize++-- src/libsodium/crypto_verify/32/verify_32_api.c+-- foreign import ccall "crypto_verify_32_bytes"+-- c_crypto_verify_32_bytes :: CSize
+ src/Crypto/Saltine/Internal/Util.hs view
@@ -0,0 +1,85 @@+module Crypto.Saltine.Internal.Util where++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 Data.STRef++foreign import ccall "randombytes_buf"+ c_randombytes_buf :: Ptr Word8 -> CInt -> IO ()++-- | 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++-- | 0-pad a vector+pad :: (VM.Storable a, Num a) => Int -> V.Vector a -> V.Vector a+pad n = mappend (V.replicate n 0)++-- | Remove a 0-padding from a vector+unpad :: VM.Storable a => Int -> V.Vector a -> V.Vector a+unpad = V.drop++-- | Converts a C-convention errno to an Either+handleErrno :: CInt -> (a -> Either String a)+handleErrno err a = case err of+ 0 -> Right a+ -1 -> Left "failed"+ n -> Left ("unexpected error code: " ++ show n)++unsafeDidSucceed :: IO CInt -> Bool+unsafeDidSucceed = go . unsafePerformIO+ where go 0 = True+ 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)))) ($ [])++-- | 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' n k = do+ buf <- mallocForeignPtrArray n+ b <- withForeignPtr buf k+ vec <- V.unsafeFreeze (VM.unsafeFromForeignPtr buf 0 n)+ return (b, vec)++-- | 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)+buildUnsafeCVector n = unsafePerformIO . buildUnsafeCVector' n++-- | Build a sized random 'V.Vector' 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++-- | To prevent a dependency on package 'errors'+hush :: Either s a -> Maybe a+hush = either (const Nothing) Just
+ tests/Main.hs view
@@ -0,0 +1,22 @@+{-# LANGUAGE OverloadedStrings #-}++module Main where++import SecretBoxProperties (testSecretBox)+import BoxProperties (testBox)+import StreamProperties (testStream)+import AuthProperties (testAuth)+import OneTimeAuthProperties (testOneTimeAuth)+import SignProperties (testSign)++import Test.Framework++main :: IO ()+main = defaultMain [+ testBox,+ testSecretBox,+ testStream,+ testAuth,+ testOneTimeAuth,+ testSign+ ]