add RC4
This commit is contained in:
parent
7185a5b871
commit
f2bfecfa3e
92
Crypto/Cipher/RC4.hs
Normal file
92
Crypto/Cipher/RC4.hs
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
{-# LANGUAGE ForeignFunctionInterface, CPP #-}
|
||||||
|
-- |
|
||||||
|
-- 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 Data.Word
|
||||||
|
import Data.Byteable
|
||||||
|
import Foreign.Ptr
|
||||||
|
import Foreign.ForeignPtr
|
||||||
|
import System.IO.Unsafe
|
||||||
|
import Data.Byteable
|
||||||
|
import Data.ByteString (ByteString)
|
||||||
|
import qualified Data.ByteString as B
|
||||||
|
import qualified Data.ByteString.Internal as B
|
||||||
|
import Control.Applicative ((<$>))
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
unsafeDoIO :: IO a -> a
|
||||||
|
#if __GLASGOW_HASKELL__ > 704
|
||||||
|
unsafeDoIO = unsafeDupablePerformIO
|
||||||
|
#else
|
||||||
|
unsafeDoIO = unsafePerformIO
|
||||||
|
#endif
|
||||||
|
|
||||||
|
-- | The encryption state for RC4
|
||||||
|
newtype State = State ByteString
|
||||||
|
|
||||||
|
-- | 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 ()
|
||||||
|
|
||||||
|
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.
|
||||||
|
initialize :: Byteable key
|
||||||
|
=> key -- ^ The key
|
||||||
|
-> State -- ^ The RC4 context with the key mixed in
|
||||||
|
initialize key = unsafeDoIO $ do
|
||||||
|
State <$> (B.create 264 $ \ctx -> withBytePtr key $ \keyPtr -> c_rc4_init (castPtr keyPtr) (fromIntegral $ byteableLength key) (castPtr ctx))
|
||||||
|
|
||||||
|
-- | generate the next len bytes of the rc4 stream without combining
|
||||||
|
-- it to anything.
|
||||||
|
generate :: State -> Int -> (State, ByteString)
|
||||||
|
generate ctx len = combine ctx (B.replicate len 0)
|
||||||
|
|
||||||
|
-- | RC4 xor combination of the rc4 stream with an input
|
||||||
|
combine :: State -- ^ rc4 context
|
||||||
|
-> ByteString -- ^ input
|
||||||
|
-> (State, ByteString) -- ^ new rc4 context, and the output
|
||||||
|
combine (State cctx) clearText = unsafeDoIO $
|
||||||
|
B.mallocByteString 264 >>= \dctx ->
|
||||||
|
B.mallocByteString len >>= \outfptr ->
|
||||||
|
withByteStringPtr clearText $ \clearPtr ->
|
||||||
|
withByteStringPtr cctx $ \srcState ->
|
||||||
|
withForeignPtr dctx $ \dstState -> do
|
||||||
|
withForeignPtr outfptr $ \outptr -> do
|
||||||
|
B.memcpy dstState srcState 264
|
||||||
|
c_rc4_combine (castPtr dstState) clearPtr (fromIntegral len) outptr
|
||||||
|
return $! (State $! B.PS dctx 0 264, B.PS outfptr 0 len)
|
||||||
|
where len = B.length clearText
|
||||||
63
cbits/cryptonite_rc4.c
Normal file
63
cbits/cryptonite_rc4.c
Normal file
@ -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 "cryptonite_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 cryptonite_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 cryptonite_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;
|
||||||
|
}
|
||||||
14
cbits/cryptonite_rc4.h
Normal file
14
cbits/cryptonite_rc4.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef CRYPTONITE_RC4_H
|
||||||
|
# define CRYPTONITE_RC4_H
|
||||||
|
|
||||||
|
struct rc4_ctx
|
||||||
|
{
|
||||||
|
uint8_t state[256];
|
||||||
|
uint32_t i;
|
||||||
|
uint32_t j;
|
||||||
|
};
|
||||||
|
|
||||||
|
void cryptonite_rc4_init(uint8_t * key, uint32_t keylen, struct rc4_ctx *ctx);
|
||||||
|
void cryptonite_rc4_combine(struct rc4_ctx *ctx, uint8_t *input, uint32_t len, uint8_t *output);
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -23,6 +23,7 @@ source-repository head
|
|||||||
Library
|
Library
|
||||||
Exposed-modules: Crypto.Cipher.ChaCha
|
Exposed-modules: Crypto.Cipher.ChaCha
|
||||||
Crypto.Cipher.Salsa
|
Crypto.Cipher.Salsa
|
||||||
|
Crypto.Cipher.RC4
|
||||||
Crypto.MAC.Poly1305
|
Crypto.MAC.Poly1305
|
||||||
Crypto.MAC.HMAC
|
Crypto.MAC.HMAC
|
||||||
Crypto.KDF.PBKDF2
|
Crypto.KDF.PBKDF2
|
||||||
@ -57,6 +58,7 @@ Library
|
|||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
C-sources: cbits/cryptonite_chacha.c
|
C-sources: cbits/cryptonite_chacha.c
|
||||||
, cbits/cryptonite_salsa.c
|
, cbits/cryptonite_salsa.c
|
||||||
|
, cbits/cryptonite_rc4.c
|
||||||
, cbits/cryptonite_poly1305.c
|
, cbits/cryptonite_poly1305.c
|
||||||
, cbits/cryptonite_sha1.c
|
, cbits/cryptonite_sha1.c
|
||||||
, cbits/cryptonite_sha256.c
|
, cbits/cryptonite_sha256.c
|
||||||
|
|||||||
34
tests/KAT_RC4.hs
Normal file
34
tests/KAT_RC4.hs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
{-# LANGUAGE ViewPatterns #-}
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
module KAT_RC4 where
|
||||||
|
|
||||||
|
import Test.Tasty
|
||||||
|
import Test.Tasty.HUnit
|
||||||
|
|
||||||
|
import Data.ByteString (ByteString)
|
||||||
|
import Data.ByteString.Char8 ()
|
||||||
|
import qualified Crypto.Cipher.RC4 as RC4
|
||||||
|
|
||||||
|
-- taken from wikipedia pages
|
||||||
|
vectors :: [(ByteString, ByteString, ByteString)]
|
||||||
|
vectors =
|
||||||
|
[ ("Key"
|
||||||
|
,"Plaintext"
|
||||||
|
,"\xBB\xF3\x16\xE8\xD9\x40\xAF\x0A\xD3"
|
||||||
|
)
|
||||||
|
, ("Wiki"
|
||||||
|
,"pedia"
|
||||||
|
,"\x10\x21\xBF\x04\x20"
|
||||||
|
)
|
||||||
|
, ("Secret"
|
||||||
|
,"Attack at dawn"
|
||||||
|
,"\x45\xA0\x1F\x64\x5F\xC3\x5B\x38\x35\x52\x54\x4B\x9B\xF5"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
tests = testGroup "RC4"
|
||||||
|
$ map toKatTest $ zip is vectors
|
||||||
|
where toKatTest (i, (key, plainText, cipherText)) =
|
||||||
|
testCase (show i) (cipherText @=? snd (RC4.combine (RC4.initialize key) plainText))
|
||||||
|
is :: [Int]
|
||||||
|
is = [1..]
|
||||||
@ -18,6 +18,7 @@ import qualified KATSalsa
|
|||||||
import qualified KATHash
|
import qualified KATHash
|
||||||
import qualified KAT_HMAC
|
import qualified KAT_HMAC
|
||||||
import qualified KAT_PBKDF2
|
import qualified KAT_PBKDF2
|
||||||
|
import qualified KAT_RC4
|
||||||
|
|
||||||
b8_128_k0_i0 = "\xe2\x8a\x5f\xa4\xa6\x7f\x8c\x5d\xef\xed\x3e\x6f\xb7\x30\x34\x86\xaa\x84\x27\xd3\x14\x19\xa7\x29\x57\x2d\x77\x79\x53\x49\x11\x20\xb6\x4a\xb8\xe7\x2b\x8d\xeb\x85\xcd\x6a\xea\x7c\xb6\x08\x9a\x10\x18\x24\xbe\xeb\x08\x81\x4a\x42\x8a\xab\x1f\xa2\xc8\x16\x08\x1b\x8a\x26\xaf\x44\x8a\x1b\xa9\x06\x36\x8f\xd8\xc8\x38\x31\xc1\x8c\xec\x8c\xed\x81\x1a\x02\x8e\x67\x5b\x8d\x2b\xe8\xfc\xe0\x81\x16\x5c\xea\xe9\xf1\xd1\xb7\xa9\x75\x49\x77\x49\x48\x05\x69\xce\xb8\x3d\xe6\xa0\xa5\x87\xd4\x98\x4f\x19\x92\x5f\x5d\x33\x8e\x43\x0d"
|
b8_128_k0_i0 = "\xe2\x8a\x5f\xa4\xa6\x7f\x8c\x5d\xef\xed\x3e\x6f\xb7\x30\x34\x86\xaa\x84\x27\xd3\x14\x19\xa7\x29\x57\x2d\x77\x79\x53\x49\x11\x20\xb6\x4a\xb8\xe7\x2b\x8d\xeb\x85\xcd\x6a\xea\x7c\xb6\x08\x9a\x10\x18\x24\xbe\xeb\x08\x81\x4a\x42\x8a\xab\x1f\xa2\xc8\x16\x08\x1b\x8a\x26\xaf\x44\x8a\x1b\xa9\x06\x36\x8f\xd8\xc8\x38\x31\xc1\x8c\xec\x8c\xed\x81\x1a\x02\x8e\x67\x5b\x8d\x2b\xe8\xfc\xe0\x81\x16\x5c\xea\xe9\xf1\xd1\xb7\xa9\x75\x49\x77\x49\x48\x05\x69\xce\xb8\x3d\xe6\xa0\xa5\x87\xd4\x98\x4f\x19\x92\x5f\x5d\x33\x8e\x43\x0d"
|
||||||
|
|
||||||
@ -72,6 +73,7 @@ tests = testGroup "cryptonite"
|
|||||||
, KATHash.tests
|
, KATHash.tests
|
||||||
, KAT_HMAC.tests
|
, KAT_HMAC.tests
|
||||||
, KAT_PBKDF2.tests
|
, KAT_PBKDF2.tests
|
||||||
|
, KAT_RC4.tests
|
||||||
]
|
]
|
||||||
where chachaRunSimple expected rounds klen nonceLen =
|
where chachaRunSimple expected rounds klen nonceLen =
|
||||||
let chacha = ChaCha.initialize rounds (B.replicate klen 0) (B.replicate nonceLen 0)
|
let chacha = ChaCha.initialize rounds (B.replicate klen 0) (B.replicate nonceLen 0)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user