module OpenSSL.RSA
(
RSAKey(..)
, RSAPubKey
, RSAKeyPair
, RSA
, RSAGenKeyCallback
, generateRSAKey
, generateRSAKey'
, rsaD
, rsaP
, rsaQ
, rsaDMP1
, rsaDMQ1
, rsaIQMP
, rsaCopyPublic
, rsaKeyPairFinalize
)
where
import Control.Monad
import Data.Typeable
import Foreign
import Foreign.C
import OpenSSL.BN
import OpenSSL.Utils
newtype RSAPubKey = RSAPubKey (ForeignPtr RSA)
deriving Typeable
newtype RSAKeyPair = RSAKeyPair (ForeignPtr RSA)
deriving Typeable
data RSA
class RSAKey k where
rsaSize :: k -> Int
rsaSize rsa
= unsafePerformIO $
withRSAPtr rsa $ \ rsaPtr ->
fmap fromIntegral (_size rsaPtr)
rsaN :: k -> Integer
rsaN = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 16))
rsaE :: k -> Integer
rsaE = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 20))
withRSAPtr :: k -> (Ptr RSA -> IO a) -> IO a
peekRSAPtr :: Ptr RSA -> IO (Maybe k)
absorbRSAPtr :: Ptr RSA -> IO (Maybe k)
instance RSAKey RSAPubKey where
withRSAPtr (RSAPubKey fp) = withForeignPtr fp
peekRSAPtr rsaPtr = _pubDup rsaPtr >>= absorbRSAPtr
absorbRSAPtr rsaPtr = fmap (Just . RSAPubKey) (newForeignPtr _free rsaPtr)
instance RSAKey RSAKeyPair where
withRSAPtr (RSAKeyPair fp) = withForeignPtr fp
peekRSAPtr rsaPtr
= do hasP <- hasRSAPrivateKey rsaPtr
if hasP then
_privDup rsaPtr >>= absorbRSAPtr
else
return Nothing
absorbRSAPtr rsaPtr
= do hasP <- hasRSAPrivateKey rsaPtr
if hasP then
fmap (Just . RSAKeyPair) (newForeignPtr _free rsaPtr)
else
return Nothing
hasRSAPrivateKey :: Ptr RSA -> IO Bool
hasRSAPrivateKey rsaPtr
= do d <- ((\hsc_ptr -> peekByteOff hsc_ptr 24)) rsaPtr
p <- ((\hsc_ptr -> peekByteOff hsc_ptr 28)) rsaPtr
q <- ((\hsc_ptr -> peekByteOff hsc_ptr 32)) rsaPtr
return (d /= nullPtr && p /= nullPtr && q /= nullPtr)
foreign import ccall unsafe "&RSA_free"
_free :: FunPtr (Ptr RSA -> IO ())
foreign import ccall unsafe "RSAPublicKey_dup"
_pubDup :: Ptr RSA -> IO (Ptr RSA)
foreign import ccall unsafe "RSAPrivateKey_dup"
_privDup :: Ptr RSA -> IO (Ptr RSA)
foreign import ccall unsafe "RSA_size"
_size :: Ptr RSA -> IO CInt
rsaCopyPublic :: RSAKey key => key -> IO RSAPubKey
rsaCopyPublic key = withRSAPtr key (fmap RSAPubKey . (newForeignPtr _free =<<) . _pubDup)
rsaKeyPairFinalize :: RSAKeyPair -> IO ()
rsaKeyPairFinalize (RSAKeyPair fp) = finalizeForeignPtr fp
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 :: CInt -> CInt -> FunPtr RSAGenKeyCallback' -> Ptr a -> IO (Ptr RSA)
generateRSAKey :: Int
-> Int
-> Maybe RSAGenKeyCallback
-> IO RSAKeyPair
generateRSAKey nbits e Nothing
= do ptr <- _generate_key (fromIntegral nbits) (fromIntegral e) nullFunPtr nullPtr
failIfNull_ ptr
fmap RSAKeyPair (newForeignPtr _free ptr)
generateRSAKey nbits e (Just cb)
= do cbPtr <- mkGenKeyCallback
$ \ arg1 arg2 _ -> cb arg1 arg2
ptr <- _generate_key (fromIntegral nbits) (fromIntegral e) cbPtr nullPtr
freeHaskellFunPtr cbPtr
failIfNull_ ptr
fmap RSAKeyPair (newForeignPtr _free ptr)
generateRSAKey' :: Int
-> Int
-> IO RSAKeyPair
generateRSAKey' nbits e
= generateRSAKey nbits e Nothing
peekI :: RSAKey a => (Ptr RSA -> IO (Ptr BIGNUM)) -> a -> Integer
peekI peeker rsa
= unsafePerformIO $
withRSAPtr rsa $ \ rsaPtr ->
do bn <- peeker rsaPtr
when (bn == nullPtr) $ fail "peekI: got a nullPtr"
peekBN (wrapBN bn)
peekMI :: RSAKey a => (Ptr RSA -> IO (Ptr BIGNUM)) -> a -> Maybe Integer
peekMI peeker rsa
= unsafePerformIO $
withRSAPtr rsa $ \ rsaPtr ->
do bn <- peeker rsaPtr
if bn == nullPtr then
return Nothing
else
fmap Just (peekBN (wrapBN bn))
rsaD :: RSAKeyPair -> Integer
rsaD = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 24))
rsaP :: RSAKeyPair -> Integer
rsaP = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 28))
rsaQ :: RSAKeyPair -> Integer
rsaQ = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 32))
rsaDMP1 :: RSAKeyPair -> Maybe Integer
rsaDMP1 = peekMI ((\hsc_ptr -> peekByteOff hsc_ptr 36))
rsaDMQ1 :: RSAKeyPair -> Maybe Integer
rsaDMQ1 = peekMI ((\hsc_ptr -> peekByteOff hsc_ptr 40))
rsaIQMP :: RSAKeyPair -> Maybe Integer
rsaIQMP = peekMI ((\hsc_ptr -> peekByteOff hsc_ptr 44))
instance Eq RSAPubKey where
a == b
= rsaN a == rsaN b &&
rsaE a == rsaE b
instance Eq RSAKeyPair where
a == b
= rsaN a == rsaN b &&
rsaE a == rsaE b &&
rsaD a == rsaD b &&
rsaP a == rsaP b &&
rsaQ a == rsaQ b
instance Ord RSAPubKey where
a `compare` b
| rsaN a < rsaN b = LT
| rsaN a > rsaN b = GT
| rsaE a < rsaE b = LT
| rsaE a > rsaE b = GT
| otherwise = EQ
instance Ord RSAKeyPair where
a `compare` b
| rsaN a < rsaN b = LT
| rsaN a > rsaN b = GT
| rsaE a < rsaE b = LT
| rsaE a > rsaE b = GT
| rsaD a < rsaD b = LT
| rsaD a > rsaD b = GT
| rsaP a < rsaP b = LT
| rsaP a > rsaP b = GT
| rsaQ a < rsaQ b = LT
| rsaQ a > rsaQ b = GT
| otherwise = EQ
instance Show RSAPubKey where
show a
= concat [ "RSAPubKey {"
, "rsaN = ", show (rsaN a), ", "
, "rsaE = ", show (rsaE a)
, "}"
]
instance Show RSAKeyPair where
show a
= concat [ "RSAKeyPair {"
, "rsaN = ", show (rsaN a), ", "
, "rsaE = ", show (rsaE a), ", "
, "rsaD = ", show (rsaD a), ", "
, "rsaP = ", show (rsaP a), ", "
, "rsaQ = ", show (rsaQ a)
, "}"
]