{-# LANGUAGE DeriveDataTypeable #-}
module Crypto.PubKey.DSA
( Params(..)
, Signature(..)
, PublicKey(..)
, PrivateKey(..)
, PublicNumber
, PrivateNumber
, generatePrivate
, calculatePublic
, sign
, signWith
, verify
, KeyPair(..)
, toPublicKey
, toPrivateKey
) where
import Data.Data
import Data.Maybe
import Crypto.Number.ModArithmetic (expFast, expSafe, inverse)
import Crypto.Number.Generate
import Crypto.Internal.ByteArray (ByteArrayAccess)
import Crypto.Internal.Imports
import Crypto.Hash
import Crypto.PubKey.Internal (dsaTruncHash)
import Crypto.Random.Types
type PublicNumber = Integer
type PrivateNumber = Integer
data Params = Params
{ params_p :: Integer
, params_g :: Integer
, params_q :: Integer
} deriving (Show,Read,Eq,Data)
instance NFData Params where
rnf (Params p g q) = p `seq` g `seq` q `seq` ()
data Signature = Signature
{ sign_r :: Integer
, sign_s :: Integer
} deriving (Show,Read,Eq,Data)
instance NFData Signature where
rnf (Signature r s) = r `seq` s `seq` ()
data PublicKey = PublicKey
{ public_params :: Params
, public_y :: PublicNumber
} deriving (Show,Read,Eq,Data)
instance NFData PublicKey where
rnf (PublicKey params y) = y `seq` params `seq` ()
data PrivateKey = PrivateKey
{ private_params :: Params
, private_x :: PrivateNumber
} deriving (Show,Read,Eq,Data)
instance NFData PrivateKey where
rnf (PrivateKey params x) = x `seq` params `seq` ()
data KeyPair = KeyPair Params PublicNumber PrivateNumber
deriving (Show,Read,Eq,Data)
instance NFData KeyPair where
rnf (KeyPair params y x) = x `seq` y `seq` params `seq` ()
toPublicKey :: KeyPair -> PublicKey
toPublicKey (KeyPair params pub _) = PublicKey params pub
toPrivateKey :: KeyPair -> PrivateKey
toPrivateKey (KeyPair params _ priv) = PrivateKey params priv
generatePrivate :: MonadRandom m => Params -> m PrivateNumber
generatePrivate (Params _ _ q) = generateMax q
calculatePublic :: Params -> PrivateNumber -> PublicNumber
calculatePublic (Params p g _) x = expSafe g x p
signWith :: (ByteArrayAccess msg, HashAlgorithm hash)
=> Integer
-> PrivateKey
-> hash
-> msg
-> Maybe Signature
signWith k pk hashAlg msg
| r == 0 || s == 0 = Nothing
| otherwise = Just $ Signature r s
where
(Params p g q) = private_params pk
x = private_x pk
kInv = fromJust $ inverse k q
hm = dsaTruncHash hashAlg msg q
r = expSafe g k p `mod` q
s = (kInv * (hm + x * r)) `mod` q
sign :: (ByteArrayAccess msg, HashAlgorithm hash, MonadRandom m) => PrivateKey -> hash -> msg -> m Signature
sign pk hashAlg msg = do
k <- generateMax q
case signWith k pk hashAlg msg of
Nothing -> sign pk hashAlg msg
Just sig -> return sig
where
(Params _ _ q) = private_params pk
verify :: (ByteArrayAccess msg, HashAlgorithm hash) => hash -> PublicKey -> Signature -> msg -> Bool
verify hashAlg pk (Signature r s) m
| 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 = dsaTruncHash hashAlg m q
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