{-# LANGUAGE DeriveDataTypeable, GeneralizedNewtypeDeriving, DeriveGeneric, ForeignFunctionInterface #-} -- | -- Module : Crypto.Saltine.Internal.SecretBox -- Copyright : (c) Max Amanshauser 2021 -- License : MIT -- -- Maintainer : max@lambdalifting.org -- Stability : experimental -- Portability : non-portable -- module Crypto.Saltine.Internal.SecretBox ( secretbox_keybytes, secretbox_noncebytes, secretbox_macbytes, secretbox_zerobytes, secretbox_boxzerobytes, c_secretbox, c_secretbox_detached, c_secretbox_open, c_secretbox_open_detached, Key(..), Nonce(..), Authenticator(..) ) where import Control.DeepSeq (NFData) import Crypto.Saltine.Class import Crypto.Saltine.Core.Hash (shorthash) import Crypto.Saltine.Internal.Hash (nullShKey) import Crypto.Saltine.Internal.Util as U import Data.ByteString (ByteString) import Data.Data (Data, Typeable) import Data.Hashable (Hashable) import Data.Monoid import Foreign.C import Foreign.Ptr import GHC.Generics (Generic) import qualified Data.ByteString as S secretbox_keybytes, secretbox_noncebytes, secretbox_macbytes, secretbox_zerobytes, secretbox_boxzerobytes :: Int -- | An opaque 'secretbox' cryptographic key. newtype Key = Key { unKey :: ByteString } deriving (Ord, Hashable, Data, Typeable, Generic, NFData) instance Eq Key where Key a == Key b = U.compare a b instance Show Key where show k = "SecretBox.Key {hashesTo = \"" <> (bin2hex . shorthash nullShKey $ encode k) <> "\"}" instance IsEncoding Key where decode v = if S.length v == secretbox_keybytes then Just (Key v) else Nothing {-# INLINE decode #-} encode (Key v) = v {-# INLINE encode #-} -- | An opaque 'secretbox' nonce. newtype Nonce = Nonce { unNonce :: ByteString } deriving (Eq, Ord, Hashable, Data, Typeable, Generic, NFData) instance Show Nonce where show k = "SecretBox.Nonce " <> bin2hex (encode k) instance IsEncoding Nonce where decode v = if S.length v == secretbox_noncebytes then Just (Nonce v) else Nothing {-# INLINE decode #-} encode (Nonce v) = v {-# INLINE encode #-} instance IsNonce Nonce where zero = Nonce (S.replicate secretbox_noncebytes 0) nudge (Nonce n) = Nonce (nudgeBS n) -- | An Authenticator for a Message newtype Authenticator = Au { unAu :: ByteString } deriving (Eq, Ord, Data, Typeable, Hashable, Generic, NFData) instance Show Authenticator where show k = "Sign.Authenticator " <> bin2hex (encode k) instance IsEncoding Authenticator where decode v = if S.length v == secretbox_macbytes then Just (Au v) else Nothing {-# INLINE decode #-} encode (Au v) = v {-# INLINE encode #-} -- | Size of a @crypto_secretbox@ secret key secretbox_keybytes = fromIntegral c_crypto_secretbox_keybytes -- | Size of a @crypto_secretbox@ nonce secretbox_noncebytes = fromIntegral c_crypto_secretbox_noncebytes -- | Size of a @crypto_secretbox@ mac secretbox_macbytes = fromIntegral c_crypto_secretbox_macbytes -- | Size of 0-padding prepended to messages before using -- @crypto_secretbox@ or after using @crypto_secretbox_open@ secretbox_zerobytes = fromIntegral c_crypto_secretbox_zerobytes -- | Size of 0-padding prepended to ciphertext before using -- @crypto_secretbox_open@ or after using @crypto_secretbox@ secretbox_boxzerobytes = fromIntegral c_crypto_secretbox_boxzerobytes -- 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_macbytes" c_crypto_secretbox_macbytes :: CSize foreign import ccall "crypto_secretbox_zerobytes" c_crypto_secretbox_zerobytes :: CSize foreign import ccall "crypto_secretbox_boxzerobytes" c_crypto_secretbox_boxzerobytes :: CSize -- | The secretbox C API uses 0-padded C strings. Always returns 0. foreign import ccall "crypto_secretbox" c_secretbox :: Ptr CChar -- ^ Cipher 0-padded output buffer -> Ptr CChar -- ^ Constant 0-padded message input buffer -> CULLong -- ^ Length of message input buffer (incl. 0s) -> Ptr CChar -- ^ Constant nonce buffer -> Ptr CChar -- ^ Constant key buffer -> IO CInt -- | The secretbox_detached C API uses C strings. Always returns 0. foreign import ccall "crypto_secretbox_detached" c_secretbox_detached :: Ptr CChar -- ^ Ciphertext output buffer -> Ptr CChar -- ^ Authentication tag output buffer -> Ptr CChar -- ^ Constant message input buffer -> CULLong -- ^ Length of message input buffer (incl. 0s) -> Ptr CChar -- ^ Constant nonce buffer -> Ptr CChar -- ^ Constant key buffer -> IO CInt -- | The secretbox C API uses 0-padded C strings. Returns 0 if -- successful or -1 if verification failed. foreign import ccall "crypto_secretbox_open" c_secretbox_open :: Ptr CChar -- ^ Message 0-padded output buffer -> Ptr CChar -- ^ Constant 0-padded message input buffer -> CULLong -- ^ Length of message input buffer (incl. 0s) -> Ptr CChar -- ^ Constant nonce buffer -> Ptr CChar -- ^ Constant key buffer -> IO CInt -- | The secretbox C API uses C strings. Returns 0 if -- successful or -1 if verification failed. foreign import ccall "crypto_secretbox_open_detached" c_secretbox_open_detached :: Ptr CChar -- ^ Message output buffer -> Ptr CChar -- ^ Constant ciphertext input buffer -> Ptr CChar -- ^ Constant auth tag input buffer -> CULLong -- ^ Length of ciphertext input buffer -> Ptr CChar -- ^ Constant nonce buffer -> Ptr CChar -- ^ Constant key buffer -> IO CInt