-- | -- 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: ). 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.\" -- . -- -- 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