1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
|
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-- |
-- Module : Crypto.Cipher.RC4
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : stable
-- Portability : Good
--
-- Simple implementation of the RC4 stream cipher.
-- http://en.wikipedia.org/wiki/RC4
--
-- Initial FFI implementation by Peter White <peter@janrain.com>
--
-- Reorganized and simplified to have an opaque context.
module Crypto.Cipher.RC4 (
initialize,
combine,
generate,
State,
) where
import Crypto.Internal.ByteArray (
ByteArray,
ByteArrayAccess,
ScrubbedBytes,
)
import qualified Crypto.Internal.ByteArray as B
import Data.Word
import Foreign.Ptr
import Crypto.Internal.Compat
import Crypto.Internal.Imports
-- | The encryption state for RC4
--
-- This type is an instance of 'ByteArrayAccess' for debugging purpose. Internal
-- layout is architecture dependent, may contain uninitialized data fragments,
-- and change in future versions. The bytearray should not be used as input to
-- cryptographic algorithms.
newtype State = State ScrubbedBytes
deriving (ByteArrayAccess, NFData)
-- | C Call for initializing the encryptor
foreign import ccall unsafe "crypton_rc4.h crypton_rc4_init"
c_rc4_init
:: Ptr Word8
-- ^ The rc4 key
-> Word32
-- ^ The key length
-> Ptr State
-- ^ The context
-> IO ()
foreign import ccall unsafe "crypton_rc4.h crypton_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
where
-- return $! (State st, B.PS outfptr 0 len)
len = B.length clearText
|