diff --git a/Crypto/Cipher/Camellia.hs b/Crypto/Cipher/Camellia.hs
new file mode 100644
--- /dev/null
+++ b/Crypto/Cipher/Camellia.hs
@@ -0,0 +1,320 @@
+-- |
+-- Module      : Crypto.Cipher.Camellia
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : Good
+--
+-- this only cover Camellia 128 bits for now, API will change once
+-- 192 and 256 mode are implemented too
+
+module Crypto.Cipher.Camellia (
+	Key(..),
+	initKey,
+	encrypt,
+	decrypt
+	) where
+
+import Data.Word
+import Data.Vector.Unboxed
+import Data.Bits
+import qualified Data.ByteString as B
+
+data Mode = Decrypt | Encrypt
+
+-- should probably use crypto large word ?
+data Word128 = Word128 !Word64 !Word64 deriving (Show, Eq)
+
+w128tow64 :: Word128 -> (Word64, Word64)
+w128tow64 (Word128 w1 w2) = (w1, w2)
+
+w64tow128 :: (Word64, Word64) -> Word128
+w64tow128 (x1, x2) = Word128 x1 x2
+
+w64tow8 :: Word64 -> (Word8, Word8, Word8, Word8, Word8, Word8, Word8, Word8)
+w64tow8 x = (t1, t2, t3, t4, t5, t6, t7, t8)
+	where
+		t1 = fromIntegral (x `shiftR` 56)
+		t2 = fromIntegral (x `shiftR` 48)
+		t3 = fromIntegral (x `shiftR` 40)
+		t4 = fromIntegral (x `shiftR` 32)
+		t5 = fromIntegral (x `shiftR` 24)
+		t6 = fromIntegral (x `shiftR` 16)
+		t7 = fromIntegral (x `shiftR` 8)
+		t8 = fromIntegral (x)
+
+w8tow64 :: (Word8, Word8, Word8, Word8, Word8, Word8, Word8, Word8) -> Word64
+w8tow64 (t1, t2, t3, t4, t5, t6, t7, t8) =
+	(sh t1 56 .|. sh t2 48 .|. sh t3 40 .|. sh t4 32 .|. sh t5 24 .|. sh t6 16 .|. sh t7 8 .|. sh t8 0)
+	where sh i r = (fromIntegral i) `shiftL` r
+
+w64tow32 :: Word64 -> (Word32, Word32)
+w64tow32 w = (fromIntegral (w `shiftR` 32), fromIntegral (w .&. 0xffffffff))
+
+w32tow64 :: (Word32, Word32) -> Word64
+w32tow64 (x1, x2) = ((fromIntegral x1) `shiftL` 32) .|. (fromIntegral x2)
+
+w128tow8 :: Word128 -> [Word8]
+w128tow8 (Word128 x1 x2) = [t1,t2,t3,t4,t5,t6,t7,t8,u1,u2,u3,u4,u5,u6,u7,u8]
+	where
+		(t1, t2, t3, t4, t5, t6, t7, t8) = w64tow8 x1
+		(u1, u2, u3, u4, u5, u6, u7, u8) = w64tow8 x2
+
+getWord64 :: B.ByteString -> Word64
+getWord64 s = sh 0 56 .|. sh 1 48 .|. sh 2 40 .|. sh 3 32 .|. sh 4 24 .|. sh 5 16 .|. sh 6 8 .|. sh 7 0
+	where
+		sh i l = (fromIntegral (s `B.index` i) `shiftL` l)
+
+getWord128 :: B.ByteString -> Word128
+getWord128 s = Word128 (getWord64 s) (getWord64 (B.drop 8 s))
+
+putWord128 :: Word128 -> B.ByteString
+putWord128 = B.pack . w128tow8
+
+sbox :: Vector Word8
+sbox = fromList
+	[112,130, 44,236,179, 39,192,229,228,133, 87, 53,234, 12,174, 65
+	, 35,239,107,147, 69, 25,165, 33,237, 14, 79, 78, 29,101,146,189
+	,134,184,175,143,124,235, 31,206, 62, 48,220, 95, 94,197, 11, 26
+	,166,225, 57,202,213, 71, 93, 61,217,  1, 90,214, 81, 86,108, 77
+	,139, 13,154,102,251,204,176, 45,116, 18, 43, 32,240,177,132,153
+	,223, 76,203,194, 52,126,118,  5,109,183,169, 49,209, 23,  4,215
+	, 20, 88, 58, 97,222, 27, 17, 28, 50, 15,156, 22, 83, 24,242, 34
+	,254, 68,207,178,195,181,122,145, 36,  8,232,168, 96,252,105, 80
+	,170,208,160,125,161,137, 98,151, 84, 91, 30,149,224,255,100,210
+	, 16,196,  0, 72,163,247,117,219,138,  3,230,218,  9, 63,221,148
+	,135, 92,131,  2,205, 74,144, 51,115,103,246,243,157,127,191,226
+	, 82,155,216, 38,200, 55,198, 59,129,150,111, 75, 19,190, 99, 46
+	,233,121,167,140,159,110,188,142, 41,245,249,182, 47,253,180, 89
+	,120,152,  6,106,231, 70,113,186,212, 37,171, 66,136,162,141,250
+	,114,  7,185, 85,248,238,172, 10, 54, 73, 42,104, 60, 56,241,164
+	, 64, 40,211,123,187,201, 67,193, 21,227,173,244,119,199,128,158
+	]
+
+sbox1 :: Word8 -> Word8
+sbox1 x = sbox ! (fromIntegral x)
+
+sbox2 :: Word8 -> Word8
+sbox2 x = sbox1 x `rotateL` 1;
+
+sbox3 :: Word8 -> Word8
+sbox3 x = sbox1 x `rotateL` 7;
+
+sbox4 :: Word8 -> Word8
+sbox4 x = sbox1 (x `rotateL` 1);
+
+sigma1 :: Word64
+sigma1 = 0xA09E667F3BCC908B
+
+sigma2 :: Word64
+sigma2 = 0xB67AE8584CAA73B2
+
+sigma3 :: Word64
+sigma3 = 0xC6EF372FE94F82BE
+
+sigma4 :: Word64
+sigma4 = 0x54FF53A5F1D36F1C
+
+sigma5 :: Word64
+sigma5 = 0x10E527FADE682D1D
+
+sigma6 :: Word64
+sigma6 = 0xB05688C2B3E6C1FD
+
+rotl128 :: Word128 -> Int -> Word128
+rotl128 v               0  = v
+rotl128 (Word128 x1 x2) 64 = Word128 x2 x1
+
+rotl128 v@(Word128 x1 x2) w
+	| w > 64    = (v `rotl128` 64) `rotl128` (w - 64)
+	| otherwise = Word128 (x1high .|. x2low) (x2high .|. x1low)
+		where
+			splitBits i = (i .&. complement x, i .&. x)
+				where x = 2 ^ w - 1
+			(x1high, x1low) = splitBits (x1 `rotateL` w)
+			(x2high, x2low) = splitBits (x2 `rotateL` w)
+
+data Key = Key
+	{ k :: Vector Word64
+	, kw :: Vector Word64
+	, ke :: Vector Word64 }
+	deriving (Show)
+
+setKeyInterim :: [Word8] -> (Word128, Word128, Word128, Word128)
+setKeyInterim [a0,a1,a2,a3,a4,a5,a6,a7,b0,b1,b2,b3,b4,b5,b6,b7] =
+	let kL = (w8tow64 (a0,a1,a2,a3,a4,a5,a6,a7), w8tow64 (b0,b1,b2,b3,b4,b5,b6,b7)) in
+	let kR = (0, 0) in
+
+	let kA =
+		let d1 = (fst kL `xor` fst kR) in
+		let d2 = (snd kL `xor` snd kR) in
+
+		let d3 = d2 `xor` feistel d1 sigma1 in
+		let d4 = d1 `xor` feistel d3 sigma2 in
+		let d5 = d4 `xor` (fst kL) in
+		let d6 = d3 `xor` (snd kL) in
+		let d7 = d6 `xor` feistel d5 sigma3 in
+		let d8 = d5 `xor` feistel d7 sigma4 in
+		(d8, d7)
+		in
+
+	let kB =
+		let d1 = (fst kA `xor` fst kR) in
+		let d2 = (snd kA `xor` snd kR) in
+
+		let d3 = d2 `xor` feistel d1 sigma5 in
+		let d4 = d1 `xor` feistel d3 sigma6 in
+		(d4, d3)
+		in
+	(w64tow128 kL, w64tow128 kR, w64tow128 kA, w64tow128 kB)
+
+setKeyInterim _ = error "wrong size key"
+
+initKey :: [Word8] -> Either String Key
+initKey l =
+	let (kL, _, kA, _) = setKeyInterim l in
+
+	let (kw1, kw2) = w128tow64 (kL `rotl128` 0) in
+	let (k1, k2)   = w128tow64 (kA `rotl128` 0) in
+	let (k3, k4)   = w128tow64 (kL `rotl128` 15) in
+	let (k5, k6)   = w128tow64 (kA `rotl128` 15) in
+	let (ke1, ke2) = w128tow64 (kA `rotl128` 30) in --ke1 = (KA <<<  30) >> 64; ke2 = (KA <<<  30) & MASK64;
+	let (k7, k8)   = w128tow64 (kL `rotl128` 45) in --k7  = (KL <<<  45) >> 64; k8  = (KL <<<  45) & MASK64;
+	let (k9, _)    = w128tow64 (kA `rotl128` 45) in --k9  = (KA <<<  45) >> 64;
+	let (_, k10)   = w128tow64 (kL `rotl128` 60) in
+	let (k11, k12) = w128tow64 (kA `rotl128` 60) in
+	let (ke3, ke4) = w128tow64 (kL `rotl128` 77) in
+	let (k13, k14) = w128tow64 (kL `rotl128` 94) in
+	let (k15, k16) = w128tow64 (kA `rotl128` 94) in
+	let (k17, k18) = w128tow64 (kL `rotl128` 111) in
+	let (kw3, kw4) = w128tow64 (kA `rotl128` 111) in
+
+	Right $ Key
+		{ kw = fromList [ kw1, kw2, kw3, kw4 ]
+		, ke = fromList [ ke1, ke2, ke3, ke4 ]
+		, k  = fromList [ k1, k2, k3, k4, k5, k6, k7, k8, k9,
+		                  k10, k11, k12, k13, k14, k15, k16, k17, k18 ]
+		}
+
+feistel :: Word64 -> Word64 -> Word64
+feistel fin sk = 
+	let x = fin `xor` sk in
+	let (t1, t2, t3, t4, t5, t6, t7, t8) = w64tow8 x in
+	let t1' = sbox1 t1 in
+	let t2' = sbox2 t2 in
+	let t3' = sbox3 t3 in
+	let t4' = sbox4 t4 in
+	let t5' = sbox2 t5 in
+	let t6' = sbox3 t6 in
+	let t7' = sbox4 t7 in
+	let t8' = sbox1 t8 in
+	let y1 = t1' `xor` t3' `xor` t4' `xor` t6' `xor` t7' `xor` t8' in
+	let y2 = t1' `xor` t2' `xor` t4' `xor` t5' `xor` t7' `xor` t8' in
+	let y3 = t1' `xor` t2' `xor` t3' `xor` t5' `xor` t6' `xor` t8' in
+	let y4 = t2' `xor` t3' `xor` t4' `xor` t5' `xor` t6' `xor` t7' in
+	let y5 = t1' `xor` t2' `xor` t6' `xor` t7' `xor` t8' in
+	let y6 = t2' `xor` t3' `xor` t5' `xor` t7' `xor` t8' in
+	let y7 = t3' `xor` t4' `xor` t5' `xor` t6' `xor` t8' in
+	let y8 = t1' `xor` t4' `xor` t5' `xor` t6' `xor` t7' in
+	w8tow64 (y1, y2, y3, y4, y5, y6, y7, y8)
+
+fl :: Word64 -> Word64 -> Word64
+fl fin sk =
+	let (x1, x2) = w64tow32 fin in
+	let (k1, k2) = w64tow32 sk in
+	let y2 = x2 `xor` ((x1 .&. k1) `rotateL` 1) in
+	let y1 = x1 `xor` (y2 .|. k2) in
+	w32tow64 (y1, y2)
+
+flinv :: Word64 -> Word64 -> Word64
+flinv fin sk =
+	let (y1, y2) = w64tow32 fin in
+	let (k1, k2) = w64tow32 sk in
+	let x1 = y1 `xor` (y2 .|. k2) in
+	let x2 = y2 `xor` ((x1 .&. k1) `rotateL` 1) in
+	w32tow64 (x1, x2)
+
+{- in decrypt mode 0->17 1->16 ... -}
+getKeyK :: Mode -> Key -> Int -> Word64
+getKeyK Encrypt key i = k key ! i
+getKeyK Decrypt key i = k key ! (17 - i)
+
+{- in decrypt mode 0->3 1->2 2->1 3->0 -}
+getKeyKe :: Mode -> Key -> Int -> Word64
+getKeyKe Encrypt key i = ke key ! i
+getKeyKe Decrypt key i = ke key ! (3 - i)
+
+{- in decrypt mode 0->2 1->3 2->0 3->1 -}
+getKeyKw :: Mode -> Key -> Int -> Word64
+getKeyKw Encrypt key i = kw key ! i
+getKeyKw Decrypt key i = kw key ! ((i + 2) `mod` 4)
+
+{- perform the following
+	D2 = D2 ^ F(D1, k1);     // Round 1
+	D1 = D1 ^ F(D2, k2);     // Round 2
+	D2 = D2 ^ F(D1, k3);     // Round 3
+	D1 = D1 ^ F(D2, k4);     // Round 4
+	D2 = D2 ^ F(D1, k5);     // Round 5
+	D1 = D1 ^ F(D2, k6);     // Round 6
+ -}
+doBlockRound :: Mode -> Key -> Word64 -> Word64 -> Int -> (Word64, Word64)
+doBlockRound mode key d1 d2 i =
+	let r1 = d2 `xor` feistel d1 (getKeyK mode key (0+i)) in     {- Round 1+i -}
+	let r2 = d1 `xor` feistel r1 (getKeyK mode key (1+i)) in     {- Round 2+i -}
+	let r3 = r1 `xor` feistel r2 (getKeyK mode key (2+i)) in     {- Round 3+i -}
+	let r4 = r2 `xor` feistel r3 (getKeyK mode key (3+i)) in     {- Round 4+i -}
+	let r5 = r3 `xor` feistel r4 (getKeyK mode key (4+i)) in     {- Round 5+i -}
+	let r6 = r4 `xor` feistel r5 (getKeyK mode key (5+i)) in     {- Round 6+i -}
+	(r6, r5)
+
+doBlock :: Mode -> Key -> Word128 -> Word128
+doBlock mode key m =
+	let (d1, d2) = w128tow64 m in
+
+	let d1a = d1 `xor` (getKeyKw mode key 0) in {- Prewhitening -}
+	let d2a = d2 `xor` (getKeyKw mode key 1) in
+
+	let (d1b, d2b) = doBlockRound mode key d1a d2a 0 in
+
+	let d1c = fl    d1b (getKeyKe mode key 0) in {- FL -}
+	let d2c = flinv d2b (getKeyKe mode key 1) in {- FLINV -}
+
+	let (d1d, d2d) = doBlockRound mode key d1c d2c 6 in
+
+	let d1e = fl    d1d (getKeyKe mode key 2) in {- FL -}
+	let d2e = flinv d2d (getKeyKe mode key 3) in {- FLINV -}
+
+	let (d1f, d2f) = doBlockRound mode key d1e d2e 12 in
+
+	let d2g = d2f `xor` (getKeyKw mode key 2) in {- Postwhitening -}
+	let d1g = d1f `xor` (getKeyKw mode key 3) in
+	w64tow128 (d2g, d1g)
+
+{- encryption for 128 bits blocks -}
+encryptBlock :: Key -> Word128 -> Word128
+encryptBlock = doBlock Encrypt
+
+{- decryption for 128 bits blocks -}
+decryptBlock :: Key -> Word128 -> Word128
+decryptBlock = doBlock Decrypt
+
+encryptChunk :: Key -> B.ByteString -> B.ByteString
+encryptChunk key b = putWord128 $ encryptBlock key $ getWord128 b
+
+decryptChunk :: Key -> B.ByteString -> B.ByteString
+decryptChunk key b = putWord128 $ decryptBlock key $ getWord128 b
+
+doChunks :: (B.ByteString -> B.ByteString) -> B.ByteString -> [B.ByteString]
+doChunks f b =
+	let (x, rest) = B.splitAt 16 b in
+	if B.length rest >= 16
+		then f x : doChunks f rest
+		else [ f x ]
+
+{- | encrypt with the key a bytestring and returns the encrypted bytestring -}
+encrypt :: Key -> B.ByteString -> B.ByteString
+encrypt key b = B.concat $ doChunks (encryptChunk key) b
+
+{- | decrypt with the key a bytestring and returns the encrypted bytestring -}
+decrypt :: Key -> B.ByteString -> B.ByteString
+decrypt key b = B.concat $ doChunks (decryptChunk key) b
diff --git a/Crypto/Cipher/RC4.hs b/Crypto/Cipher/RC4.hs
new file mode 100644
--- /dev/null
+++ b/Crypto/Cipher/RC4.hs
@@ -0,0 +1,82 @@
+-- |
+-- Module      : Crypto.Cipher.RC4
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : Good
+--
+
+module Crypto.Cipher.RC4 (
+	Ctx,
+	initCtx,
+	encrypt,
+	decrypt,
+	encryptlazy,
+	decryptlazy
+	) where
+
+import Data.Vector.Unboxed
+import Data.Bits (xor)
+import Data.Word
+import Control.Arrow (second)
+import Data.Maybe (fromJust)
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Lazy as L
+import Prelude hiding (length)
+
+type Ctx = (Vector Word8, Word8, Word8)
+
+swap :: Vector Word8 -> Int -> Int -> Vector Word8
+swap arr x y
+	| x == y    = arr
+	| otherwise = arr // [(x, arr ! y), (y, arr ! x)]
+
+setKey :: Vector Word8 -> Int -> Word8 -> Int -> Vector Word8 -> Vector Word8
+setKey _   _  _  256 arr = arr
+setKey key ki si i   arr = setKey key ki' si' (i + 1) (swap arr (fromIntegral si') i)
+	where
+		si' = si + (key ! ki) + (arr ! i)
+		ki' = (ki + 1) `mod` (length key)
+
+{- | initCtx initialize the Ctx with the key as parameter.
+   the key can be of any size but not empty -}
+initCtx :: [Word8] -> Ctx
+initCtx key = (setKey (fromList key) 0 0 0 initialArray, 0, 0)
+	where
+		initialArray = generate 256 (\i -> fromIntegral i)
+
+getNextChar :: Ctx -> (Word8, Ctx)
+getNextChar (arr, x, y) = (c, (na, x', y'))
+	where
+		na = swap arr (fromIntegral x') (fromIntegral y')
+		x' = x + 1
+		y' = sx + y
+		sx = arr ! (fromIntegral x')
+		c  = na ! (fromIntegral (sx + (arr ! (fromIntegral y'))))
+
+genstream :: Ctx -> Int -> (B.ByteString, Ctx)
+genstream ctx len = second fromJust $ B.unfoldrN len (\c -> Just $ getNextChar c) ctx
+
+{- | encrypt with the current context a bytestring and returns a new context
+   and the resulted encrypted bytestring -}
+encrypt :: Ctx -> B.ByteString -> (Ctx, B.ByteString)
+encrypt ctx d = (ctx', B.pack $ B.zipWith xor d rc4stream)
+	where
+		(rc4stream, ctx') = genstream ctx (B.length d)
+
+{- | decrypt with the current context a bytestring and returns a new context
+   and the resulted decrypted bytestring -}
+decrypt :: Ctx -> B.ByteString -> (Ctx, B.ByteString)
+decrypt = encrypt
+
+{- | encrypt with the current context a lazy bytestring and returns a new context
+   and the resulted lencrypted lazy bytestring -}
+encryptlazy :: Ctx -> L.ByteString -> (Ctx, L.ByteString)
+encryptlazy ctx d = (ctx', L.pack $ L.zipWith xor d (L.fromChunks [ rc4stream ]))
+	where
+		(rc4stream, ctx') = genstream ctx (fromIntegral $ L.length d)
+
+{- | decrypt with the current context a lazy bytestring and returns a new context
+   and the resulted decrypted lazy bytestring -}
+decryptlazy :: Ctx -> L.ByteString -> (Ctx, L.ByteString)
+decryptlazy = encryptlazy
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2010 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.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/Tests.hs b/Tests.hs
new file mode 100644
--- /dev/null
+++ b/Tests.hs
@@ -0,0 +1,70 @@
+import Test.HUnit ((~:), (~=?))
+import qualified Test.HUnit as Unit
+import Data.Char
+import Data.Bits
+import Data.Word
+import qualified Data.ByteString as B
+import qualified Crypto.Cipher.RC4 as RC4
+import qualified Crypto.Cipher.Camellia as Camellia
+
+{- CAMELLIA test vectors -}
+{-
+   Here are test data for Camellia in hexadecimal form.
+
+   128-bit key
+       Key       : 01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10
+       Plaintext : 01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10
+       Ciphertext: 67 67 31 38 54 96 69 73 08 57 06 56 48 ea be 43
+
+   192-bit key
+       Key       : 01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10
+                 : 00 11 22 33 44 55 66 77
+       Plaintext : 01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10
+       Ciphertext: b4 99 34 01 b3 e9 96 f8 4e e5 ce e7 d7 9b 09 b9
+
+   256-bit key
+       Key       : 01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10
+                 : 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff
+       Plaintext : 01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10
+       Ciphertext: 9a cc 23 7d ff 16 d7 6c 20 ef 7c 91 9e 3a 75 09
+-}
+
+encryptStream fi fc key plaintext = B.unpack $ snd $ fc (fi key) plaintext
+
+encryptBlock fi fc key plaintext =
+	let e = fi key in
+	case e of
+		Right k -> B.unpack $ fc k plaintext
+		Left  e -> error e
+
+wordify :: [Char] -> [Word8]
+wordify = map (toEnum . fromEnum)
+
+packString :: [Char] -> B.ByteString
+packString = B.pack . wordify
+
+vectors_rc4 =
+	[ (wordify "Key", packString "Plaintext", [ 0xBB,0xF3,0x16,0xE8,0xD9,0x40,0xAF,0x0A,0xD3 ])
+	, (wordify "Wiki", packString "pedia", [ 0x10,0x21,0xBF,0x04,0x20 ])
+	, (wordify "Secret", packString "Attack at dawn", [ 0x45,0xA0,0x1F,0x64,0x5F,0xC3,0x5B,0x38,0x35,0x52,0x54,0x4B,0x9B,0xF5 ])
+	]
+
+vectors_camellia128 =
+	[ 
+	  ([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+	   B.pack [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+	   [0x3d,0x02,0x80,0x25,0xb1,0x56,0x32,0x7c,0x17,0xf7,0x62,0xc1,0xf2,0xcb,0xca,0x71]),
+	  ([0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10],
+	   B.pack [0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10],
+           [0x67,0x67,0x31,0x38,0x54,0x96,0x69,0x73,0x08,0x57,0x06,0x56,0x48,0xea,0xbe,0x43])
+	]
+
+vectors =
+	[ ("RC4",      vectors_rc4,         encryptStream RC4.initCtx RC4.encrypt)
+	, ("Camellia", vectors_camellia128, encryptBlock Camellia.initKey Camellia.encrypt)
+	]
+
+utests :: [Unit.Test]
+utests = concatMap (\(name, v, f) -> map (\(k,p,e) -> name ~: name ~: e ~=? f k p) v) vectors
+
+main = Unit.runTestTT (Unit.TestList utests)
diff --git a/cryptocipher.cabal b/cryptocipher.cabal
new file mode 100644
--- /dev/null
+++ b/cryptocipher.cabal
@@ -0,0 +1,34 @@
+Name:                cryptocipher
+Version:             0.1
+Description:         Symmetrical Block and Stream Ciphers
+License:             BSD3
+License-file:        LICENSE
+Copyright:           Vincent Hanquez <vincent@snarc.org>
+Author:              Vincent Hanquez <vincent@snarc.org>
+Maintainer:          Vincent Hanquez <vincent@snarc.org>
+Synopsis:            Symmetrical Block and Stream Ciphers
+Category:            Cryptography
+Build-Type:          Simple
+Cabal-Version:       >=1.6
+
+Flag test
+  Description:       Build unit test
+  Default:           False
+
+Library
+  Build-Depends:     base >= 3 && < 5, bytestring, haskell98, vector
+  Exposed-modules:   Crypto.Cipher.RC4
+                     Crypto.Cipher.Camellia
+  ghc-options:       -Wall
+
+Executable           Tests
+  Main-Is:           Tests.hs
+  if flag(test)
+    Buildable:       True
+    Build-depends:   base >= 3 && < 5, HUnit, bytestring
+  else
+    Buildable:       False
+
+source-repository head
+  type:     git
+  location: git://github.com/vincenthz/hs-cryptocipher
