-- |
-- 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
-- 'ByteString' 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(..), Signature,
newKeypair,
sign, signOpen,
signDetached, signVerifyDetached
) where
import Crypto.Saltine.Internal.Sign
( c_sign_keypair
, c_sign
, c_sign_open
, c_sign_detached
, c_sign_verify_detached
, SecretKey(..)
, PublicKey(..)
, Keypair(..)
, Signature(..)
)
import Crypto.Saltine.Internal.Util as U
import Data.ByteString (ByteString)
import Foreign.Marshal.Alloc
import Foreign.Storable
import System.IO.Unsafe
import qualified Crypto.Saltine.Internal.Sign as Bytes
import qualified Data.ByteString as S
-- | 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) <- buildUnsafeByteString' Bytes.sign_publickeybytes $ \pkbuf ->
buildUnsafeByteString' Bytes.sign_secretkeybytes $ \skbuf ->
c_sign_keypair pkbuf skbuf
return $ Keypair (SK sk) (PK pk)
-- | Augments a message with a signature forming a \"signed
-- message\".
sign :: SecretKey
-> ByteString
-- ^ Message
-> ByteString
-- ^ Signed message
sign (SK k) m = unsafePerformIO $
alloca $ \psmlen -> do
(_err, sm) <- buildUnsafeByteString' (len + Bytes.sign_bytes) $ \psmbuf ->
constByteStrings [k, m] $ \[(pk, _), (pm, _)] ->
c_sign psmbuf psmlen pm (fromIntegral len) pk
smlen <- peek psmlen
return $ S.take (fromIntegral smlen) sm
where len = S.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
-> ByteString
-- ^ Signed message
-> Maybe ByteString
-- ^ Maybe the restored message
signOpen (PK k) sm = unsafePerformIO $
alloca $ \pmlen -> do
(err, m) <- buildUnsafeByteString' smlen $ \pmbuf ->
constByteStrings [k, sm] $ \[(pk, _), (psm, _)] ->
c_sign_open pmbuf pmlen psm (fromIntegral smlen) pk
mlen <- peek pmlen
case err of
0 -> return $ Just $ S.take (fromIntegral mlen) m
_ -> return Nothing
where smlen = S.length sm
-- | Returns just the signature for a message using a SecretKey.
signDetached :: SecretKey
-> ByteString
-- ^ Message
-> Signature
-- ^ Signature
signDetached (SK k) m = unsafePerformIO $
alloca $ \psmlen -> do
(_err, sm) <- buildUnsafeByteString' Bytes.sign_bytes $ \sigbuf ->
constByteStrings [k, m] $ \[(pk, _), (pm, _)] ->
c_sign_detached sigbuf psmlen pm (fromIntegral len) pk
smlen <- peek psmlen
return $ Signature $ S.take (fromIntegral smlen) sm
where len = S.length m
-- | Returns @True@ if the signature is valid for the given public key and
-- message.
signVerifyDetached :: PublicKey
-> Signature
-- ^ Signature
-> ByteString
-- ^ Message (not signed)
-> Bool
signVerifyDetached (PK k) (Signature sig) sm = unsafePerformIO $
constByteStrings [k, sig, sm] $ \[(pk, _), (psig, _), (psm, _)] -> do
res <- c_sign_verify_detached psig psm (fromIntegral len) pk
return (res == 0)
where len = S.length sm