Merge pull request #270 from ocheron/pr-241-rebased

add ECDSA sign/verify digest APIs
This commit is contained in:
Olivier Chéron 2019-03-04 06:32:43 +01:00
commit 26057fa0f6
2 changed files with 56 additions and 24 deletions

View File

@ -11,8 +11,11 @@ module Crypto.PubKey.ECC.ECDSA
, toPublicKey , toPublicKey
, toPrivateKey , toPrivateKey
, signWith , signWith
, signDigestWith
, sign , sign
, signDigest
, verify , verify
, verifyDigest
) where ) where
import Control.Monad import Control.Monad
@ -24,7 +27,7 @@ import Crypto.Number.ModArithmetic (inverse)
import Crypto.Number.Generate import Crypto.Number.Generate
import Crypto.PubKey.ECC.Types import Crypto.PubKey.ECC.Types
import Crypto.PubKey.ECC.Prim import Crypto.PubKey.ECC.Prim
import Crypto.PubKey.Internal (dsaTruncHash) import Crypto.PubKey.Internal (dsaTruncHashDigest)
import Crypto.Random.Types import Crypto.Random.Types
-- | Represent a ECDSA signature namely R and S. -- | Represent a ECDSA signature namely R and S.
@ -57,17 +60,16 @@ toPublicKey (KeyPair curve pub _) = PublicKey curve pub
toPrivateKey :: KeyPair -> PrivateKey toPrivateKey :: KeyPair -> PrivateKey
toPrivateKey (KeyPair curve _ priv) = PrivateKey curve priv 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. -- /WARNING:/ Vulnerable to timing attacks.
signWith :: (ByteArrayAccess msg, HashAlgorithm hash) signDigestWith :: HashAlgorithm hash
=> Integer -- ^ k random number => Integer -- ^ k random number
-> PrivateKey -- ^ private key -> PrivateKey -- ^ private key
-> hash -- ^ hash function -> Digest hash -- ^ digest to sign
-> msg -- ^ message to sign -> Maybe Signature
-> Maybe Signature signDigestWith k (PrivateKey curve d) digest = do
signWith k (PrivateKey curve d) hashAlg msg = do let z = dsaTruncHashDigest digest n
let z = dsaTruncHash hashAlg msg n
CurveCommon _ _ g n _ = common_curve curve CurveCommon _ _ g n _ = common_curve curve
let point = pointMul curve k g let point = pointMul curve k g
r <- case point of r <- case point of
@ -78,26 +80,44 @@ signWith k (PrivateKey curve d) hashAlg msg = do
when (r == 0 || s == 0) Nothing when (r == 0 || s == 0) Nothing
return $ Signature r s 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. -- | Sign message using the private key.
-- --
-- /WARNING:/ Vulnerable to timing attacks. -- /WARNING:/ Vulnerable to timing attacks.
sign :: (ByteArrayAccess msg, HashAlgorithm hash, MonadRandom m) sign :: (ByteArrayAccess msg, HashAlgorithm hash, MonadRandom m)
=> PrivateKey -> hash -> msg -> m Signature => PrivateKey -> hash -> msg -> m Signature
sign pk hashAlg msg = do sign pk hashAlg msg = signDigest pk (hashWith hashAlg msg)
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
-- | Verify a bytestring using the public key. -- | Verify a digest using the public key.
verify :: (ByteArrayAccess msg, HashAlgorithm hash) => hash -> PublicKey -> Signature -> msg -> Bool verifyDigest :: HashAlgorithm hash => PublicKey -> Signature -> Digest hash -> Bool
verify _ (PublicKey _ PointO) _ _ = False verifyDigest (PublicKey _ PointO) _ _ = False
verify hashAlg pk@(PublicKey curve q) (Signature r s) msg verifyDigest pk@(PublicKey curve q) (Signature r s) digest
| r < 1 || r >= n || s < 1 || s >= n = False | r < 1 || r >= n || s < 1 || s >= n = False
| otherwise = maybe False (r ==) $ do | otherwise = maybe False (r ==) $ do
w <- inverse s n w <- inverse s n
let z = dsaTruncHash hashAlg msg n let z = dsaTruncHashDigest digest n
u1 = z * w `mod` n u1 = z * w `mod` n
u2 = r * w `mod` n u2 = r * w `mod` n
x = pointAddTwoMuls curve u1 g u2 q 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 where n = ecc_n cc
g = ecc_g cc g = ecc_g cc
cc = common_curve $ public_curve pk 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)

View File

@ -9,6 +9,7 @@ module Crypto.PubKey.Internal
( and' ( and'
, (&&!) , (&&!)
, dsaTruncHash , dsaTruncHash
, dsaTruncHashDigest
) where ) where
import Data.Bits (shiftR) import Data.Bits (shiftR)
@ -32,8 +33,15 @@ False &&! False = False
-- | Truncate and hash for DSA and ECDSA. -- | Truncate and hash for DSA and ECDSA.
dsaTruncHash :: (ByteArrayAccess msg, HashAlgorithm hash) => hash -> msg -> Integer -> Integer 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 | d > 0 = shiftR e d
| otherwise = e | otherwise = e
where e = os2ip $ hashWith hashAlg m where e = os2ip digest
d = hashDigestSize hashAlg * 8 - numBits n d = hashDigestSize (getHashAlg digest) * 8 - numBits n
getHashAlg :: Digest hash -> hash
getHashAlg _ = undefined