packages feed

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 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+  ]