module Crypto.PubKey.RSA
( Error(..)
, PublicKey(..)
, PrivateKey(..)
, Blinder(..)
, generateWith
, generate
, generateBlinder
) where
import Crypto.Random
import Crypto.Types.PubKey.RSA
import Crypto.Number.ModArithmetic (inverse, inverseCoprimes)
import Crypto.Number.Generate (generateMax)
import Crypto.Number.Prime (generatePrime)
import Crypto.PubKey.RSA.Types
generateWith :: (Integer, Integer)
-> Int
-> Integer
-> Maybe (PublicKey, PrivateKey)
generateWith (p,q) size e =
case inverse e phi of
Nothing -> Nothing
Just d -> Just (pub,priv d)
where n = p*q
phi = (p-1)*(q-1)
qinv = inverseCoprimes q p
pub = PublicKey { public_size = size
, public_n = n
, public_e = e
}
priv d = PrivateKey { private_pub = pub
, private_d = d
, private_p = p
, private_q = q
, private_dP = d `mod` (p-1)
, private_dQ = d `mod` (q-1)
, private_qinv = qinv
}
generate :: CPRG g
=> g
-> Int
-> Integer
-> ((PublicKey, PrivateKey), g)
generate rng size e = loop rng
where loop g =
let (pq, g') = generatePQ g
in case generateWith pq size e of
Nothing -> loop g'
Just pp -> (pp, g')
generatePQ g =
let (p, g') = generatePrime g (8 * (size `div` 2))
(q, g'') = generateQ p g'
in ((p,q), g'')
generateQ p h =
let (q, h') = generatePrime h (8 * (size - (size `div` 2)))
in if p == q then generateQ p h' else (q, h')
generateBlinder :: CPRG g
=> g
-> Integer
-> (Blinder, g)
generateBlinder rng n = (Blinder r (inverseCoprimes r n), rng')
where (r, rng') = generateMax rng n