    -- |
    -- Module      : Crypto.PubKey.RSA
    -- License     : BSD-style
    -- Maintainer  : Vincent Hanquez <vincent@snarc.org>
    -- Stability   : experimental
    -- Portability : Good
    --
    module Crypto.PubKey.RSA
        ( Error(..)
        , PublicKey(..)
        , PrivateKey(..)
        , Blinder(..)
        -- * generation function
        , 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

    -- | Generate a key pair given p and q.
    --
    -- p and q need to be distinct prime numbers.
    --
    -- e need to be coprime to phi=(p-1)*(q-1). If that's not the
    -- case, the function will not return a key pair.
    -- A small hamming weight results in better performance.
    --
    -- * e=0x10001 is a popular choice
    --
    -- * e=3 is popular as well, but proven to not be as secure for some cases.
    --
    generateWith :: (Integer, Integer) -- ^ chosen distinct primes p and q
                 -> Int                -- ^ size in bytes
                 -> Integer            -- ^ RSA public exponant 'e'
                 -> Maybe (PublicKey, PrivateKey)
    generateWith :: (Integer, Integer)
    -> Int -> Integer -> Maybe (PublicKey, PrivateKey)
    generateWith (p :: Integer
    p,q :: Integer
    q) size :: Int
    size e :: Integer
    e =
        case Integer -> Integer -> Maybe Integer
    inverse Integer
    e Integer
    phi of
            Nothing -> Maybe (PublicKey, PrivateKey)
    forall a. Maybe a
    Nothing
            Just d :: Integer
    d  -> (PublicKey, PrivateKey) -> Maybe (PublicKey, PrivateKey)
    forall a. a -> Maybe a
    Just (PublicKey
    pub,Integer -> PrivateKey
    priv Integer
    d)
      where n :: Integer
    n   = Integer
    pInteger -> Integer -> Integer
    forall a. Num a => a -> a -> a
    *Integer
    q
            phi :: Integer
    phi = (Integer
    pInteger -> Integer -> Integer
    forall a. Num a => a -> a -> a
    -1)Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    *(Integer
    qInteger -> Integer -> Integer
    forall a. Num a => a -> a -> a
    -1)
            -- q and p should be *distinct* *prime* numbers, hence always coprime
            qinv :: Integer
    qinv = Integer -> Integer -> Integer
    inverseCoprimes Integer
    q Integer
    p
            pub :: PublicKey
    pub = PublicKey :: Int -> Integer -> Integer -> PublicKey
    PublicKey { public_size :: Int
    public_size = Int
    size
                            , public_n :: Integer
    public_n    = Integer
    n
                            , public_e :: Integer
    public_e    = Integer
    e
                            }
            priv :: Integer -> PrivateKey
    priv d :: Integer
    d = PrivateKey :: PublicKey
    -> Integer
    -> Integer
    -> Integer
    -> Integer
    -> Integer
    -> Integer
    -> PrivateKey
    PrivateKey { private_pub :: PublicKey
    private_pub  = PublicKey
    pub
                                , private_d :: Integer
    private_d    = Integer
    d
                                , private_p :: Integer
    private_p    = Integer
    p
                                , private_q :: Integer
    private_q    = Integer
    q
                                , private_dP :: Integer
    private_dP   = Integer
    d Integer -> Integer -> Integer
    forall a. Integral a => a -> a -> a
    `mod` (Integer
    pInteger -> Integer -> Integer
    forall a. Num a => a -> a -> a
    -1)
                                , private_dQ :: Integer
    private_dQ   = Integer
    d Integer -> Integer -> Integer
    forall a. Integral a => a -> a -> a
    `mod` (Integer
    qInteger -> Integer -> Integer
    forall a. Num a => a -> a -> a
    -1)
                                , private_qinv :: Integer
    private_qinv = Integer
    qinv
                                }

    -- | generate a pair of (private, public) key of size in bytes.
    generate :: CPRG g
             => g       -- ^ CPRG
             -> Int     -- ^ size in bytes
             -> Integer -- ^ RSA public exponant 'e'
             -> ((PublicKey, PrivateKey), g)
    generate :: g -> Int -> Integer -> ((PublicKey, PrivateKey), g)
    generate rng :: g
    rng size :: Int
    size e :: Integer
    e = g -> ((PublicKey, PrivateKey), g)
    forall b. CPRG b => b -> ((PublicKey, PrivateKey), b)
    loop g
    rng
      where loop :: b -> ((PublicKey, PrivateKey), b)
    loop g :: b
    g = -- loop until we find a valid key pair given e
                let (pq :: (Integer, Integer)
    pq, g' :: b
    g') = b -> ((Integer, Integer), b)
    forall b. CPRG b => b -> ((Integer, Integer), b)
    generatePQ b
    g
                 in case (Integer, Integer)
    -> Int -> Integer -> Maybe (PublicKey, PrivateKey)
    generateWith (Integer, Integer)
    pq Int
    size Integer
    e of
                        Nothing -> b -> ((PublicKey, PrivateKey), b)
    loop b
    g'
                        Just pp :: (PublicKey, PrivateKey)
    pp -> ((PublicKey, PrivateKey)
    pp, b
    g')
            generatePQ :: b -> ((Integer, Integer), b)
    generatePQ g :: b
    g =
                let (p :: Integer
    p, g' :: b
    g')  = b -> Int -> (Integer, b)
    forall g. CPRG g => g -> Int -> (Integer, g)
    generatePrime b
    g (8 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    * (Int
    size Int -> Int -> Int
    forall a. Integral a => a -> a -> a
    `div` 2))
                    (q :: Integer
    q, g'' :: b
    g'') = Integer -> b -> (Integer, b)
    forall b. CPRG b => Integer -> b -> (Integer, b)
    generateQ Integer
    p b
    g'
                 in ((Integer
    p,Integer
    q), b
    g'')
            generateQ :: Integer -> b -> (Integer, b)
    generateQ p :: Integer
    p h :: b
    h =
                let (q :: Integer
    q, h' :: b
    h') = b -> Int -> (Integer, b)
    forall g. CPRG g => g -> Int -> (Integer, g)
    generatePrime b
    h (8 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    * (Int
    size Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - (Int
    size Int -> Int -> Int
    forall a. Integral a => a -> a -> a
    `div` 2)))
                 in if Integer
    p Integer -> Integer -> Bool
    forall a. Eq a => a -> a -> Bool
    == Integer
    q then Integer -> b -> (Integer, b)
    generateQ Integer
    p b
    h' else (Integer
    q, b
    h')

    -- | Generate a blinder to use with decryption and signing operation
    --
    -- the unique parameter apart from the random number generator is the
    -- public key value N.
    generateBlinder :: CPRG g
                    => g       -- ^ CPRG to use.
                    -> Integer -- ^ RSA public N parameter.
                    -> (Blinder, g)
    generateBlinder :: g -> Integer -> (Blinder, g)
    generateBlinder rng :: g
    rng n :: Integer
    n = (Integer -> Integer -> Blinder
    Blinder Integer
    r (Integer -> Integer -> Integer
    inverseCoprimes Integer
    r Integer
    n), g
    rng')
      where (r :: Integer
    r, rng' :: g
    rng') = g -> Integer -> (Integer, g)
    forall g. CPRG g => g -> Integer -> (Integer, g)
    generateMax g
    rng Integer
    n