{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Crypto.PubKey.ElGamal
( Params
, PublicNumber
, PrivateNumber
, EphemeralKey(..)
, SharedKey
, Signature
, generatePrivate
, generatePublic
, encryptWith
, encrypt
, decrypt
, signWith
, sign
, verify
) where
import Data.Maybe (fromJust)
import Crypto.Internal.Imports
import Crypto.Internal.ByteArray (ByteArrayAccess)
import Crypto.Number.ModArithmetic (expSafe, expFast, inverse)
import Crypto.Number.Generate (generateMax)
import Crypto.Number.Serialize (os2ip)
import Crypto.Number.Basic (gcde)
import Crypto.Random.Types
import Crypto.PubKey.DH (PrivateNumber(..), PublicNumber(..), Params(..), SharedKey(..))
import Crypto.Hash
data Signature = Signature (Integer, Integer)
newtype EphemeralKey = EphemeralKey Integer
deriving (EphemeralKey -> ()
(EphemeralKey -> ()) -> NFData EphemeralKey
forall a. (a -> ()) -> NFData a
rnf :: EphemeralKey -> ()
$crnf :: EphemeralKey -> ()
NFData)
generatePrivate :: MonadRandom m => Integer -> m PrivateNumber
generatePrivate :: Integer -> m PrivateNumber
generatePrivate q :: Integer
q = Integer -> PrivateNumber
PrivateNumber (Integer -> PrivateNumber) -> m Integer -> m PrivateNumber
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Integer -> m Integer
forall (m :: * -> *). MonadRandom m => Integer -> m Integer
generateMax Integer
q
generateEphemeral :: MonadRandom m => Integer -> m EphemeralKey
generateEphemeral :: Integer -> m EphemeralKey
generateEphemeral q :: Integer
q = PrivateNumber -> EphemeralKey
toEphemeral (PrivateNumber -> EphemeralKey)
-> m PrivateNumber -> m EphemeralKey
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Integer -> m PrivateNumber
forall (m :: * -> *). MonadRandom m => Integer -> m PrivateNumber
generatePrivate Integer
q
where toEphemeral :: PrivateNumber -> EphemeralKey
toEphemeral (PrivateNumber n :: Integer
n) = Integer -> EphemeralKey
EphemeralKey Integer
n
generatePublic :: Params -> PrivateNumber -> PublicNumber
generatePublic :: Params -> PrivateNumber -> PublicNumber
generatePublic (Params p :: Integer
p g :: Integer
g _) (PrivateNumber a :: Integer
a) = Integer -> PublicNumber
PublicNumber (Integer -> PublicNumber) -> Integer -> PublicNumber
forall a b. (a -> b) -> a -> b
$ Integer -> Integer -> Integer -> Integer
expSafe Integer
g Integer
a Integer
p
encryptWith :: EphemeralKey -> Params -> PublicNumber -> Integer -> (Integer,Integer)
encryptWith :: EphemeralKey
-> Params -> PublicNumber -> Integer -> (Integer, Integer)
encryptWith (EphemeralKey b :: Integer
b) (Params p :: Integer
p g :: Integer
g _) (PublicNumber h :: Integer
h) m :: Integer
m = (Integer
c1,Integer
c2)
where s :: Integer
s = Integer -> Integer -> Integer -> Integer
expSafe Integer
h Integer
b Integer
p
c1 :: Integer
c1 = Integer -> Integer -> Integer -> Integer
expSafe Integer
g Integer
b Integer
p
c2 :: Integer
c2 = (Integer
s Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
m) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
p
encrypt :: MonadRandom m => Params -> PublicNumber -> Integer -> m (Integer,Integer)
encrypt :: Params -> PublicNumber -> Integer -> m (Integer, Integer)
encrypt params :: Params
params@(Params p :: Integer
p _ _) public :: PublicNumber
public m :: Integer
m = (\b :: EphemeralKey
b -> EphemeralKey
-> Params -> PublicNumber -> Integer -> (Integer, Integer)
encryptWith EphemeralKey
b Params
params PublicNumber
public Integer
m) (EphemeralKey -> (Integer, Integer))
-> m EphemeralKey -> m (Integer, Integer)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Integer -> m EphemeralKey
forall (m :: * -> *). MonadRandom m => Integer -> m EphemeralKey
generateEphemeral Integer
q
where q :: Integer
q = Integer
pInteger -> Integer -> Integer
forall a. Num a => a -> a -> a
-1
decrypt :: Params -> PrivateNumber -> (Integer, Integer) -> Integer
decrypt :: Params -> PrivateNumber -> (Integer, Integer) -> Integer
decrypt (Params p :: Integer
p _ _) (PrivateNumber a :: Integer
a) (c1 :: Integer
c1,c2 :: Integer
c2) = (Integer
c2 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
sm1) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
p
where s :: Integer
s = Integer -> Integer -> Integer -> Integer
expSafe Integer
c1 Integer
a Integer
p
sm1 :: Integer
sm1 = Maybe Integer -> Integer
forall a. HasCallStack => Maybe a -> a
fromJust (Maybe Integer -> Integer) -> Maybe Integer -> Integer
forall a b. (a -> b) -> a -> b
$ Integer -> Integer -> Maybe Integer
inverse Integer
s Integer
p
signWith :: (ByteArrayAccess msg, HashAlgorithm hash)
=> Integer
-> Params
-> PrivateNumber
-> hash
-> msg
-> Maybe Signature
signWith :: Integer
-> Params -> PrivateNumber -> hash -> msg -> Maybe Signature
signWith k :: Integer
k (Params p :: Integer
p g :: Integer
g _) (PrivateNumber x :: Integer
x) hashAlg :: hash
hashAlg msg :: msg
msg
| Integer
k Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>= Integer
pInteger -> Integer -> Integer
forall a. Num a => a -> a -> a
-1 Bool -> Bool -> Bool
|| Integer
d Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> 1 = Maybe Signature
forall a. Maybe a
Nothing
| Integer
s Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== 0 = Maybe Signature
forall a. Maybe a
Nothing
| Bool
otherwise = Signature -> Maybe Signature
forall a. a -> Maybe a
Just (Signature -> Maybe Signature) -> Signature -> Maybe Signature
forall a b. (a -> b) -> a -> b
$ (Integer, Integer) -> Signature
Signature (Integer
r,Integer
s)
where r :: Integer
r = Integer -> Integer -> Integer -> Integer
expSafe Integer
g Integer
k Integer
p
h :: Integer
h = Digest hash -> Integer
forall ba. ByteArrayAccess ba => ba -> Integer
os2ip (Digest hash -> Integer) -> Digest hash -> Integer
forall a b. (a -> b) -> a -> b
$ hash -> msg -> Digest hash
forall ba alg.
(ByteArrayAccess ba, HashAlgorithm alg) =>
alg -> ba -> Digest alg
hashWith hash
hashAlg msg
msg
s :: Integer
s = ((Integer
h Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
xInteger -> Integer -> Integer
forall a. Num a => a -> a -> a
*Integer
r) Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
kInv) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` (Integer
pInteger -> Integer -> Integer
forall a. Num a => a -> a -> a
-1)
(kInv :: Integer
kInv,_,d :: Integer
d) = Integer -> Integer -> (Integer, Integer, Integer)
gcde Integer
k (Integer
pInteger -> Integer -> Integer
forall a. Num a => a -> a -> a
-1)
sign :: (ByteArrayAccess msg, HashAlgorithm hash, MonadRandom m)
=> Params
-> PrivateNumber
-> hash
-> msg
-> m Signature
sign :: Params -> PrivateNumber -> hash -> msg -> m Signature
sign params :: Params
params@(Params p :: Integer
p _ _) priv :: PrivateNumber
priv hashAlg :: hash
hashAlg msg :: msg
msg = do
Integer
k <- Integer -> m Integer
forall (m :: * -> *). MonadRandom m => Integer -> m Integer
generateMax (Integer
pInteger -> Integer -> Integer
forall a. Num a => a -> a -> a
-1)
case Integer
-> Params -> PrivateNumber -> hash -> msg -> Maybe Signature
forall msg hash.
(ByteArrayAccess msg, HashAlgorithm hash) =>
Integer
-> Params -> PrivateNumber -> hash -> msg -> Maybe Signature
signWith Integer
k Params
params PrivateNumber
priv hash
hashAlg msg
msg of
Nothing -> Params -> PrivateNumber -> hash -> msg -> m Signature
forall msg hash (m :: * -> *).
(ByteArrayAccess msg, HashAlgorithm hash, MonadRandom m) =>
Params -> PrivateNumber -> hash -> msg -> m Signature
sign Params
params PrivateNumber
priv hash
hashAlg msg
msg
Just sig :: Signature
sig -> Signature -> m Signature
forall (m :: * -> *) a. Monad m => a -> m a
return Signature
sig
verify :: (ByteArrayAccess msg, HashAlgorithm hash)
=> Params
-> PublicNumber
-> hash
-> msg
-> Signature
-> Bool
verify :: Params -> PublicNumber -> hash -> msg -> Signature -> Bool
verify (Params p :: Integer
p g :: Integer
g _) (PublicNumber y :: Integer
y) hashAlg :: hash
hashAlg msg :: msg
msg (Signature (r :: Integer
r,s :: Integer
s))
| [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
or [Integer
r Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
<= 0,Integer
r Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>= Integer
p,Integer
s Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
<= 0,Integer
s Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>= (Integer
pInteger -> Integer -> Integer
forall a. Num a => a -> a -> a
-1)] = Bool
False
| Bool
otherwise = Integer
lhs Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
rhs
where h :: Integer
h = Digest hash -> Integer
forall ba. ByteArrayAccess ba => ba -> Integer
os2ip (Digest hash -> Integer) -> Digest hash -> Integer
forall a b. (a -> b) -> a -> b
$ hash -> msg -> Digest hash
forall ba alg.
(ByteArrayAccess ba, HashAlgorithm alg) =>
alg -> ba -> Digest alg
hashWith hash
hashAlg msg
msg
lhs :: Integer
lhs = Integer -> Integer -> Integer -> Integer
expFast Integer
g Integer
h Integer
p
rhs :: Integer
rhs = (Integer -> Integer -> Integer -> Integer
expFast Integer
y Integer
r Integer
p Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer -> Integer -> Integer -> Integer
expFast Integer
r Integer
s Integer
p) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
p