module OpenSSL.EVP.Seal
( seal
, sealBS
, sealLBS
)
where
import qualified Data.ByteString.Char8 as B8
import qualified Data.ByteString.Lazy.Char8 as L8
import Foreign
import Foreign.C
import OpenSSL.EVP.Cipher hiding (cipher)
import OpenSSL.EVP.PKey
import OpenSSL.EVP.Internal
import OpenSSL.Utils
foreign import ccall unsafe "EVP_SealInit"
_SealInit :: Ptr EVP_CIPHER_CTX
-> Cipher
-> Ptr (Ptr CChar)
-> Ptr CInt
-> CString
-> Ptr (Ptr EVP_PKEY)
-> CInt
-> IO CInt
sealInit :: Cipher
-> [SomePublicKey]
-> IO (CipherCtx, [B8.ByteString], B8.ByteString)
sealInit _ []
= fail "sealInit: at least one public key is required"
sealInit cipher pubKeys
= do ctx <- newCipherCtx
encKeyBufs <- mapM mallocEncKeyBuf pubKeys
encKeyBufsPtr <- newArray encKeyBufs
encKeyBufsLenPtr <- mallocArray nKeys
ivPtr <- mallocArray (cipherIvLength cipher)
pkeys <- mapM toPKey pubKeys
pubKeysPtr <- newArray $ map unsafePKeyToPtr pkeys
let cleanup = do mapM_ free encKeyBufs
free encKeyBufsPtr
free encKeyBufsLenPtr
free ivPtr
free pubKeysPtr
mapM_ touchPKey pkeys
ret <- withCipherCtxPtr ctx $ \ ctxPtr ->
_SealInit ctxPtr cipher encKeyBufsPtr encKeyBufsLenPtr ivPtr pubKeysPtr (fromIntegral nKeys)
if ret == 0 then
cleanup >> raiseOpenSSLError
else
do encKeysLen <- peekArray nKeys encKeyBufsLenPtr
encKeys <- mapM B8.packCStringLen $ zip encKeyBufs (fromIntegral `fmap` encKeysLen)
iv <- B8.packCStringLen (ivPtr, cipherIvLength cipher)
cleanup
return (ctx, encKeys, iv)
where
nKeys :: Int
nKeys = length pubKeys
mallocEncKeyBuf :: (PKey k, Storable a) => k -> IO (Ptr a)
mallocEncKeyBuf = mallocArray . pkeySize
seal :: Cipher
-> [SomePublicKey]
-> String
-> IO ( String
, [String]
, String
)
seal cipher pubKeys input
= do (output, encKeys, iv) <- sealLBS cipher pubKeys $ L8.pack input
return ( L8.unpack output
, B8.unpack `fmap` encKeys
, B8.unpack iv
)
sealBS :: Cipher
-> [SomePublicKey]
-> B8.ByteString
-> IO ( B8.ByteString
, [B8.ByteString]
, B8.ByteString
)
sealBS cipher pubKeys input
= do (ctx, encKeys, iv) <- sealInit cipher pubKeys
output <- cipherStrictly ctx input
return (output, encKeys, iv)
sealLBS :: Cipher
-> [SomePublicKey]
-> L8.ByteString
-> IO ( L8.ByteString
, [B8.ByteString]
, B8.ByteString
)
sealLBS cipher pubKeys input
= do (ctx, encKeys, iv) <- sealInit cipher pubKeys
output <- cipherLazily ctx input
return (output, encKeys, iv)