diff --git a/Crypto/Cipher/AES.hs b/Crypto/Cipher/AES.hs
new file mode 100644
--- /dev/null
+++ b/Crypto/Cipher/AES.hs
@@ -0,0 +1,492 @@
+module Crypto.Cipher.AES
+	( Key
+	, encrypt
+	, decrypt
+	, initKey128
+	-- * those key sizes are not actually working right now.
+	, initKey192
+	, initKey256
+	) where
+
+import Data.Word
+import Data.Vector.Unboxed (Vector, (//))
+import qualified Data.Vector.Unboxed as V
+import Data.Bits
+import Data.ByteString (ByteString)
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Unsafe as B
+import Control.Monad.State.Strict
+
+newtype Key = Key (Int, Vector Word8)
+	deriving (Show,Eq)
+
+{- | encrypt with the key a bytestring and returns the encrypted bytestring -}
+encrypt :: Key -> B.ByteString -> B.ByteString
+encrypt key b
+	| B.length b `mod` 16 == 0 = B.concat $ doChunks (coreEncrypt key) b
+	| otherwise                = error "wrong length"
+
+{- | decrypt with the key a bytestring and returns the encrypted bytestring -}
+decrypt :: Key -> B.ByteString -> B.ByteString
+decrypt key b
+	| B.length b `mod` 16 == 0 = B.concat $ doChunks (coreDecrypt key) b
+	| otherwise                = error "wrong length"
+
+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 ]
+
+coreEncrypt :: Key -> ByteString -> ByteString
+coreEncrypt key input = swapBlockInv $ aesMain 10 key $ swapBlock input
+
+coreDecrypt :: Key -> ByteString -> ByteString
+coreDecrypt key input = swapBlockInv $ aesMainInv 10 key $ swapBlock input
+
+initKey128 :: ByteString -> Either String Key
+initKey128 = initKey 16 10
+
+initKey192 :: ByteString -> Either String Key
+initKey192 = initKey 24 12
+
+initKey256 :: ByteString -> Either String Key
+initKey256 = initKey 32 14
+
+initKey :: Int -> Int -> ByteString -> Either String Key
+initKey sz nbr b
+	| B.length b == sz = Right $ coreExpandKey nbr (V.generate sz $ B.unsafeIndex b)
+	| otherwise        = Left "wrong key size"
+
+aesMain :: Int -> Key -> Vector Word8 -> Vector Word8
+aesMain nbr key block = flip execState block $ do
+	addRoundKey $ createRoundKey key 0
+
+	forM_ [1..nbr-1] $ \i -> do
+		modify shiftRows
+		mixColumns
+		addRoundKey $ createRoundKey key i
+
+        modify shiftRows
+        addRoundKey $ createRoundKey key nbr
+
+aesMainInv :: Int -> Key -> Vector Word8 -> Vector Word8
+aesMainInv nbr key block = flip execState block $ do
+	addRoundKey $ createRoundKey key nbr
+        
+	forM_ (reverse [1..nbr-1]) $ \i -> do
+		modify shiftRowsInv
+		addRoundKey $ createRoundKey key i
+		mixColumnsInv
+
+        modify shiftRowsInv
+        addRoundKey $ createRoundKey key 0
+
+{- 0 -> 0, 1 -> 4, ... -}
+swapIndexes :: Vector Int
+swapIndexes = V.fromList [ 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 ]
+swapIndex :: Int -> Int
+swapIndex i = V.unsafeIndex swapIndexes i
+
+coreExpandKey :: Int -> Vector Word8 -> Key
+coreExpandKey nbr vkey = Key (nbr, V.concat (ek0 : ekN))
+	where
+		ek0 = vkey
+		ekN = reverse $ snd $ foldl generateFold (ek0, []) [1..nbr]
+
+		generateFold (prevk, accK) it = let nk = generate prevk it in (nk, nk : accK)
+		generate prevk it =
+			let v0 = cR0 it (V.unsafeIndex prevk 12)
+			                (V.unsafeIndex prevk 13)
+			                (V.unsafeIndex prevk 14)
+			                (V.unsafeIndex prevk 15) in
+			let (e0,e1,e2,e3) = xorVector prevk 0 v0 in
+			let (e4,e5,e6,e7) = xorVector prevk 4 (e0,e1,e2,e3) in
+			let (e8,e9,e10,e11) = xorVector prevk 8 (e4,e5,e6,e7) in
+			let (e12,e13,e14,e15) = xorVector prevk 12 (e8,e9,e10,e11) in
+			V.fromList [e0,e1,e2,e3,e4,e5,e6,e7,e8,e9,e10,e11,e12,e13,e14,e15]
+
+		xorVector k i (t0,t1,t2,t3) =
+			( V.unsafeIndex k (i+0) `xor` t0
+			, V.unsafeIndex k (i+1) `xor` t1
+			, V.unsafeIndex k (i+2) `xor` t2
+			, V.unsafeIndex k (i+3) `xor` t3
+			)
+
+		cR0 it r0 r1 r2 r3 =
+			(mSbox r1 `xor` mRcon it, mSbox r2, mSbox r3, mSbox r0)
+
+shiftRows :: Vector Word8 -> Vector Word8
+shiftRows ost =
+	let st = V.map mSbox ost in
+	st // [ (7, V.unsafeIndex st 4), (4, V.unsafeIndex st 5), (5, V.unsafeIndex st 6), (6, V.unsafeIndex st 7)
+	      , (10, V.unsafeIndex st 8), (11, V.unsafeIndex st 9), (8, V.unsafeIndex st 10), (9, V.unsafeIndex st 11)
+	      , (13, V.unsafeIndex st 12), (14, V.unsafeIndex st 13), (15, V.unsafeIndex st 14), (12, V.unsafeIndex st 15)
+	      ]
+
+addRoundKey :: Vector Word8 -> State (Vector Word8) ()
+addRoundKey rk = modify (\state -> V.zipWith (\v1 v2 -> v1 `xor` v2) state rk)
+
+mixColumns :: State (Vector Word8) ()
+mixColumns =
+	forM_ [0..3] $ \i -> do
+		state <- get
+		let cpy0 = V.unsafeIndex state (0 * 4 + i)
+		let cpy1 = V.unsafeIndex state (1 * 4 + i)
+		let cpy2 = V.unsafeIndex state (2 * 4 + i)
+		let cpy3 = V.unsafeIndex state (3 * 4 + i)
+
+		let state0  = gm2 cpy0 `xor` gm1 cpy3 `xor` gm1 cpy2 `xor` gm3 cpy1
+                let state4  = gm2 cpy1 `xor` gm1 cpy0 `xor` gm1 cpy3 `xor` gm3 cpy2
+                let state8  = gm2 cpy2 `xor` gm1 cpy1 `xor` gm1 cpy0 `xor` gm3 cpy3
+                let state12 = gm2 cpy3 `xor` gm1 cpy2 `xor` gm1 cpy1 `xor` gm3 cpy0
+
+		put (state // [ (i, state0), (4+i, state4), (8+i, state8), (12+i, state12) ])
+	where
+		gm1 a = a
+		gm2 a = V.unsafeIndex gmtab2 $ fromIntegral a
+		gm3 a = V.unsafeIndex gmtab3 $ fromIntegral a
+
+createRoundKey :: Key -> Int -> Vector Word8
+createRoundKey (Key (_, key)) i = V.generate 16 (\n -> V.unsafeIndex key (16 * i + swapIndex n))
+
+shiftRowsInv :: Vector Word8 -> Vector Word8
+shiftRowsInv st =
+	let nst = st //
+		[ (5, V.unsafeIndex st 4), (6, V.unsafeIndex st 5), (7, V.unsafeIndex st 6), (4, V.unsafeIndex st 7)
+		, (10, V.unsafeIndex st 8), (11, V.unsafeIndex st 9), (8, V.unsafeIndex st 10), (9, V.unsafeIndex st 11)
+		, (15, V.unsafeIndex st 12), (12, V.unsafeIndex st 13), (13, V.unsafeIndex st 14), (14, V.unsafeIndex st 15)
+		] in
+	V.map mRsbox nst
+
+mixColumnsInv :: State (Vector Word8) ()
+mixColumnsInv =
+	forM_ [0..3] $ \i -> do
+		state <- get
+		let cpy0 = V.unsafeIndex state (0 * 4 + i)
+		let cpy1 = V.unsafeIndex state (1 * 4 + i)
+		let cpy2 = V.unsafeIndex state (2 * 4 + i)
+		let cpy3 = V.unsafeIndex state (3 * 4 + i)
+
+		let state0  = gm14 cpy0 `xor` gm9 cpy3 `xor` gm13 cpy2 `xor` gm11 cpy1
+		let state4  = gm14 cpy1 `xor` gm9 cpy0 `xor` gm13 cpy3 `xor` gm11 cpy2
+		let state8  = gm14 cpy2 `xor` gm9 cpy1 `xor` gm13 cpy0 `xor` gm11 cpy3
+		let state12 = gm14 cpy3 `xor` gm9 cpy2 `xor` gm13 cpy1 `xor` gm11 cpy0
+
+		put (state // [ (i, state0), (4+i, state4), (8+i, state8), (12+i, state12) ])
+	where
+		gm14 a = V.unsafeIndex gmtab14 $ fromIntegral a
+		gm13 a = V.unsafeIndex gmtab13 $ fromIntegral a
+		gm11 a = V.unsafeIndex gmtab11 $ fromIntegral a
+		gm9 a  = V.unsafeIndex gmtab9 $ fromIntegral a
+
+swapBlock :: ByteString -> Vector Word8
+swapBlock b = V.generate 16 (\i -> B.unsafeIndex b $ swapIndex i)
+
+swapBlockInv :: Vector Word8 -> ByteString
+swapBlockInv v = B.pack $ map (V.unsafeIndex v . swapIndex) [0..15]
+
+mSbox :: Word8 -> Word8
+mSbox = V.unsafeIndex sbox . fromIntegral
+
+mRsbox :: Word8 -> Word8
+mRsbox = V.unsafeIndex rsbox . fromIntegral
+
+mRcon :: Int -> Word8
+mRcon i = V.unsafeIndex rcon (i `mod` len)
+	where len = V.length rcon
+
+sbox :: Vector Word8
+sbox = V.fromList 
+	[ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5
+	, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76
+	, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0
+	, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0
+	, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc
+	, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15
+	, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a
+	, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75
+	, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0
+	, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84
+	, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b
+	, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf
+	, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85
+	, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8
+	, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5
+	, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2
+	, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17
+	, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73
+	, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88
+	, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb
+	, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c
+	, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79
+	, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9
+	, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08
+	, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6
+	, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a
+	, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e
+	, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e
+	, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94
+	, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf
+	, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68
+	, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
+	]
+
+rsbox :: Vector Word8
+rsbox = V.fromList
+	[ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38
+	, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb
+	, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87
+	, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb
+	, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d
+	, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e
+	, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2
+	, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25
+	, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16
+	, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92
+	, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda
+	, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84
+	, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a
+	, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06
+	, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02
+	, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b
+	, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea
+	, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73
+	, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85
+	, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e
+	, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89
+	, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b
+	, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20
+	, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4
+	, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31
+	, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f
+	, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d
+	, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef
+	, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0
+	, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61
+	, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26
+	, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
+	]
+
+rcon :: Vector Word8
+rcon = V.fromList
+	[ 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40
+	, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a
+	, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a
+	, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39
+	, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25
+	, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a
+	, 0x74, 0xe8, 0xcb
+	]
+
+gmtab2, gmtab3, gmtab9, gmtab11, gmtab13, gmtab14 :: Vector Word8
+gmtab2 = V.fromList
+	[ 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e
+	, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e
+	, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e
+	, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e
+	, 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e
+	, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e
+	, 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e
+	, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e
+	, 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e
+	, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e
+	, 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae
+	, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe
+	, 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce
+	, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde
+	, 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee
+	, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe
+	, 0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15
+	, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05
+	, 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35
+	, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25
+	, 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55
+	, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45
+	, 0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75
+	, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65
+	, 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95
+	, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85
+	, 0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5
+	, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5
+	, 0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5
+	, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5
+	, 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5
+	, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5
+	]
+
+gmtab3 = V.fromList
+	[ 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09
+	, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11
+	, 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39
+	, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21
+	, 0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69
+	, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71
+	, 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59
+	, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41
+	, 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9
+	, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1
+	, 0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9
+	, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1
+	, 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9
+	, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1
+	, 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99
+	, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81
+	, 0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92
+	, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a
+	, 0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2
+	, 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba
+	, 0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2
+	, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea
+	, 0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2
+	, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda
+	, 0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52
+	, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a
+	, 0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62
+	, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a
+	, 0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32
+	, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a
+	, 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02
+	, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a
+	]
+
+gmtab9 = V.fromList
+	[ 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f
+	, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77
+	, 0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf
+	, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7
+	, 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04
+	, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c
+	, 0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94
+	, 0xe3, 0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc
+	, 0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49
+	, 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01
+	, 0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9
+	, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91
+	, 0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72
+	, 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28, 0x33, 0x3a
+	, 0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2
+	, 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa
+	, 0xec, 0xe5, 0xfe, 0xf7, 0xc8, 0xc1, 0xda, 0xd3
+	, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b
+	, 0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43
+	, 0x34, 0x3d, 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b
+	, 0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8
+	, 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0
+	, 0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78
+	, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30
+	, 0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5
+	, 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed
+	, 0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35
+	, 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d
+	, 0xa1, 0xa8, 0xb3, 0xba, 0x85, 0x8c, 0x97, 0x9e
+	, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6
+	, 0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e
+	, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46
+	]
+
+gmtab11 = V.fromList
+	[ 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31
+	, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69
+	, 0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81
+	, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9
+	, 0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c, 0x41, 0x4a
+	, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12
+	, 0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa
+	, 0x93, 0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2
+	, 0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7
+	, 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f
+	, 0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77
+	, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f
+	, 0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc
+	, 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2, 0xef, 0xe4
+	, 0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c
+	, 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54
+	, 0xf7, 0xfc, 0xe1, 0xea, 0xdb, 0xd0, 0xcd, 0xc6
+	, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e
+	, 0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76
+	, 0x1f, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e
+	, 0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd
+	, 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5
+	, 0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d
+	, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55
+	, 0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30
+	, 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68
+	, 0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80
+	, 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8
+	, 0x7a, 0x71, 0x6c, 0x67, 0x56, 0x5d, 0x40, 0x4b
+	, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13
+	, 0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb
+	, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3
+	]
+
+gmtab13 = V.fromList
+	[ 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23
+	, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b
+	, 0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3
+	, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b
+	, 0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82, 0x95, 0x98
+	, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0
+	, 0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48
+	, 0x03, 0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20
+	, 0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e
+	, 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26
+	, 0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e
+	, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6
+	, 0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5
+	, 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87, 0x90, 0x9d
+	, 0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25
+	, 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d
+	, 0xda, 0xd7, 0xc0, 0xcd, 0xee, 0xe3, 0xf4, 0xf9
+	, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91
+	, 0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29
+	, 0x62, 0x6f, 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41
+	, 0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42
+	, 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a
+	, 0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92
+	, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa
+	, 0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94
+	, 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc
+	, 0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44
+	, 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c
+	, 0x0c, 0x01, 0x16, 0x1b, 0x38, 0x35, 0x22, 0x2f
+	, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47
+	, 0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff
+	, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97
+	]
+
+gmtab14 = V.fromList
+	[ 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a
+	, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a
+	, 0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca
+	, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba
+	, 0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed, 0xff, 0xf1
+	, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81
+	, 0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11
+	, 0x4b, 0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61
+	, 0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87
+	, 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7
+	, 0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67
+	, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17
+	, 0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c
+	, 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30, 0x22, 0x2c
+	, 0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc
+	, 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc
+	, 0x41, 0x4f, 0x5d, 0x53, 0x79, 0x77, 0x65, 0x6b
+	, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b
+	, 0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b
+	, 0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb
+	, 0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0
+	, 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0
+	, 0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50
+	, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20
+	, 0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6
+	, 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6
+	, 0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26
+	, 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56
+	, 0x37, 0x39, 0x2b, 0x25, 0x0f, 0x01, 0x13, 0x1d
+	, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d
+	, 0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd
+	, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d
+	]
diff --git a/Crypto/Cipher/RSA.hs b/Crypto/Cipher/RSA.hs
--- a/Crypto/Cipher/RSA.hs
+++ b/Crypto/Cipher/RSA.hs
@@ -11,11 +11,16 @@
 	( Error(..)
 	, PublicKey(..)
 	, PrivateKey(..)
+	, HashF
+	, HashASN1
 	, decrypt
 	, encrypt
+	, sign
+	, verify
 	) where
 
 import Control.Arrow (first)
+import Control.Monad.Error ()
 import Crypto.Random
 import Data.ByteString (ByteString)
 import qualified Data.ByteString as B
@@ -26,6 +31,7 @@
 	  MessageSizeIncorrect      -- ^ the message to decrypt is not of the correct size (need to be == private_size)
 	| MessageTooLong            -- ^ the message to encrypt is too long (>= private_size - 11)
 	| MessageNotRecognized      -- ^ the message decrypted doesn't have a PKCS15 structure (0 2 .. 0 msg)
+	| SignatureTooLong          -- ^ the signature generated through the hash is too long to process with this key
 	| RandomGenFailure GenError -- ^ the random generator returns an error. give the opportunity to reseed for example.
 	| KeyInternalError          -- ^ the whole key is probably not valid, since the message is bigger than the key size
 	deriving (Show,Eq)
@@ -47,12 +53,17 @@
 	, private_qinv :: Integer -- ^ q^(-1) mod p
 	} deriving (Show)
 
+type HashF = ByteString -> ByteString
+type HashASN1 = ByteString
+
+{-
 #if ! (MIN_VERSION_base(4,3,0))
 instance Monad (Either Error) where
 	return          = Right
 	(Left x) >>= _  = Left x
 	(Right x) >>= f = f x
 #endif
+-}
 
 padPKCS1 :: CryptoRandomGen g => g -> Int -> ByteString -> Either Error (ByteString, g)
 padPKCS1 rng len m = do
@@ -102,6 +113,28 @@
 		(em, rng') <- padPKCS1 rng (public_sz pk) m
 		c          <- i2ospOf (public_sz pk) $ expmod (os2ip em) (public_e pk) (public_n pk)
 		return (c, rng')
+
+{-| sign message using private key, a hash and its ASN1 description -}
+sign :: HashF -> HashASN1 -> PrivateKey -> ByteString -> Either Error ByteString
+sign hash hashdesc pk m = makeSignature hash hashdesc (private_sz pk) m >>= d pk
+	where d = if private_p pk /= 0 && private_q pk /= 0 then dpFast else dpSlow
+
+{-| verify message with the signed message -}
+verify :: HashF -> HashASN1 -> PublicKey -> ByteString -> ByteString -> Either Error Bool
+verify hash hashdesc pk m sm = do
+	s  <- makeSignature hash hashdesc (public_sz pk) m
+	em <- i2ospOf (public_sz pk) $ expmod (os2ip sm) (public_e pk) (public_n pk)
+	Right (s == em)
+
+{- makeSignature for sign and verify -}
+makeSignature :: HashF -> HashASN1 -> Int -> ByteString -> Either Error ByteString
+makeSignature hash descr klen m
+	| klen < siglen+1 = Left SignatureTooLong
+	| otherwise       = Right $ B.concat [B.singleton 0,B.singleton 1,padding,B.singleton 0,signature]
+	where
+		signature = descr `B.append` hash m
+		siglen    = B.length signature
+		padding   = B.replicate (klen - siglen - 3) 0xff
 
 {- get random non-null bytes for encryption padding. -}
 getRandomBytes :: CryptoRandomGen g => g -> Int -> Either Error (ByteString, g)
diff --git a/Tests.hs b/Tests.hs
--- a/Tests.hs
+++ b/Tests.hs
@@ -14,6 +14,7 @@
 import Data.Char
 import Data.Bits
 import Data.Word
+import qualified Data.Vector.Unboxed as V
 import qualified Data.ByteString as B
 import qualified Data.ByteString.Char8 as BC
 -- for DSA
@@ -22,6 +23,7 @@
 -- numbers
 import Number.ModArithmetic
 -- ciphers
+import qualified Crypto.Cipher.AES as AES
 import qualified Crypto.Cipher.RC4 as RC4
 import qualified Crypto.Cipher.Camellia as Camellia
 import qualified Crypto.Cipher.RSA as RSA
@@ -39,6 +41,61 @@
 wordify :: [Char] -> [Word8]
 wordify = map (toEnum . fromEnum)
 
+vectors_aes128 =
+	[
+	  ( [0x10, 0xa5, 0x88, 0x69, 0xd7, 0x4b, 0xe5, 0xa3,0x74,0xcf,0x86,0x7c,0xfb,0x47,0x38,0x59]
+	  , B.replicate 16 0
+	  , [0x6d,0x25,0x1e,0x69,0x44,0xb0,0x51,0xe0,0x4e,0xaa,0x6f,0xb4,0xdb,0xf7,0x84,0x65]
+	  )
+	, ( [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
+	  , B.pack [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
+	  , [0x66,0xe9,0x4b,0xd4,0xef,0x8a,0x2c,0x3b,0x88,0x4c,0xfa,0x59,0xca,0x34,0x2b,0x2e]
+	  )
+	, ( [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
+	  , B.pack [0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01]
+	  , [0xe1,0x4d,0x5d,0x0e,0xe2,0x77,0x15,0xdf,0x08,0xb4,0x15,0x2b,0xa2,0x3d,0xa8,0xe0]
+	  )
+	, ( [0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01]
+	  , B.pack [0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02]
+	  , [0x17,0xd6,0x14,0xf3,0x79,0xa9,0x35,0x90,0x77,0xe9,0x55,0x77,0xfd,0x31,0xc2,0x0a]
+	  )
+	, ( [0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02]
+	  , B.pack [0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01]
+	  , [0x8f,0x42,0xc2,0x4b,0xee,0x6e,0x63,0x47,0x2b,0x16,0x5a,0xa9,0x41,0x31,0x2f,0x7c]
+	  )
+	, ( [0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03]
+	  , B.pack [0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02]
+	  , [0x90,0x98,0x85,0xe4,0x77,0xbc,0x20,0xf5,0x8a,0x66,0x97,0x1d,0xa0,0xbc,0x75,0xe3]
+	  )
+	]
+
+vectors_aes192 =
+	[
+	  ( [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
+	  , B.pack [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
+	  , [0xaa,0xe0,0x69,0x92,0xac,0xbf,0x52,0xa3,0xe8,0xf4,0xa9,0x6e,0xc9,0x30,0x0b,0xd7]
+	  )
+	, ( [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
+	  , B.pack [0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01]
+	  , [0xcf,0x1e,0xce,0x3c,0x44,0xb0,0x78,0xfb,0x27,0xcb,0x0a,0x3e,0x07,0x1b,0x08,0x20]
+	  )
+	, ( [0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01]
+	  , B.pack [0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02]
+	  , [0xeb,0x8c,0x17,0x30,0x90,0xc7,0x5b,0x77,0xd6,0x72,0xb4,0x57,0xa7,0x78,0xd9,0xd0]
+	  )
+	, ( [0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02]
+	  , B.pack [0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01]
+	  , [0xf2,0xf0,0xae,0xd8,0xcd,0xc9,0x21,0xca,0x4b,0x55,0x84,0x5d,0xa4,0x15,0x21,0xc2]
+	  )
+	, ( [0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03]
+	  , B.pack [0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02]
+	  , [0xca,0xcc,0x30,0x79,0xe4,0xb7,0x95,0x27,0x63,0xd2,0x55,0xd6,0x34,0x10,0x46,0x14]
+	  )
+	]
+
+aes128InitKey = AES.initKey128 . B.pack
+aes192InitKey = AES.initKey192 . B.pack
+
 vectors_rc4 =
 	[ (wordify "Key", "Plaintext", [ 0xBB,0xF3,0x16,0xE8,0xD9,0x40,0xAF,0x0A,0xD3 ])
 	, (wordify "Wiki", "pedia", [ 0x10,0x21,0xBF,0x04,0x20 ])
@@ -76,6 +133,8 @@
 
 vectors =
 	[ ("RC4",      vectors_rc4,         encryptStream RC4.initCtx RC4.encrypt)
+	, ("AES128",   vectors_aes128,      encryptBlock aes128InitKey AES.encrypt)
+	, ("AES192",   vectors_aes192,      encryptBlock aes192InitKey AES.encrypt)
 	, ("Camellia", vectors_camellia128, encryptBlock Camellia.initKey Camellia.encrypt)
 	]
 
@@ -138,13 +197,23 @@
 {- testing RSA -}
 {-----------------------------------------------------------------------------------------------}
 
-prop_rsa_fast_valid (RSAMessage msg) =
-	(either Left (RSA.decrypt rsaPrivatekey . fst) $ RSA.encrypt rng rsaPublickey msg) == Right msg
-
-prop_rsa_slow_valid (RSAMessage msg) =
+prop_rsa_valid fast (RSAMessage msg) =
 	(either Left (RSA.decrypt pk . fst) $ RSA.encrypt rng rsaPublickey msg) == Right msg
-	where pk = rsaPrivatekey { RSA.private_p = 0, RSA.private_q = 0 }
+	where pk       = if fast then rsaPrivatekey else rsaPrivatekey { RSA.private_p = 0, RSA.private_q = 0 }
 
+prop_rsa_fast_valid  = prop_rsa_valid True
+prop_rsa_slow_valid  = prop_rsa_valid False
+
+prop_rsa_sign_valid fast (RSAMessage msg) = (either Left (\smsg -> verify msg smsg) $ sign msg) == Right True
+	where
+		verify   = RSA.verify (SHA1.hash) sha1desc rsaPublickey
+		sign     = RSA.sign (SHA1.hash) sha1desc pk
+		sha1desc = B.pack [0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03, 0x02,0x1a,0x05,0x00,0x04,0x14]
+		pk       = if fast then rsaPrivatekey else rsaPrivatekey { RSA.private_p = 0, RSA.private_q = 0 }
+
+prop_rsa_sign_fast_valid = prop_rsa_sign_valid True
+prop_rsa_sign_slow_valid = prop_rsa_sign_valid False
+
 rsaPrivatekey = RSA.PrivateKey
 	{ RSA.private_sz   = 128
 	, RSA.private_n    = 140203425894164333410594309212077886844966070748523642084363106504571537866632850620326769291612455847330220940078873180639537021888802572151020701352955762744921926221566899281852945861389488419179600933178716009889963150132778947506523961974222282461654256451508762805133855866018054403911588630700228345151
@@ -191,6 +260,23 @@
 		Right (signature, rng') = DSA.sign rng (SHA1.hash) dsaPrivatekey msg
 
 {-----------------------------------------------------------------------------------------------}
+{- testing AES -}
+{-----------------------------------------------------------------------------------------------}
+data AES128Message = AES128Message B.ByteString B.ByteString deriving (Show, Eq)
+
+instance Arbitrary AES128Message where
+	arbitrary = do
+		sz <- choose (1, 12)
+		ws <- replicateM (sz*16) (choose (0,255) :: Gen Int)
+		key <- replicateM 16 (choose (0,255) :: Gen Int)
+		return $ AES128Message (B.pack $ map fromIntegral key) (B.pack $ map fromIntegral ws)
+
+prop_aes128_valid (AES128Message key msg) =
+	let (Right k) = AES.initKey128 key in
+	let emsg = AES.encrypt k msg in
+	AES.decrypt k emsg == msg
+
+{-----------------------------------------------------------------------------------------------}
 {- main -}
 {-----------------------------------------------------------------------------------------------}
 
@@ -210,7 +296,12 @@
 	run_test "exponantiation RTL valid" prop_modexp_rtl_valid
 	run_test "inverse valid" prop_modinv_valid
 
+	run_test "RSA verify . sign(slow) = true" prop_rsa_sign_slow_valid
+	run_test "RSA verify . sign(fast) = true" prop_rsa_sign_fast_valid
+
 	run_test "RSA decrypt(slow).encrypt = id" prop_rsa_slow_valid
 	run_test "RSA decrypt(fast).encrypt = id" prop_rsa_fast_valid
 
-	run_test "DSA verify . sign = valid" prop_dsa_valid
+	run_test "DSA verify . sign = true" prop_dsa_valid
+
+	run_test "AES128 decrypt.encrypt = id" prop_aes128_valid
diff --git a/cryptocipher.cabal b/cryptocipher.cabal
--- a/cryptocipher.cabal
+++ b/cryptocipher.cabal
@@ -1,5 +1,5 @@
 Name:                cryptocipher
-Version:             0.2.2
+Version:             0.2.3
 Description:         Symmetrical Block, Stream and PubKey Ciphers
 License:             BSD3
 License-file:        LICENSE
@@ -17,8 +17,13 @@
   Default:           False
 
 Library
-  Build-Depends:     base >= 4 && < 7, bytestring, vector, crypto-api >= 0.2
+  Build-Depends:     base >= 4 && < 5
+                   , bytestring
+                   , vector
+                   , crypto-api >= 0.2
+                   , mtl
   Exposed-modules:   Crypto.Cipher.RC4
+                     Crypto.Cipher.AES
                      Crypto.Cipher.Camellia
                      Crypto.Cipher.RSA
                      Crypto.Cipher.DSA
@@ -31,7 +36,11 @@
   Main-Is:           Tests.hs
   if flag(test)
     Buildable:       True
-    Build-depends:   base >= 4 && < 7, HUnit, bytestring, cryptohash, QuickCheck >= 2
+    Build-depends:   base >= 4 && < 5
+                   , HUnit
+                   , bytestring
+                   , cryptohash
+                   , QuickCheck >= 2
   else
     Buildable:       False
 
