diff --git a/Crypto/PubKey/ECC/ECDSA.hs b/Crypto/PubKey/ECC/ECDSA.hs index 4cfc4b8..175f75c 100644 --- a/Crypto/PubKey/ECC/ECDSA.hs +++ b/Crypto/PubKey/ECC/ECDSA.hs @@ -11,8 +11,11 @@ module Crypto.PubKey.ECC.ECDSA , toPublicKey , toPrivateKey , signWith + , signDigestWith , sign + , signDigest , verify + , verifyDigest ) where import Control.Monad @@ -24,7 +27,7 @@ import Crypto.Number.ModArithmetic (inverse) import Crypto.Number.Generate import Crypto.PubKey.ECC.Types import Crypto.PubKey.ECC.Prim -import Crypto.PubKey.Internal (dsaTruncHash) +import Crypto.PubKey.Internal (dsaTruncHashDigest) import Crypto.Random.Types -- | Represent a ECDSA signature namely R and S. @@ -57,17 +60,16 @@ toPublicKey (KeyPair curve pub _) = PublicKey curve pub toPrivateKey :: KeyPair -> PrivateKey toPrivateKey (KeyPair curve _ priv) = PrivateKey curve priv --- | Sign message using the private key and an explicit k number. +-- | Sign digest using the private key and an explicit k number. -- -- /WARNING:/ Vulnerable to timing attacks. -signWith :: (ByteArrayAccess msg, HashAlgorithm hash) - => Integer -- ^ k random number - -> PrivateKey -- ^ private key - -> hash -- ^ hash function - -> msg -- ^ message to sign - -> Maybe Signature -signWith k (PrivateKey curve d) hashAlg msg = do - let z = dsaTruncHash hashAlg msg n +signDigestWith :: HashAlgorithm hash + => Integer -- ^ k random number + -> PrivateKey -- ^ private key + -> Digest hash -- ^ digest to sign + -> Maybe Signature +signDigestWith k (PrivateKey curve d) digest = do + let z = dsaTruncHashDigest digest n CurveCommon _ _ g n _ = common_curve curve let point = pointMul curve k g r <- case point of @@ -78,26 +80,44 @@ signWith k (PrivateKey curve d) hashAlg msg = do when (r == 0 || s == 0) Nothing return $ Signature r s +-- | Sign message using the private key and an explicit k number. +-- +-- /WARNING:/ Vulnerable to timing attacks. +signWith :: (ByteArrayAccess msg, HashAlgorithm hash) + => Integer -- ^ k random number + -> PrivateKey -- ^ private key + -> hash -- ^ hash function + -> msg -- ^ message to sign + -> Maybe Signature +signWith k pk hashAlg msg = signDigestWith k pk (hashWith hashAlg msg) + +-- | Sign digest using the private key. +-- +-- /WARNING:/ Vulnerable to timing attacks. +signDigest :: (HashAlgorithm hash, MonadRandom m) + => PrivateKey -> Digest hash -> m Signature +signDigest pk digest = do + k <- generateBetween 1 (n - 1) + case signDigestWith k pk digest of + Nothing -> signDigest pk digest + Just sig -> return sig + where n = ecc_n . common_curve $ private_curve pk + -- | Sign message using the private key. -- -- /WARNING:/ Vulnerable to timing attacks. sign :: (ByteArrayAccess msg, HashAlgorithm hash, MonadRandom m) => PrivateKey -> hash -> msg -> m Signature -sign pk hashAlg msg = do - k <- generateBetween 1 (n - 1) - case signWith k pk hashAlg msg of - Nothing -> sign pk hashAlg msg - Just sig -> return sig - where n = ecc_n . common_curve $ private_curve pk +sign pk hashAlg msg = signDigest pk (hashWith hashAlg msg) --- | Verify a bytestring using the public key. -verify :: (ByteArrayAccess msg, HashAlgorithm hash) => hash -> PublicKey -> Signature -> msg -> Bool -verify _ (PublicKey _ PointO) _ _ = False -verify hashAlg pk@(PublicKey curve q) (Signature r s) msg +-- | Verify a digest using the public key. +verifyDigest :: HashAlgorithm hash => PublicKey -> Signature -> Digest hash -> Bool +verifyDigest (PublicKey _ PointO) _ _ = False +verifyDigest pk@(PublicKey curve q) (Signature r s) digest | r < 1 || r >= n || s < 1 || s >= n = False | otherwise = maybe False (r ==) $ do w <- inverse s n - let z = dsaTruncHash hashAlg msg n + let z = dsaTruncHashDigest digest n u1 = z * w `mod` n u2 = r * w `mod` n x = pointAddTwoMuls curve u1 g u2 q @@ -107,3 +127,7 @@ verify hashAlg pk@(PublicKey curve q) (Signature r s) msg where n = ecc_n cc g = ecc_g cc cc = common_curve $ public_curve pk + +-- | Verify a bytestring using the public key. +verify :: (ByteArrayAccess msg, HashAlgorithm hash) => hash -> PublicKey -> Signature -> msg -> Bool +verify hashAlg pk sig msg = verifyDigest pk sig (hashWith hashAlg msg) diff --git a/Crypto/PubKey/Internal.hs b/Crypto/PubKey/Internal.hs index b1631cc..3951d06 100644 --- a/Crypto/PubKey/Internal.hs +++ b/Crypto/PubKey/Internal.hs @@ -9,6 +9,7 @@ module Crypto.PubKey.Internal ( and' , (&&!) , dsaTruncHash + , dsaTruncHashDigest ) where import Data.Bits (shiftR) @@ -32,8 +33,15 @@ False &&! False = False -- | Truncate and hash for DSA and ECDSA. dsaTruncHash :: (ByteArrayAccess msg, HashAlgorithm hash) => hash -> msg -> Integer -> Integer -dsaTruncHash hashAlg m n +dsaTruncHash hashAlg = dsaTruncHashDigest . hashWith hashAlg + +-- | Truncate a digest for DSA and ECDSA. +dsaTruncHashDigest :: HashAlgorithm hash => Digest hash -> Integer -> Integer +dsaTruncHashDigest digest n | d > 0 = shiftR e d | otherwise = e - where e = os2ip $ hashWith hashAlg m - d = hashDigestSize hashAlg * 8 - numBits n + where e = os2ip digest + d = hashDigestSize (getHashAlg digest) * 8 - numBits n + +getHashAlg :: Digest hash -> hash +getHashAlg _ = undefined