-- | -- Module : Crypto.PubKey.DSA -- License : BSD-style -- Maintainer : Vincent Hanquez -- Stability : experimental -- Portability : Good -- -- An implementation of the Digital Signature Algorithm (DSA) module Crypto.PubKey.DSA ( Params(..) , Signature(..) , PublicKey(..) , PrivateKey(..) -- * generation , generatePrivate , calculatePublic -- * signature primitive , sign , signWith -- * verification primitive , verify ) where import Crypto.Random import Data.Maybe import Data.ByteString (ByteString) import Crypto.Number.ModArithmetic (expFast, expSafe, inverse) import Crypto.Number.Serialize import Crypto.Number.Generate import Crypto.Types.PubKey.DSA import Crypto.PubKey.HashDescr -- | generate a private number with no specific property -- this number is usually called X in DSA text. generatePrivate :: CPRG g => g -> Params -> (PrivateNumber, g) generatePrivate rng (Params _ _ q) = generateMax rng q -- | Calculate the public number from the parameters and the private key calculatePublic :: Params -> PrivateNumber -> PublicNumber calculatePublic (Params p g _) x = expSafe g x p -- | sign message using the private key and an explicit k number. signWith :: Integer -- ^ k random number -> PrivateKey -- ^ private key -> HashFunction -- ^ hash function -> ByteString -- ^ message to sign -> Maybe Signature signWith k pk hash msg | r == 0 || s == 0 = Nothing | otherwise = Just $ Signature r s where -- parameters (Params p g q) = private_params pk x = private_x pk -- compute r,s kInv = fromJust $ inverse k q hm = os2ip $ hash msg r = expSafe g k p `mod` q s = (kInv * (hm + x * r)) `mod` q -- | sign message using the private key. sign :: CPRG g => g -> PrivateKey -> HashFunction -> ByteString -> (Signature, g) sign rng pk hash msg = case signWith k pk hash msg of Nothing -> sign rng' pk hash msg Just sig -> (sig, rng') where (Params _ _ q) = private_params pk (k, rng') = generateMax rng q -- | verify a bytestring using the public key. verify :: HashFunction -> PublicKey -> Signature -> ByteString -> Bool verify hash pk (Signature r s) m -- Reject the signature if either 0 < r < q or 0 < s < q is not satisfied. | r <= 0 || r >= q || s <= 0 || s >= q = False | otherwise = v == r where (Params p g q) = public_params pk y = public_y pk hm = os2ip $ hash m w = fromJust $ inverse s q u1 = (hm*w) `mod` q u2 = (r*w) `mod` q v = ((expFast g u1 p) * (expFast y u2 p)) `mod` p `mod` q