-- | -- Module : Crypto.Cipher.RC4 -- License : BSD-style -- Maintainer : Vincent Hanquez -- Stability : stable -- Portability : Good -- -- Simple implementation of the RC4 stream cipher. -- http://en.wikipedia.org/wiki/RC4 -- -- Initial FFI implementation by Peter White -- -- Reorganized and simplified to have an opaque context. -- {-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} module Crypto.Cipher.RC4 ( initialize , combine , generate , State ) where import Data.Word import Foreign.Ptr import Crypto.Internal.ByteArray (ScrubbedBytes, ByteArray, ByteArrayAccess) import qualified Crypto.Internal.ByteArray as B import Crypto.Internal.Compat import Crypto.Internal.Imports -- | The encryption state for RC4 newtype State = State ScrubbedBytes deriving (ByteArrayAccess,NFData) -- | C Call for initializing the encryptor foreign import ccall unsafe "cryptonite_rc4.h cryptonite_rc4_init" c_rc4_init :: Ptr Word8 -- ^ The rc4 key -> Word32 -- ^ The key length -> Ptr State -- ^ The context -> IO () foreign import ccall unsafe "cryptonite_rc4.h cryptonite_rc4_combine" c_rc4_combine :: Ptr State -- ^ Pointer to the permutation -> Ptr Word8 -- ^ Pointer to the clear text -> Word32 -- ^ Length of the clear text -> Ptr Word8 -- ^ Output buffer -> IO () -- | RC4 context initialization. -- -- seed the context with an initial key. the key size need to be -- adequate otherwise security takes a hit. initialize :: ByteArrayAccess key => key -- ^ The key -> State -- ^ The RC4 context with the key mixed in initialize key = unsafeDoIO $ do st <- B.alloc 264 $ \stPtr -> B.withByteArray key $ \keyPtr -> c_rc4_init keyPtr (fromIntegral $ B.length key) (castPtr stPtr) return $ State st -- | generate the next len bytes of the rc4 stream without combining -- it to anything. generate :: ByteArray ba => State -> Int -> (State, ba) generate ctx len = combine ctx (B.zero len) -- | RC4 xor combination of the rc4 stream with an input combine :: ByteArray ba => State -- ^ rc4 context -> ba -- ^ input -> (State, ba) -- ^ new rc4 context, and the output combine (State prevSt) clearText = unsafeDoIO $ B.allocRet len $ \outptr -> B.withByteArray clearText $ \clearPtr -> do st <- B.copy prevSt $ \stPtr -> c_rc4_combine (castPtr stPtr) clearPtr (fromIntegral len) outptr return $! State st --return $! (State st, B.PS outfptr 0 len) where len = B.length clearText