HsOpenSSL-0.3: OpenSSL/RSA.hsc
{- -*- haskell -*- -}
-- #prune
-- |An interface to RSA public key generator.
#include "HsOpenSSL.h"
module OpenSSL.RSA
( -- * Type
RSA
, RSA_ -- private
, withRSAPtr -- private
-- * Generating keypair
, RSAGenKeyCallback
, generateKey
-- * Exploring keypair
, rsaN
, rsaE
, rsaD
, rsaP
, rsaQ
, rsaDMP1
, rsaDMQ1
, rsaIQMP
)
where
import Control.Monad
import Foreign
import OpenSSL.BN
import OpenSSL.Utils
-- |@'RSA'@ is an opaque object that represents either RSA public key
-- or public\/private keypair.
newtype RSA = RSA (ForeignPtr RSA_)
data RSA_
foreign import ccall unsafe "&RSA_free"
_free :: FunPtr (Ptr RSA_ -> IO ())
withRSAPtr :: RSA -> (Ptr RSA_ -> IO a) -> IO a
withRSAPtr (RSA rsa) = withForeignPtr rsa
{- generation --------------------------------------------------------------- -}
-- |@'RSAGenKeyCallback'@ represents a callback function to get
-- informed the progress of RSA key generation.
--
-- * @callback 0 i@ is called after generating the @i@-th potential
-- prime number.
--
-- * While the number is being tested for primality, @callback 1 j@ is
-- called after the @j@-th iteration (j = 0, 1, ...).
--
-- * When the @n@-th randomly generated prime is rejected as not
-- suitable for the key, @callback 2 n@ is called.
--
-- * When a random @p@ has been found with @p@-1 relatively prime to
-- @e@, it is called as @callback 3 0@.
--
-- * The process is then repeated for prime @q@ with @callback 3 1@.
type RSAGenKeyCallback = Int -> Int -> IO ()
type RSAGenKeyCallback' = Int -> Int -> Ptr () -> IO ()
foreign import ccall "wrapper"
mkGenKeyCallback :: RSAGenKeyCallback' -> IO (FunPtr RSAGenKeyCallback')
foreign import ccall safe "RSA_generate_key"
_generate_key :: Int -> Int -> FunPtr RSAGenKeyCallback' -> Ptr a -> IO (Ptr RSA_)
-- |@'generateKey'@ generates an RSA keypair.
generateKey :: Int -- ^ The number of bits of the public modulus
-- (i.e. key size). Key sizes with @n < 1024@
-- should be considered insecure.
-> Int -- ^ The public exponent. It is an odd number,
-- typically 3, 17 or 65537.
-> Maybe RSAGenKeyCallback -- ^ A callback function.
-> IO RSA -- ^ The generated keypair.
generateKey nbits e Nothing
= do ptr <- _generate_key nbits e nullFunPtr nullPtr
failIfNull ptr
newForeignPtr _free ptr >>= return . RSA
generateKey nbits e (Just cb)
= do cbPtr <- mkGenKeyCallback
$ \ arg1 arg2 _ -> cb arg1 arg2
ptr <- _generate_key nbits e cbPtr nullPtr
freeHaskellFunPtr cbPtr
failIfNull ptr
newForeignPtr _free ptr >>= return . RSA
{- exploration -------------------------------------------------------------- -}
peekRSAPublic :: (Ptr RSA_ -> IO (Ptr BIGNUM)) -> RSA -> IO Integer
peekRSAPublic peeker rsa
= withRSAPtr rsa $ \ rsaPtr ->
do bn <- peeker rsaPtr
when (bn == nullPtr) $ fail "peekRSAPublic: got a nullPtr"
peekBN (wrapBN bn)
peekRSAPrivate :: (Ptr RSA_ -> IO (Ptr BIGNUM)) -> RSA -> IO (Maybe Integer)
peekRSAPrivate peeker rsa
= withRSAPtr rsa $ \ rsaPtr ->
do bn <- peeker rsaPtr
if bn == nullPtr then
return Nothing
else
peekBN (wrapBN bn) >>= return . Just
-- |@'rsaN' pubKey@ returns the public modulus of the key.
rsaN :: RSA -> IO Integer
rsaN = peekRSAPublic (#peek RSA, n)
-- |@'rsaE' pubKey@ returns the public exponent of the key.
rsaE :: RSA -> IO Integer
rsaE = peekRSAPublic (#peek RSA, e)
-- |@'rsaD' privKey@ returns the private exponent of the key. If
-- @privKey@ is not really a private key, the result is @Nothing@.
rsaD :: RSA -> IO (Maybe Integer)
rsaD = peekRSAPrivate (#peek RSA, d)
-- |@'rsaP' privkey@ returns the secret prime factor @p@ of the key.
rsaP :: RSA -> IO (Maybe Integer)
rsaP = peekRSAPrivate (#peek RSA, p)
-- |@'rsaQ' privkey@ returns the secret prime factor @q@ of the key.
rsaQ :: RSA -> IO (Maybe Integer)
rsaQ = peekRSAPrivate (#peek RSA, q)
-- |@'rsaDMP1' privkey@ returns @d mod (p-1)@ of the key.
rsaDMP1 :: RSA -> IO (Maybe Integer)
rsaDMP1 = peekRSAPrivate (#peek RSA, dmp1)
-- |@'rsaDMQ1' privkey@ returns @d mod (q-1)@ of the key.
rsaDMQ1 :: RSA -> IO (Maybe Integer)
rsaDMQ1 = peekRSAPrivate (#peek RSA, dmq1)
-- |@'rsaIQMP' privkey@ returns @q^-1 mod p@ of the key.
rsaIQMP :: RSA -> IO (Maybe Integer)
rsaIQMP = peekRSAPrivate (#peek RSA, iqmp)