module Crypto.Cipher.RC4
( Ctx(..)
, initCtx
, generate
, combine
, encrypt
, decrypt
) where
import Data.Word
import Foreign.Ptr
import Foreign.ForeignPtr
import System.IO.Unsafe (unsafeDupablePerformIO)
import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import qualified Data.ByteString.Internal as B
import Control.Applicative ((<$>))
newtype Ctx = Ctx B.ByteString
instance Show Ctx where
show _ = "RC4.Ctx"
foreign import ccall unsafe "rc4.h rc4_init"
c_rc4_init :: Ptr Word8
-> Word32
-> Ptr Ctx
-> IO ()
foreign import ccall unsafe "rc4.h rc4_combine"
c_rc4_combine :: Ptr Ctx
-> Ptr Word8
-> Word32
-> Ptr Word8
-> IO ()
withByteStringPtr :: ByteString -> (Ptr Word8 -> IO a) -> IO a
withByteStringPtr b f = withForeignPtr fptr $ \ptr -> f (ptr `plusPtr` off)
where (fptr, off, _) = B.toForeignPtr b
initCtx :: B.ByteString
-> Ctx
initCtx key = unsafeDupablePerformIO $
Ctx <$> (B.create 264 $ \ctx -> B.useAsCStringLen key $ \(keyPtr,keyLen) -> c_rc4_init (castPtr keyPtr) (fromIntegral keyLen) (castPtr ctx))
generate :: Ctx -> Int -> (Ctx, B.ByteString)
generate ctx len = combine ctx (B.replicate len 0)
combine :: Ctx
-> B.ByteString
-> (Ctx, B.ByteString)
combine (Ctx cctx) clearText = unsafeDupablePerformIO $
B.mallocByteString 264 >>= \dctx ->
B.mallocByteString len >>= \outfptr ->
withByteStringPtr clearText $ \clearPtr ->
withByteStringPtr cctx $ \srcCtx ->
withForeignPtr dctx $ \dstCtx -> do
withForeignPtr outfptr $ \outptr -> do
B.memcpy dstCtx srcCtx 264
c_rc4_combine (castPtr dstCtx) clearPtr (fromIntegral len) outptr
return $! (Ctx $! B.PS dctx 0 264, B.PS outfptr 0 len)
where len = B.length clearText
encrypt,decrypt :: Ctx -> B.ByteString -> (Ctx, B.ByteString)
encrypt = combine
decrypt = combine