cipher-rc4 (empty) → 0.1.0
raw patch · 8 files changed
+344/−0 lines, 8 filesdep +QuickCheckdep +basedep +bytestringsetup-changed
Dependencies added: QuickCheck, base, bytestring, cipher-rc4, criterion, deepseq, mtl, test-framework, test-framework-quickcheck2, vector
Files
- Benchmarks/Benchmarks.hs +34/−0
- Crypto/Cipher/RC4.hs +91/−0
- LICENSE +27/−0
- Setup.hs +2/−0
- Tests/Tests.hs +64/−0
- cbits/rc4.c +63/−0
- cbits/rc4.h +14/−0
- cipher-rc4.cabal +49/−0
+ Benchmarks/Benchmarks.hs view
@@ -0,0 +1,34 @@+module Main where++import Criterion.Main++import Crypto.Cipher.RC4+import qualified Data.ByteString as B+import Control.DeepSeq++instance NFData Ctx where+ rnf (Ctx c) = c `seq` ()++main = defaultMain+ [ bgroup "init"+ [ bench "1" $ whnf initCtx b1+ , bench "8" $ whnf initCtx b8+ , bench "32" $ whnf initCtx b32+ , bench "64" $ whnf initCtx b64+ , bench "256" $ whnf initCtx b256+ ]+ , bgroup "encrypt"+ [ bench "8" $ nf (encrypt ctx) b8+ , bench "32" $ nf (encrypt ctx) b32+ , bench "64" $ nf (encrypt ctx) b64+ , bench "256" $ nf (encrypt ctx) b256+ , bench "1024" $ nf (encrypt ctx) b1024+ ]+ ]+ where b1 = B.replicate 1 0xf7+ b8 = B.replicate 8 0xf7+ b32 = B.replicate 32 0xf7+ b64 = B.replicate 64 0x7f+ b256 = B.replicate 256 0x7f+ b1024 = B.replicate 1024 0x7f+ ctx = initCtx $ B.pack [1..10]
+ Crypto/Cipher/RC4.hs view
@@ -0,0 +1,91 @@+{-# LANGUAGE ForeignFunctionInterface #-}+-- |+-- Module : Crypto.Cipher.RC4+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : stable+-- Portability : Good+--+-- Initial FFI implementation by Peter White <peter@janrain.com>+--+-- Reorganized and simplified to have an opaque context.+--+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 ((<$>))++----------------------------------------------------------------------++-- | The encryption context for RC4+newtype Ctx = Ctx B.ByteString++instance Show Ctx where+ show _ = "RC4.Ctx"++-- | C Call for initializing the encryptor+foreign import ccall unsafe "rc4.h rc4_init"+ c_rc4_init :: Ptr Word8 -- ^ The rc4 key+ -> Word32 -- ^ The key length+ -> Ptr Ctx -- ^ The context+ -> IO ()++foreign import ccall unsafe "rc4.h rc4_combine"+ c_rc4_combine :: Ptr Ctx -- ^ Pointer to the permutation+ -> Ptr Word8 -- ^ Pointer to the clear text+ -> Word32 -- ^ Length of the clear text+ -> Ptr Word8 -- ^ Output buffer+ -> 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++-- | RC4 context initialization.+--+-- seed the context with an initial key. the key size need to be+-- adequate otherwise security takes a hit.+initCtx :: B.ByteString -- ^ The key+ -> Ctx -- ^ The RC4 context with the key mixed in+initCtx key = unsafeDupablePerformIO $+ Ctx <$> (B.create 264 $ \ctx -> B.useAsCStringLen key $ \(keyPtr,keyLen) -> c_rc4_init (castPtr keyPtr) (fromIntegral keyLen) (castPtr ctx))++-- | generate the next len bytes of the rc4 stream without combining+-- it to anything.+generate :: Ctx -> Int -> (Ctx, B.ByteString)+generate ctx len = combine ctx (B.replicate len 0)++-- | RC4 xor combination of the rc4 stream with an input+combine :: Ctx -- ^ rc4 context+ -> B.ByteString -- ^ input+ -> (Ctx, B.ByteString) -- ^ new rc4 context, and the output+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++{-# DEPRECATED encrypt "use combine instead" #-}+{-# DEPRECATED decrypt "use combine instead" #-}+encrypt,decrypt :: Ctx -> B.ByteString -> (Ctx, B.ByteString)+encrypt = combine+decrypt = combine
+ LICENSE view
@@ -0,0 +1,27 @@+Copyright (c) 2008-2012 Vincent Hanquez <vincent@snarc.org>++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:+1. Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.+2. Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.+3. Neither the name of the author nor the names of his contributors+ may be used to endorse or promote products derived from this software+ without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF+SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ Tests/Tests.hs view
@@ -0,0 +1,64 @@+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE OverloadedStrings #-}+module Main where++import Control.Applicative+import Control.Monad++import Test.Framework (Test, defaultMain, testGroup)+import Test.Framework.Providers.QuickCheck2 (testProperty)++import Test.QuickCheck+import Test.QuickCheck.Test+import Test.Framework.Providers.QuickCheck2 (testProperty)++import qualified Data.ByteString as B+import qualified Data.ByteString.Char8 as BC+import qualified Crypto.Cipher.RC4 as RC4++-- taken from wikipedia pages+kats :: [ (B.ByteString, B.ByteString, B.ByteString) ]+kats =+ [ ("Key"+ ,"Plaintext"+ ,B.pack [0xBB,0xF3,0x16,0xE8,0xD9,0x40,0xAF,0x0A,0xD3]+ )+ , ("Wiki"+ ,"pedia"+ ,B.pack [0x10,0x21,0xBF,0x04,0x20]+ )+ , ("Secret"+ ,"Attack at dawn"+ ,B.pack [0x45,0xA0,0x1F,0x64,0x5F,0xC3,0x5B,0x38,0x35,0x52,0x54,0x4B,0x9B,0xF5]+ )+ ]++runKat (key,plainText,cipherText) =+ snd (RC4.encrypt ctx plainText) == cipherText+ && snd (RC4.decrypt ctx cipherText) == plainText+ where ctx = RC4.initCtx $ key++katToTestProperty (kat, i) = testProperty ("KAT " ++ show i) (runKat kat)++data RC4Unit = RC4Unit B.ByteString B.ByteString+ deriving (Show)++instance Arbitrary RC4Unit where+ arbitrary = RC4Unit <$> generateKey <*> generatePlaintext++generateKey = choose (1, 284) >>= \sz -> (B.pack <$> replicateM sz arbitrary)+generatePlaintext = choose (0,324) >>= \sz -> (B.pack <$> replicateM sz arbitrary)++runOp f1 f2 (RC4Unit key plainText) =+ let ctx = RC4.initCtx key+ in (snd $ f2 ctx $ snd $ f1 ctx plainText) == plainText++tests =+ [ testGroup "KAT-RC4" $ map katToTestProperty $ zip kats [0..]+ , testGroup "id"+ [ testProperty "encrypt.decrypt" (runOp RC4.decrypt RC4.encrypt)+ , testProperty "decrypt.encrypt" (runOp RC4.encrypt RC4.decrypt)+ ]+ ]++main = defaultMain tests
+ cbits/rc4.c view
@@ -0,0 +1,63 @@+/* initial implementation by+ * Peter White <peter@janrain.com>+ */++/* C Standard includes */+#include <stdlib.h>+#include <stdio.h>+#include <string.h>+#include <stdint.h>++/* Local include */+#include "rc4.h"++/* Swap array elements i=State[i] and b=State[j]. */+static void swap(uint8_t *i, uint8_t *j)+{+ uint8_t temp;++ temp = *i;+ *i = *j;+ *j = temp;+}++/* Key scheduling algorithm. Swap array elements based on the key. */+void rc4_init(uint8_t *key, uint32_t keylen, struct rc4_ctx *ctx)+{+ uint32_t i, j;+ memset(ctx, 0, sizeof(struct rc4_ctx));++ /* initialize context */+ for (i = 0; i < 256; i++)+ ctx->state[i] = i;+ for (i = j = 0; i < 256; i++) {+ j = (j + ctx->state[i] + key[i % keylen]) % 256;+ swap(&ctx->state[i], &ctx->state[j]);+ }+}++/* Combine the stream generated by the rc4 with some input */+void rc4_combine(struct rc4_ctx *ctx, uint8_t *input, uint32_t len, uint8_t *output)+{+ uint32_t i = ctx->i;+ uint32_t j = ctx->j;+ uint32_t m;+ uint8_t si, sj;++ /* The RC4 algorithm */+ for (m = 0; m < len; m++) {+ i = (i + 1) & 0xff;+ si = ctx->state[i];+ j = (j + si) & 0xff;+ sj = ctx->state[j];+ /* swap(&state[i], &state[j]); */+ ctx->state[i] = sj;+ ctx->state[j] = si;+ /* Xor the key stream value into the input */+ *output++ = *input++ ^ (ctx->state[(si + sj) & 0xff]);+ }++ /* Output new S-box indices */+ ctx->i = i;+ ctx->j = j;+}
+ cbits/rc4.h view
@@ -0,0 +1,14 @@+#ifndef RC4_H+# define RC4_H++struct rc4_ctx+{+ uint8_t state[256];+ uint32_t i;+ uint32_t j;+};++void rc4_init(uint8_t * key, uint32_t keylen, struct rc4_ctx *ctx);+void rc4_combine(struct rc4_ctx *ctx, uint8_t *input, uint32_t len, uint8_t *output);++#endif
+ cipher-rc4.cabal view
@@ -0,0 +1,49 @@+Name: cipher-rc4+Version: 0.1.0+Description: Fast RC4 cipher implementation+License: BSD3+License-file: LICENSE+Copyright: Vincent Hanquez <vincent@snarc.org>+Author: Vincent Hanquez <vincent@snarc.org>+Maintainer: Vincent Hanquez <vincent@snarc.org>+Synopsis: Fast RC4 cipher implementation+Category: Cryptography+Build-Type: Simple+Homepage: http://github.com/vincenthz/hs-cipher-rc4+Cabal-Version: >=1.8+Extra-Source-Files: Tests/*.hs+ cbits/*.h++Library+ Build-Depends: base >= 4 && < 5+ , bytestring+ , vector+ Exposed-modules: Crypto.Cipher.RC4+ ghc-options: -Wall+ C-sources: cbits/rc4.c++Test-Suite test-cipher-rc4+ type: exitcode-stdio-1.0+ hs-source-dirs: Tests+ Main-Is: Tests.hs+ Build-depends: base >= 4 && < 5+ , cipher-rc4+ , bytestring+ , QuickCheck >= 2+ , test-framework >= 0.3.3+ , test-framework-quickcheck2 >= 0.2.9++Benchmark bench-cipher-rc4+ hs-source-dirs: Benchmarks+ Main-Is: Benchmarks.hs+ type: exitcode-stdio-1.0+ Build-depends: base >= 4 && < 5+ , bytestring+ , cipher-rc4+ , deepseq+ , criterion+ , mtl++source-repository head+ type: git+ location: git://github.com/vincenthz/hs-cipher-rc4