module OpenSSL.DSA
(
DSAKey(..)
, DSAPubKey
, DSAKeyPair
, DSA
, generateDSAParameters
, generateDSAKey
, generateDSAParametersAndKey
, signDigestedDataWithDSA
, verifyDigestedDataWithDSA
, dsaPrivate
, dsaPubKeyToTuple
, dsaKeyPairToTuple
, tupleToDSAPubKey
, tupleToDSAKeyPair
) where
import Control.Monad
import qualified Data.ByteString as BS
import Data.Typeable
import Foreign
import Foreign.C (CString)
import Foreign.C.Types
import OpenSSL.BN
import OpenSSL.Utils
newtype DSAPubKey = DSAPubKey (ForeignPtr DSA)
deriving Typeable
newtype DSAKeyPair = DSAKeyPair (ForeignPtr DSA)
deriving Typeable
data DSA
class DSAKey k where
dsaSize :: k -> Int
dsaSize dsa
= unsafePerformIO $
withDSAPtr dsa $ \ dsaPtr ->
fmap fromIntegral (_size dsaPtr)
dsaP :: k -> Integer
dsaP = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 12))
dsaQ :: k -> Integer
dsaQ = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 16))
dsaG :: k -> Integer
dsaG = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 20))
dsaPublic :: k -> Integer
dsaPublic = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 24))
withDSAPtr :: k -> (Ptr DSA -> IO a) -> IO a
peekDSAPtr :: Ptr DSA -> IO (Maybe k)
absorbDSAPtr :: Ptr DSA -> IO (Maybe k)
instance DSAKey DSAPubKey where
withDSAPtr (DSAPubKey fp) = withForeignPtr fp
peekDSAPtr dsaPtr = _pubDup dsaPtr >>= absorbDSAPtr
absorbDSAPtr dsaPtr = fmap (Just . DSAPubKey) (newForeignPtr _free dsaPtr)
instance DSAKey DSAKeyPair where
withDSAPtr (DSAKeyPair fp) = withForeignPtr fp
peekDSAPtr dsaPtr
= do hasP <- hasDSAPrivateKey dsaPtr
if hasP then
_privDup dsaPtr >>= absorbDSAPtr
else
return Nothing
absorbDSAPtr dsaPtr
= do hasP <- hasDSAPrivateKey dsaPtr
if hasP then
fmap (Just . DSAKeyPair) (newForeignPtr _free dsaPtr)
else
return Nothing
hasDSAPrivateKey :: Ptr DSA -> IO Bool
hasDSAPrivateKey dsaPtr
= fmap (/= nullPtr) (((\hsc_ptr -> peekByteOff hsc_ptr 28)) dsaPtr)
foreign import ccall unsafe "&DSA_free"
_free :: FunPtr (Ptr DSA -> IO ())
foreign import ccall unsafe "DSA_free"
dsa_free :: Ptr DSA -> IO ()
foreign import ccall unsafe "BN_free"
_bn_free :: Ptr BIGNUM -> IO ()
foreign import ccall unsafe "DSA_new"
_dsa_new :: IO (Ptr DSA)
foreign import ccall unsafe "DSA_generate_key"
_dsa_generate_key :: Ptr DSA -> IO ()
foreign import ccall unsafe "HsOpenSSL_dsa_sign"
_dsa_sign :: Ptr DSA -> CString -> CInt -> Ptr (Ptr BIGNUM) -> Ptr (Ptr BIGNUM) -> IO CInt
foreign import ccall unsafe "HsOpenSSL_dsa_verify"
_dsa_verify :: Ptr DSA -> CString -> CInt -> Ptr BIGNUM -> Ptr BIGNUM -> IO CInt
foreign import ccall safe "DSA_generate_parameters"
_generate_params :: CInt -> Ptr CChar -> CInt -> Ptr CInt -> Ptr CInt -> Ptr () -> Ptr () -> IO (Ptr DSA)
foreign import ccall unsafe "HsOpenSSL_DSAPublicKey_dup"
_pubDup :: Ptr DSA -> IO (Ptr DSA)
foreign import ccall unsafe "HsOpenSSL_DSAPrivateKey_dup"
_privDup :: Ptr DSA -> IO (Ptr DSA)
foreign import ccall unsafe "DSA_size"
_size :: Ptr DSA -> IO CInt
peekI :: DSAKey k => (Ptr DSA -> IO (Ptr BIGNUM)) -> k -> Integer
peekI peeker dsa
= unsafePerformIO $
withDSAPtr dsa $ \ dsaPtr ->
do bn <- peeker dsaPtr
when (bn == nullPtr) $ fail "peekI: got a nullPtr"
peekBN (wrapBN bn)
generateDSAParameters :: Int
-> Maybe BS.ByteString
-> IO (Int, Int, Integer, Integer, Integer)
generateDSAParameters nbits mseed = do
when (nbits < 512 || nbits > 1024) $ fail "Invalid DSA bit size"
alloca (\i1 ->
alloca (\i2 ->
(\x -> case mseed of
Nothing -> x (nullPtr, 0)
Just seed -> BS.useAsCStringLen seed x) (\(seedptr, seedlen) -> do
ptr <- _generate_params (fromIntegral nbits) seedptr (fromIntegral seedlen) i1 i2 nullPtr nullPtr
failIfNull_ ptr
itcount <- peek i1
gencount <- peek i2
p <- ((\hsc_ptr -> peekByteOff hsc_ptr 12)) ptr >>= peekBN . wrapBN
q <- ((\hsc_ptr -> peekByteOff hsc_ptr 16)) ptr >>= peekBN . wrapBN
g <- ((\hsc_ptr -> peekByteOff hsc_ptr 20)) ptr >>= peekBN . wrapBN
dsa_free ptr
return (fromIntegral itcount, fromIntegral gencount, p, q, g))))
generateDSAKey :: Integer
-> Integer
-> Integer
-> IO DSAKeyPair
generateDSAKey p q g = do
ptr <- _dsa_new
fmap unwrapBN (newBN p) >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 12)) ptr
fmap unwrapBN (newBN q) >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 16)) ptr
fmap unwrapBN (newBN g) >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 20)) ptr
_dsa_generate_key ptr
fmap DSAKeyPair (newForeignPtr _free ptr)
dsaPrivate :: DSAKeyPair -> Integer
dsaPrivate = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 28))
dsaPubKeyToTuple :: DSAKeyPair -> (Integer, Integer, Integer, Integer)
dsaPubKeyToTuple dsa
= let p = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 12)) dsa
q = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 16)) dsa
g = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 20)) dsa
pub = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 24)) dsa
in
(p, q, g, pub)
dsaKeyPairToTuple :: DSAKeyPair -> (Integer, Integer, Integer, Integer, Integer)
dsaKeyPairToTuple dsa
= let p = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 12)) dsa
q = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 16)) dsa
g = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 20)) dsa
pub = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 24)) dsa
pri = peekI ((\hsc_ptr -> peekByteOff hsc_ptr 28)) dsa
in
(p, q, g, pub, pri)
tupleToDSAPubKey :: (Integer, Integer, Integer, Integer) -> DSAPubKey
tupleToDSAPubKey (p, q, g, pub) = unsafePerformIO $ do
ptr <- _dsa_new
fmap unwrapBN (newBN p ) >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 12)) ptr
fmap unwrapBN (newBN q ) >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 16)) ptr
fmap unwrapBN (newBN g ) >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 20)) ptr
fmap unwrapBN (newBN pub) >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 24)) ptr
((\hsc_ptr -> pokeByteOff hsc_ptr 28)) ptr nullPtr
fmap DSAPubKey (newForeignPtr _free ptr)
tupleToDSAKeyPair :: (Integer, Integer, Integer, Integer, Integer) -> DSAKeyPair
tupleToDSAKeyPair (p, q, g, pub, pri) = unsafePerformIO $ do
ptr <- _dsa_new
fmap unwrapBN (newBN p ) >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 12)) ptr
fmap unwrapBN (newBN q ) >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 16)) ptr
fmap unwrapBN (newBN g ) >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 20)) ptr
fmap unwrapBN (newBN pub) >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 24)) ptr
fmap unwrapBN (newBN pri) >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 28)) ptr
fmap DSAKeyPair (newForeignPtr _free ptr)
generateDSAParametersAndKey :: Int
-> Maybe BS.ByteString
-> IO DSAKeyPair
generateDSAParametersAndKey nbits mseed =
(\x -> case mseed of
Nothing -> x (nullPtr, 0)
Just seed -> BS.useAsCStringLen seed x) (\(seedptr, seedlen) -> do
ptr <- _generate_params (fromIntegral nbits) seedptr (fromIntegral seedlen) nullPtr nullPtr nullPtr nullPtr
failIfNull_ ptr
_dsa_generate_key ptr
fmap DSAKeyPair (newForeignPtr _free ptr))
signDigestedDataWithDSA :: DSAKeyPair -> BS.ByteString -> IO (Integer, Integer)
signDigestedDataWithDSA dsa bytes =
BS.useAsCStringLen bytes (\(ptr, len) ->
alloca (\rptr ->
alloca (\sptr ->
withDSAPtr dsa (\dsaptr -> do
_dsa_sign dsaptr ptr (fromIntegral len) rptr sptr >>= failIf_ (== 0)
r <- peek rptr >>= peekBN . wrapBN
peek rptr >>= _bn_free
s <- peek sptr >>= peekBN . wrapBN
peek sptr >>= _bn_free
return (r, s)))))
verifyDigestedDataWithDSA :: DSAKey k => k -> BS.ByteString -> (Integer, Integer) -> IO Bool
verifyDigestedDataWithDSA dsa bytes (r, s) =
BS.useAsCStringLen bytes (\(ptr, len) ->
withBN r (\bnR ->
withBN s (\bnS ->
withDSAPtr dsa (\dsaptr ->
fmap (== 1)
(_dsa_verify dsaptr ptr (fromIntegral len) (unwrapBN bnR) (unwrapBN bnS))))))
instance Eq DSAPubKey where
a == b
= dsaP a == dsaP b &&
dsaQ a == dsaQ b &&
dsaG a == dsaG b &&
dsaPublic a == dsaPublic b
instance Eq DSAKeyPair where
a == b
= dsaP a == dsaP b &&
dsaQ a == dsaQ b &&
dsaG a == dsaG b &&
dsaPublic a == dsaPublic b &&
dsaPrivate a == dsaPrivate b
instance Ord DSAPubKey where
a `compare` b
| dsaP a < dsaP b = LT
| dsaP a > dsaP b = GT
| dsaQ a < dsaQ b = LT
| dsaQ a > dsaQ b = GT
| dsaG a < dsaG b = LT
| dsaG a > dsaG b = GT
| dsaPublic a < dsaPublic b = LT
| dsaPublic a > dsaPublic b = GT
| otherwise = EQ
instance Ord DSAKeyPair where
a `compare` b
| dsaP a < dsaP b = LT
| dsaP a > dsaP b = GT
| dsaQ a < dsaQ b = LT
| dsaQ a > dsaQ b = GT
| dsaG a < dsaG b = LT
| dsaG a > dsaG b = GT
| dsaPublic a < dsaPublic b = LT
| dsaPublic a > dsaPublic b = GT
| dsaPrivate a < dsaPrivate b = LT
| dsaPrivate a > dsaPrivate b = GT
| otherwise = EQ
instance Show DSAPubKey where
show a
= concat [ "DSAPubKey {"
, "dsaP = ", show (dsaP a), ", "
, "dsaQ = ", show (dsaQ a), ", "
, "dsaG = ", show (dsaG a), ", "
, "dsaPublic = ", show (dsaPublic a)
, "}"
]
instance Show DSAKeyPair where
show a
= concat [ "DSAPubKey {"
, "dsaP = ", show (dsaP a), ", "
, "dsaQ = ", show (dsaQ a), ", "
, "dsaG = ", show (dsaG a), ", "
, "dsaPublic = ", show (dsaPublic a), ", "
, "dsaPrivate = ", show (dsaPrivate a)
, "}"
]