packages feed

saltine-0.0.0.2: src/Crypto/Saltine/Core/Auth.hs

-- |
-- 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 'ByteString' using a
-- secret key The function returns an authenticator. The 'verify'
-- function checks if it's passed a correct authenticator of a message
-- under the given secret key.
-- 
-- 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 qualified Data.ByteString as S
import           Data.ByteString (ByteString)

import Control.Applicative

-- $types

-- | An opaque 'auth' cryptographic key.
newtype Key = Key ByteString deriving (Eq, Ord)

-- | An opaque 'auth' authenticator.
newtype Authenticator = Au ByteString deriving (Eq, Ord)

instance IsEncoding Key where
  decode v = case S.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 S.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 'ByteString' from a message. It
-- is infeasible to forge these authenticators without the key, even
-- if an attacker observes many authenticators and messages and has
-- the ability to influence the messages sent.
auth :: Key 
        -> ByteString
        -- ^ Message
        -> Authenticator
auth (Key key) msg =
  Au . snd . buildUnsafeCVector Bytes.auth $ \pa ->
    constVectors [key, msg] $ \[(pk, _), (pm, mlen)] ->
    c_auth pa pm (fromIntegral mlen) pk

-- | Checks to see if an authenticator is a correct proof that a
-- message was signed by some key.
verify :: Key
          -> Authenticator
          -> ByteString
          -- ^ Message
          -> Bool
          -- ^ Is this message authentic?
verify (Key key) (Au a) msg =
  unsafeDidSucceed $ constVectors [key, msg, a] $ \[(pk, _), (pm, mlen), (pa, _)] ->
  return $ c_auth_verify pa pm (fromIntegral mlen) pk

foreign import ccall "crypto_auth"
  c_auth :: Ptr CChar
            -- ^ Authenticator output buffer
            -> Ptr CChar
            -- ^ Constant message buffer
            -> CULLong
            -- ^ Length of message buffer
            -> Ptr CChar
            -- ^ 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 CChar
                   -- ^ Constant authenticator buffer
                   -> Ptr CChar
                   -- ^ Constant message buffer
                   -> CULLong
                   -- ^ Length of message buffer
                   -> Ptr CChar
                   -- ^ Constant key buffer
                   -> CInt
                   -- ^ Success if 0, failure if -1