diff --git a/Benchmark/BinSearch.hs b/Benchmark/BinSearch.hs
new file mode 100644
--- /dev/null
+++ b/Benchmark/BinSearch.hs
@@ -0,0 +1,155 @@
+#!/usr/bin/env runhaskell
+
+
+-- ---------------------------------------------------------------------------
+--  Intel Concurrent Collections for Haskell
+--  Copyright (c) 2010, Intel Corporation.
+-- 
+--  This program is free software; you can redistribute it and/or modify it
+--  under the terms and conditions of the GNU Lesser General Public License,
+--  version 2.1, as published by the Free Software Foundation.
+-- 
+--  This program is distributed in the hope it will be useful, but WITHOUT
+--  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+--  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+--  more details.
+-- 
+--  You should have received a copy of the GNU Lesser General Public License along with
+--  this program; if not, write to the Free Software Foundation, Inc., 
+--  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+-- ---------------------------------------------------------------------------
+
+
+-- This is a script used for timing the throughput of benchmarks that
+-- take one argument and have linear complexity.
+
+
+module Benchmark.BinSearch 
+    (
+      binSearch
+    )
+where
+
+import Control.Monad
+import Data.Time.Clock -- Not in 6.10
+import Data.List
+import Data.IORef
+import System
+import System.IO
+import System.Cmd
+import System.Exit
+import Debug.Trace
+
+-- In seconds:
+--desired_exec_length = 3
+
+
+
+-- | Binary search for the number of inputs to a computation that
+-- | makes it take a specified time in seconds.
+--
+-- > binSearch verbose N (min,max) kernel
+--
+-- | binSearch will find the right input size that results in a time
+-- | between min and max, then it will then run for N trials and
+-- | return the median (input,time-in-seconds) pair.
+binSearch :: Bool -> Integer -> (Double,Double) -> (Integer -> IO ()) -> IO (Integer, Double)
+binSearch verbose trials (min,max) kernel =
+  do 
+     when(verbose)$ putStrLn$ "[binsearch] Binary search for input size resulting in time in range "++ show (min,max)
+
+     let desired_exec_length = 1.0
+	 good_trial t = (toRational t <= toRational max) && (toRational t >= toRational min)
+
+	 --loop :: Bool -> [String] -> Int -> Integer -> IO ()
+
+	 -- At some point we must give up...
+	 loop n | n > (2 ^ 100) = error "ERROR binSearch: This function doesn't seem to scale in proportion to its last argument."
+
+	 -- Not allowed to have "0" size input, bump it back to one:
+	 loop 0 = loop 1
+
+	 loop n = 
+	    do 
+	       when(verbose)$ putStr$ "[binsearch:"++ show n ++ "] "
+	       -- hFlush stdout
+
+	       time <- timeit$ kernel n
+
+	       when(verbose)$ putStrLn$ "Time consumed: "++ show time
+	       -- hFlush stdout
+	       let rate = fromIntegral n / time
+
+	       -- [2010.06.09] Introducing a small fudge factor to help our guess get over the line: 
+	       let initial_fudge_factor = 1.10
+		   fudge_factor = 1.01 -- Even in the steady state we fudge a little
+		   guess = desired_exec_length * rate 
+
+   -- TODO: We should keep more history here so that we don't re-explore input space we have already explored.
+   --       This is a balancing act because of randomness in execution time.
+
+	       if good_trial time
+		then do 
+			when(verbose)$ putStrLn$ "[binsearch] Time in range.  LOCKING input size and performing remaining trials."
+			print_trial 1 n time
+			lockin (trials-1) n [time]
+
+		-- Here we're still in the doubling phase:
+		else if time < 0.100 
+		then loop (2*n)
+
+		else do when(verbose)$ putStrLn$ "[binsearch] Estimated rate to be "++show (round$ rate)++" per second.  Trying to scale up..."
+
+			-- Here we've exited the doubling phase, but we're making our first guess as to how big a real execution should be:
+			if time > 0.100 && time < 0.33 * desired_exec_length
+			   then do when(verbose)$ putStrLn$  "[binsearch]   (Fudging first guess a little bit extra)"
+				   loop (round$ guess * initial_fudge_factor)
+			   else    loop (round$ guess * fudge_factor)
+
+ 	 -- Termination condition: Done with all trials.
+         lockin 0 n log = do when(verbose)$ putStrLn$ "[binsearch] Time-per-unit for all trials: "++ 
+				            (concat $ intersperse " " (map (show . (/ toDouble n) . toDouble) $ sort log))
+			     return (n, log !! ((length log) `quot` 2)) -- Take the median
+
+         lockin trials_left n log = 
+		     do when(verbose)$ putStrLn$ "[binsearch]------------------------------------------------------------"
+			time <- timeit$ kernel n
+			-- hFlush stdout
+			print_trial (trials - trials_left +1 ) n time
+			-- when(verbose)$ hFlush stdout
+			lockin (trials_left - 1) n (time : log)
+
+         print_trial trialnum n time = 
+	     let rate = fromIntegral n / time
+	         timeperunit = time / fromIntegral n
+	     in
+			when(verbose)$ putStrLn$ "[binsearch]  TRIAL: "++show trialnum ++
+				                 " secPerUnit: "++ showTime timeperunit ++ 
+						 " ratePerSec: "++ show (rate) ++ 
+						 " seconds: "++showTime time
+
+
+
+     (n,t) <- loop 1
+     return (n, fromRational$ toRational t)
+
+showTime t = show ((fromRational $ toRational t) :: Double)
+toDouble :: Real a => a -> Double
+toDouble = fromRational . toRational
+
+
+-- Could use cycle counters here.... but the point of this is to time
+-- things on the order of a second.
+timeit io = 
+    do strt <- getCurrentTime
+       io       
+       end  <- getCurrentTime
+       return (diffUTCTime end strt)
+
+test = 
+  binSearch True 3 (1.0, 1.05)
+   (\n -> 
+    do v <- newIORef 0
+       forM_ [1..n] $ \i -> do
+         old <- readIORef v
+         writeIORef v (old+i))
diff --git a/Codec/Crypto/ConvertRNG.hs b/Codec/Crypto/ConvertRNG.hs
new file mode 100644
--- /dev/null
+++ b/Codec/Crypto/ConvertRNG.hs
@@ -0,0 +1,182 @@
+{-|
+   Module      :  Codec.Crypto.ConvertRNG
+   Copyright   :  (c) Ryan Newton 2011
+   License     :  BSD-style (see the file LICENSE)
+   Maintainer  :  rrnewton@gmail.com
+   Stability   :  experimental
+   Portability :  portable, GHC
+
+ This module bridges these three interfaces:
+
+@
+   Crypto.Classes.BlockCipher
+   Crypto.Random.CryptoRandomGen
+   System.Random.RandomGen
+@
+
+    Specifically, a block cipher can be converted to generate a
+    @CryptoRandomGen@, which in turn can be converted to provide the
+    @RandomGen@ interface.
+
+  -}
+{-# OPTIONS_GHC -fwarn-unused-imports #-}
+{-# LANGUAGE  ScopedTypeVariables #-}
+-- FlexibleInstances, EmptyDataDecls, FlexibleContexts, NamedFieldPuns, , ForeignFunctionInterface
+
+module Codec.Crypto.ConvertRNG 
+  ( BCtoCRG(..), convertCRG     
+  , CRGtoRG()
+  , CRGtoRG0(..) -- Inefficient version for testing...
+  )
+where
+
+import System.Random 
+import System.IO.Unsafe (unsafePerformIO)
+import GHC.IO (unsafeDupablePerformIO)
+
+-- import Data.List
+import Data.Word
+import Data.Tagged
+import Data.Serialize
+
+import qualified Data.Bits
+import qualified Data.ByteString as B
+-- import qualified Data.ByteString.Char8 as BC
+import qualified Data.ByteString.Internal as BI
+
+-- import Crypto.Random.DRBG ()
+-- import Crypto.Modes
+
+import Crypto.Random (CryptoRandomGen(..), GenError(..), splitGen, genBytes)
+import Crypto.Classes (BlockCipher(..), blockSizeBytes)
+import Crypto.Types (ByteLength)
+
+import Control.Monad
+-- import Foreign.Ptr
+import qualified Foreign.ForeignPtr as FP
+import Foreign.Storable
+
+
+----------------------------------------------------------------------------------------------------
+-- Converting CryptoRandomGen to RandomGen
+------------------------------------------
+
+-- There's a potential overlapping instances problem here.  Someone
+-- may want to do their own RandomGen instance, creating a problem
+-- with this:
+--
+--   instance CryptoRandomGen g => RandomGen g where 
+--
+-- NOTE: The above would also be an undecidable instance.  Another
+-- option is to have a type used just for lifting.  See below.
+
+
+-- | Converting CryptoRandomGen to RandomGen.
+--   This naive version is probably pretty inefficent:
+data CRGtoRG0 a = CRGtoRG0 a
+instance CryptoRandomGen g => RandomGen (CRGtoRG0 g) where 
+   next  (CRGtoRG0 g) = 
+--       case genBytes (max bytes_in_int (keyLength g `quot` 8)) g of 
+       case genBytes bytes_in_int g of 
+         Left err -> error$ "CryptoRandomGen genBytes error: " ++ show err
+	 Right (bytes,g') -> 
+           case decode bytes of 
+	      Left err -> error$ "Deserialization error:"++ show err
+	      Right n -> (n, CRGtoRG0 g')
+	     
+   split (CRGtoRG0 g) = 
+       case splitGen g of 
+         Left err      -> error$ "CryptoRandomGen splitGen error:"++ show err
+	 Right (g1,g2) -> (CRGtoRG0 g1, CRGtoRG0 g2)
+
+-- Another option would be to amortize overhead by generating a large
+-- buffer of random bits at once.
+-- data CRGtoRG a = CRGtoRG a BUFFER INDEX
+
+-- Any better way to do this?
+bytes_in_int = (round $ 1 + logBase 2 (fromIntegral (maxBound :: Int)))  `quot` 8
+-- steps = 128 `quot` bits_in_int
+
+------------------------------------------------------------
+-- | Converting CryptoRandomGen to RandomGen.
+--   Keep a buffer of random bits and an index into that buffer.
+data CRGtoRG a = CRGtoRG a 
+    {-#UNPACK#-}!         (FP.ForeignPtr Int)
+    {-#UNPACK#-}!         Int
+
+instance CryptoRandomGen g => RandomGen (CRGtoRG g) where 
+   next (CRGtoRG g _ ind) | ind == bufsize = next (convertCRG g) -- Refill the buffer
+   next (CRGtoRG g buf ind) = 
+       -- As long as this memory is in use it will not be modified.
+       -- The peek action should therefore be dupable:
+       unsafeDupablePerformIO $ 
+         FP.withForeignPtr buf $ \ ptr -> 
+           do x <- peekElemOff ptr ind 
+	      return (x, CRGtoRG g buf (ind+1))
+	     
+   split (CRGtoRG g buf ind) = 
+       case splitGen g of 
+         Left err      -> error$ "CryptoRandomGen splitGen error:"++ show err
+	 Right (g1,g2) -> (CRGtoRG g1 buf ind, convertCRG g2)
+
+
+-- | The constructor for CRGtoRG values.
+convertCRG :: CryptoRandomGen g => g -> CRGtoRG g
+convertCRG crg = CRGtoRG g' (FP.castForeignPtr ptr) 0
+ where 
+  (ptr,_,_)     = BI.toForeignPtr bs
+  Right (bs,g') = genBytes (bufsize * bytes_in_int) crg
+
+
+-- How many 8 byte chunks should we buffer each time?
+-- TODO: Autotune this...
+bufsize = 256
+
+
+
+----------------------------------------------------------------------------------------------------
+-- We would also like every BlockCipher to constitute a valid CryptoRandomGen.
+-- Again there's the tension with UndecidableInstances vs explicit lifting.
+
+-- | A BlockCipher can generate random numbers.
+--   When lifting we include a counter which increments as random numbers are generated:
+data BCtoCRG a = BCtoCRG a Word64
+
+instance BlockCipher x => CryptoRandomGen (BCtoCRG x) where 
+  newGen  bytes = case buildKey bytes of Nothing -> Left NotEnoughEntropy 
+					 Just x  -> Right (BCtoCRG x 0)
+  genSeedLength = Tagged 128
+
+  -- If this is called for less than blockSize data there's some waste but it should work.
+  genBytes req (BCtoCRG (bcgen :: k) counter) = 
+      -- What's the most efficient way to do this?
+      unsafePerformIO $ do  -- Potentially heavyweight... not allowing dupable.
+--      unsafeDupablePerformIO $ do
+	-- Number of times to stamp out the counter:
+        let bsize = untag (blockSizeBytes :: Tagged k ByteLength)
+	    numstamps = (req + 7) `quot` 8
+	    numblocks = (req + bsize - 1) `quot` bsize
+	    total     = max (numstamps * 8) (numblocks * bsize)
+
+        -- putStrLn$ "[temp] requested "++show req++" bytes, stamping  "++show (numstamps*8)++
+	-- 	  " into "++show numblocks++" block(s), output buf size "++show total
+
+        buf :: FP.ForeignPtr Word64 <- FP.mallocForeignPtrBytes total
+	FP.withForeignPtr buf $ \ptr -> 
+	  forM_ [0..numstamps-1] $ \i -> 
+	    pokeElemOff ptr i (counter + fromIntegral i)
+        let cipher = encryptBlock bcgen (BI.fromForeignPtr (FP.castForeignPtr buf) 0 total)
+	    newgen = BCtoCRG bcgen (counter + fromIntegral numstamps)
+	-- At the end we may have requested more bytes than needed, so we might crop:
+	if req==total then return$ Right (cipher, newgen)
+	              else return$ Right (B.take req cipher, newgen)
+
+  reseed bs (BCtoCRG k _) = newGen (xorExtendBS (encode k) bs)
+
+xorExtendBS a b = B.append (B.pack$ B.zipWith Data.Bits.xor a b) rem
+      where
+      al = B.length a
+      bl = B.length b
+      rem | bl > al   = B.drop al b
+          | otherwise = B.drop bl a
+
diff --git a/Codec/Crypto/GladmanAES.hsc b/Codec/Crypto/GladmanAES.hsc
new file mode 100644
--- /dev/null
+++ b/Codec/Crypto/GladmanAES.hsc
@@ -0,0 +1,194 @@
+-- | ECB AES operation.  This code is based on the "AES" package from
+-- Svein Ove Aas (University of Tromsø), though it is heavily modified
+-- and any bugs should be blamed on me, Thomas M. DuBuisson.
+{-# LANGUAGE FlexibleInstances, EmptyDataDecls, FlexibleContexts, 
+    ForeignFunctionInterface, ViewPatterns,
+    ScopedTypeVariables
+    #-}
+{-# CFILES cbits/gladman/aescrypt.c cbits/gladman/aeskey.c cbits/gladman/aestab.c cbits/gladman/aes_modes.c #-}
+module Codec.Crypto.GladmanAES
+	( AES
+	, N128, N192, N256
+	, module Crypto.Classes
+	, module Crypto.Modes) where
+
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Internal as BI
+import Crypto.Modes
+import Crypto.Classes
+import Crypto.Types
+import Data.Tagged
+import Data.Serialize
+
+import Foreign
+import Control.Applicative
+import Control.Monad
+
+-- import Crypto.Random (CryptoRandomGen(newGen))
+-- The following line will cause a link problem currently [2011.02.02]:
+     -- Linking dist/build/benchmark-intel-aes-rng/benchmark-intel-aes-rng ...
+     -- /home/newton/Dropbox/working_copies/intel-aes/dist/build/libHSintel-aes-0.1.1.a(GladmanAES.o): In function `s3ho_info':
+     -- (.text+0x34c3): undefined reference to `__stginit_intelzmaeszm0zi1zi1_CodecziCryptoziConvertRNG_'
+     -- collect2: ld returned 1 exit status
+-- import qualified Codec.Crypto.ConvertRNG as CR
+
+#include "gladman/aesopt.h"
+#include "gladman/aes.h"
+#include "gladman/aestab.h"
+#include "gladman/brg_endian.h"
+#include "gladman/ctr_inc.h"
+
+data N128
+data N192
+data N256
+
+data AES n = AES
+		{ encCtx :: EncryptCtxP
+		, decCtx :: DecryptCtxP
+		, aesKeyRaw :: B.ByteString }
+
+
+-- Because of the above link problem I can't move these:
+{-
+mkAESGen :: Int -> CR.CRGtoRG (CR.BCtoCRG (AES N128))
+mkAESGen int = CR.convertCRG gen
+ where
+  Right (gen :: CR.BCtoCRG (AES N128)) = newGen (B.append halfseed halfseed )
+  halfseed = encode word64
+  word64 = fromIntegral int :: Word64
+
+mkAESGen0 :: Int -> CR.CRGtoRG0 (CR.BCtoCRG (AES N128))
+mkAESGen0 int = CR.CRGtoRG0 gen
+ where
+  Right (gen :: CR.BCtoCRG (AES N128)) = newGen (B.append halfseed halfseed )
+  halfseed = encode word64
+  word64 = fromIntegral int :: Word64
+ -}
+
+--------------------------------------------------------------------------------
+
+-- | Create an encryption/decryption context for incremental
+-- encryption/decryption
+--
+-- You may create an ECB context this way, in which case you may pass
+-- undefined for the IV
+newCtx :: B.ByteString -> IO (AES n)
+newCtx key = do
+	e <- (encryptCtx key)
+	d <- (decryptCtx key)
+	return $ AES e d key
+
+instance BlockCipher (AES N128) where
+	blockSize = Tagged 128
+	encryptBlock = aesEnc
+	decryptBlock = aesDec
+	buildKey = aesBK 128
+	keyLength = aesKL
+
+instance BlockCipher (AES N192) where
+	blockSize = Tagged 128
+	encryptBlock = aesEnc
+	decryptBlock = aesDec
+	buildKey = aesBK 192
+	keyLength = aesKL
+
+instance BlockCipher (AES N256) where
+	blockSize = Tagged 128
+	encryptBlock = aesEnc
+	decryptBlock = aesDec
+	buildKey = aesBK 256
+	keyLength = aesKL
+
+
+aesEnc :: AES n -> B.ByteString -> B.ByteString
+aesEnc k m = unsafePerformIO $ call _aes_ecb_encrypt (encCtx k) m
+
+aesDec :: AES n -> B.ByteString -> B.ByteString
+aesDec k m = unsafePerformIO $ call _aes_ecb_decrypt (decCtx k) m
+
+aesBK :: Int -> B.ByteString -> Maybe (AES n)
+aesBK n bs
+  | B.length bs == n `div` 8 = Just $ unsafePerformIO (newCtx bs)
+  | otherwise                = Nothing
+
+aesKL :: AES n -> BitLength
+aesKL = (*8) . B.length . aesKeyRaw
+
+instance Serialize (AES N128) where
+	get = getGeneral 16
+	put = putByteString . aesKeyRaw
+
+instance Serialize (AES N192) where
+	get = getGeneral 24
+	put = putByteString . aesKeyRaw
+
+instance Serialize (AES N256) where
+	get = getGeneral 32
+	put = putByteString . aesKeyRaw
+
+getGeneral :: BlockCipher (AES n) => Int -> Get (AES n)
+getGeneral n = do
+	bs <- getByteString n
+	case buildKey bs of
+		Nothing -> fail "Could not build key from serialized bytestring"
+		Just x  -> return x
+
+call :: (Ptr b -> Ptr Word8 -> Int -> Ptr a -> IO Int)
+       -> ForeignPtr a -> B.ByteString -> IO B.ByteString
+call f ctx (BI.toForeignPtr -> (bs,offset,len)) =
+  withForeignPtr ctx $ \ctxp ->
+  withForeignPtr bs $ \bsp ->
+  BI.create len $ \obuf ->
+  ensure $ f (bsp `plusPtr` offset) obuf len ctxp
+
+foreign import ccall unsafe "aes_ecb_encrypt" _aes_ecb_encrypt
+  :: Ptr Word8 -> Ptr Word8 -> Int -> Ptr EncryptCtxStruct -> IO Int
+foreign import ccall unsafe "aes_ecb_decrypt" _aes_ecb_decrypt
+  :: Ptr Word8 -> Ptr Word8 -> Int -> Ptr DecryptCtxStruct -> IO Int
+
+type EncryptCtxP = ForeignPtr EncryptCtxStruct
+
+type DecryptCtxP = ForeignPtr DecryptCtxStruct
+
+data EncryptCtxStruct
+instance Storable EncryptCtxStruct where
+  sizeOf _ = #size aes_encrypt_ctx
+  alignment _ = 16 -- FIXME: Maybe overkill, maybe underkill, definitely iffy
+
+data DecryptCtxStruct
+instance Storable DecryptCtxStruct where
+  sizeOf _ = #size aes_decrypt_ctx
+  alignment _ = 16
+
+wrap :: Int -> Bool
+wrap r | r == (#const EXIT_SUCCESS) = True
+       | otherwise = False
+
+ensure :: IO Int -> IO ()
+ensure act = do
+  r <- wrap <$> act
+  unless r (fail "AES function failed")
+
+foreign import ccall unsafe "aes_encrypt_key" _aes_encrypt_key 
+  :: Ptr Word8 -> Int -> Ptr EncryptCtxStruct -> IO Int
+
+encryptCtx :: B.ByteString -> IO EncryptCtxP
+encryptCtx bs = do
+  ctx <- mallocForeignPtr
+  let (key,offset,len) = BI.toForeignPtr bs
+  withForeignPtr ctx $ \ctx' ->
+    withForeignPtr key $ \key' ->
+    ensure $ _aes_encrypt_key (key' `plusPtr` offset) len ctx'
+  return ctx
+
+foreign import ccall unsafe "aes_decrypt_key" _aes_decrypt_key 
+  :: Ptr Word8 -> Int -> Ptr DecryptCtxStruct -> IO Int
+
+decryptCtx :: B.ByteString -> IO DecryptCtxP
+decryptCtx bs = do
+  ctx <- mallocForeignPtr
+  let (key,offset,len) = BI.toForeignPtr bs
+  withForeignPtr ctx $ \ctx' ->
+    withForeignPtr key $ \key' ->
+    ensure $ _aes_decrypt_key (key' `plusPtr` offset) len ctx'
+  return ctx
diff --git a/Codec/Crypto/IntelAES.hs b/Codec/Crypto/IntelAES.hs
new file mode 100644
--- /dev/null
+++ b/Codec/Crypto/IntelAES.hs
@@ -0,0 +1,125 @@
+{-|
+     Module      :  Codec.Crypto.IntelAES
+     Copyright   :  (c) Ryan Newton 2011
+     License     :  BSD-style (see the file LICENSE)
+     Maintainer  :  rrnewton@gmail.com
+     Stability   :  experimental
+     Portability :  linux only (NEEDS PORTING)
+
+     This module provides an AES implementation that will test the CPU
+     ID and use hardware acceleration where available, otherwise it will
+     fall back to Dr. Brian Gladman's software implementation.
+
+     This module also exports a random number generator based on AES
+     both using the System.Random.RandomGen interface and the
+     Codec.Crypto.Random.
+
+  -}
+{-# OPTIONS_GHC -fwarn-unused-imports #-}
+{-# LANGUAGE ForeignFunctionInterface, CPP, ScopedTypeVariables  #-}
+
+module Codec.Crypto.IntelAES
+    (
+      mkAESGen,
+      CompoundAESRNG(), 
+     -- Plus, instances exported of course.
+      testIntelAES
+    )
+where 
+
+import qualified Codec.Crypto.IntelAES.AESNI      as NI
+import qualified Codec.Crypto.GladmanAES as GA
+import GHC.IO (unsafeDupablePerformIO)
+import Data.Tagged
+import Data.Word
+import Data.Serialize
+import qualified Data.ByteString as B
+import Crypto.Random (CryptoRandomGen(..), GenError(..), splitGen, genBytes)
+import Crypto.Types
+import Codec.Crypto.ConvertRNG 
+import Debug.Trace
+
+newtype CompoundCRG = 
+  CompoundCRG 
+   (Either (BCtoCRG (NI.IntelAES NI.N128))
+	   (BCtoCRG (GA.AES GA.N128)))
+
+-- | A type representing an AES-based random number generator which
+--   will use AESNI instructions when available, and invoke the
+--   portable Gladman implementation when not.
+type CompoundAESRNG = CRGtoRG CompoundCRG
+
+-- | Simple function to create a random number generator from an Int,
+--   analogous to `System.Random.newStdGen`.  Only 128-bit encryption
+--   is provided for now.
+mkAESGen :: Int -> CompoundAESRNG
+mkAESGen int = convertCRG gen
+   where
+  Right (gen :: CompoundCRG) = newGen (B.append halfseed halfseed )
+  halfseed = encode word64
+  word64 = fromIntegral int :: Word64
+
+
+
+-- foreign import ccall unsafe "iaesni.h" check_for_aes_instructions :: IO Bool
+foreign import ccall unsafe "iaesni.h" check_for_aes_instructions :: Bool
+
+
+{-# INLINE mapRight #-}
+mapRight fn x@(Left _) = x
+mapRight fn (Right x)  = Right$ fn x
+
+{-# INLINE mapSnd #-}
+mapSnd fn (x,y) = (x,fn y)
+
+
+instance CryptoRandomGen CompoundCRG where 
+
+--  newGen :: B.ByteString -> Either GenError CompoundCRG
+  newGen = 
+--     if unsafeDupablePerformIO check_for_aes_instructions
+     trace ("Checked for AES instructions: "++ show check_for_aes_instructions)$
+     if check_for_aes_instructions
+     -- Ick, boilerplate:
+     then \bytes -> case newGen bytes of Left err  -> Left err
+					 Right gen -> Right$ CompoundCRG$ Left gen
+     else \bytes -> case newGen bytes of Left err  -> Left err
+					 Right gen -> Right$ CompoundCRG$ Right gen
+
+  genSeedLength = Tagged 128
+
+ 
+  -- ByteLength -> CompoundCRG -> Either GenError (B.ByteString, CompoundCRG)
+  genBytes req (CompoundCRG (Left gen)) = 
+-- Let's try to reduce that boilerplate if we can...
+#if 0
+    mapRight (mapSnd (CompoundCRG . Left) ) $ genBytes req gen
+#else
+    case genBytes req gen of 
+      Left  err  -> Left err
+      Right (bytes,gen') -> Right (bytes, CompoundCRG (Left gen'))
+#endif
+
+-- <boilerplate> OUCH
+  genBytes req (CompoundCRG (Right gen)) = 
+    case genBytes req gen of 
+      Left  err  -> Left err
+      Right (bytes,gen') -> Right (bytes, CompoundCRG (Right gen'))
+  reseed bs (CompoundCRG (Left gen)) = 
+    case reseed bs gen of 
+      Left  err  -> Left err
+      Right gen' -> Right (CompoundCRG (Left gen'))
+  reseed bs (CompoundCRG (Right gen)) = 
+    case reseed bs gen of 
+      Left  err  -> Left err
+      Right gen' -> Right (CompoundCRG (Right gen'))
+-- </boilerplate>
+
+
+
+testIntelAES = do 
+  putStrLn$ "Running crude tests."
+--  b <- check_for_aes_instructions
+  let b = check_for_aes_instructions
+  putStrLn$ "Machine supports AESNI: "++ show b
+
diff --git a/Codec/Crypto/IntelAES/AESNI.hs b/Codec/Crypto/IntelAES/AESNI.hs
new file mode 100644
--- /dev/null
+++ b/Codec/Crypto/IntelAES/AESNI.hs
@@ -0,0 +1,289 @@
+{- | 
+     Module      :  Codec.Crypto.IntelAES.AESNI
+     Copyright   :  (c) Ryan Newton 2011
+     License     :  BSD-style (see the file LICENSE)    
+     Maintainer  :  rrnewton@gmail.com
+     Stability   :  experimental
+     Portability :  linux only (NEEDS PORTING)
+
+
+     This module provides an AES implementation that /assumes/ AES-NI
+     instructions are available on the processor.  It will be
+     non-portable as a result.  Therefore, for most purposes
+     Codec.Crypto.IntelAES should be used instead.
+
+     Note: This module is simply a wrapper around the Intel-provided
+     AESNI sample library, found here:
+
+     <http://software.intel.com/en-us/articles/download-the-intel-aesni-sample-library/>
+
+ -}
+{-# OPTIONS_GHC -fwarn-unused-imports #-}
+{-# LANGUAGE FlexibleInstances, EmptyDataDecls, FlexibleContexts, NamedFieldPuns,
+     ScopedTypeVariables, ForeignFunctionInterface #-}
+
+module Codec.Crypto.IntelAES.AESNI
+    (
+      testAESNI
+    , mkAESGen, SimpleAESRNG
+    , mkAESGen192, mkAESGen256
+
+    -- Inefficient version for testing:
+    , mkAESGen0, SimpleAESRNG0
+    , IntelAES, N128, N192, N256
+     -- Plus, instances exported of course.
+    )
+where 
+
+import Codec.Crypto.ConvertRNG
+
+import System.Random 
+import System.IO.Unsafe (unsafePerformIO)
+-- import GHC.IO (unsafeDupablePerformIO)
+
+import Data.List
+import Data.Word
+import Data.Tagged
+import Data.Serialize
+
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Internal as BI
+
+import Crypto.Random.DRBG ()
+
+import Crypto.Random (CryptoRandomGen(..))
+import Crypto.Classes (BlockCipher(..))
+
+import Control.Monad
+import Foreign.Ptr
+import qualified Foreign.ForeignPtr as FP
+import Foreign.Storable
+
+----------------------------------------------------------------------------------------------------
+
+-- | The type of a simple 'System.Random.RandomGen' instance.
+type SimpleAESRNG = CRGtoRG (BCtoCRG (IntelAES N128))
+
+-- | Expose a simple System.Random.RandomGen interface using 128 bit encryption.  
+mkAESGen :: Int -> SimpleAESRNG
+mkAESGen int = convertCRG gen
+ where
+  Right (gen :: BCtoCRG (IntelAES N128)) = newGen (B.append halfseed halfseed )
+  halfseed = encode word64
+  word64 = fromIntegral int :: Word64
+
+-- | Same thing for 192 bit encryption.
+mkAESGen192 :: B.ByteString -> CRGtoRG (BCtoCRG (IntelAES N192))
+mkAESGen192 seed = convertCRG gen
+ where
+  Right (gen :: BCtoCRG (IntelAES N192)) = newGen (B.take 24 seed)
+
+-- | Ditto for 256 bit encryption.
+mkAESGen256 :: B.ByteString -> CRGtoRG (BCtoCRG (IntelAES N256))
+mkAESGen256 seed = convertCRG gen
+ where
+  Right (gen :: BCtoCRG (IntelAES N256)) = newGen (B.take 24 seed)
+
+
+
+-- | TEMP: Inefficient version for testing.
+type SimpleAESRNG0 = CRGtoRG0 (BCtoCRG (IntelAES N128))
+mkAESGen0 :: Int -> SimpleAESRNG0
+mkAESGen0 int = CRGtoRG0 gen
+ where
+  Right (gen :: BCtoCRG (IntelAES N128)) = newGen (B.append halfseed halfseed )
+  halfseed = encode word64
+  word64 = fromIntegral int :: Word64
+
+
+----------------------------------------------------------------------------------------------------
+
+type PlainText   = Ptr Word8
+type CipherText  = Ptr Word8
+type Key         = Ptr Word8
+type NullResult = IO ()
+
+foreign import ccall unsafe "iaesni.h" intel_AES_enc128     :: PlainText -> CipherText -> Key -> Int -> NullResult
+foreign import ccall unsafe "iaesni.h" intel_AES_enc128_CBC :: PlainText -> CipherText -> Key -> Int -> Ptr Word8 -> NullResult
+-- Copy/paste:
+foreign import ccall unsafe "iaesni.h" intel_AES_enc192     :: PlainText -> CipherText -> Key -> Int -> NullResult
+foreign import ccall unsafe "iaesni.h" intel_AES_enc192_CBC :: PlainText -> CipherText -> Key -> Int -> Ptr Word8 -> NullResult
+foreign import ccall unsafe "iaesni.h" intel_AES_enc256     :: PlainText -> CipherText -> Key -> Int -> NullResult
+foreign import ccall unsafe "iaesni.h" intel_AES_enc256_CBC :: PlainText -> CipherText -> Key -> Int -> Ptr Word8 -> NullResult
+foreign import ccall unsafe "iaesni.h" intel_AES_dec128     :: CipherText -> PlainText -> Key -> Int -> NullResult
+foreign import ccall unsafe "iaesni.h" intel_AES_dec128_CBC :: CipherText -> PlainText -> Key -> Int -> Ptr Word8 -> NullResult
+foreign import ccall unsafe "iaesni.h" intel_AES_dec192     :: CipherText -> PlainText -> Key -> Int -> NullResult
+foreign import ccall unsafe "iaesni.h" intel_AES_dec192_CBC :: CipherText -> PlainText -> Key -> Int -> Ptr Word8 -> NullResult
+foreign import ccall unsafe "iaesni.h" intel_AES_dec256     :: CipherText -> PlainText -> Key -> Int -> NullResult
+foreign import ccall unsafe "iaesni.h" intel_AES_dec256_CBC :: CipherText -> PlainText -> Key -> Int -> Ptr Word8 -> NullResult
+
+foreign import ccall unsafe "iaesni.h" intel_AES_encdec128_CTR :: Ptr Word8 -> Ptr Word8 -> Key -> Int -> Ptr Word8 -> NullResult
+foreign import ccall unsafe "iaesni.h" intel_AES_encdec192_CTR :: Ptr Word8 -> Ptr Word8 -> Key -> Int -> Ptr Word8 -> NullResult
+foreign import ccall unsafe "iaesni.h" intel_AES_encdec256_CTR :: Ptr Word8 -> Ptr Word8 -> Key -> Int -> Ptr Word8 -> NullResult
+
+
+foreign import ccall unsafe "stdlib.h" malloc :: Int -> IO (Ptr Word8)
+foreign import ccall unsafe "stdlib.h" calloc :: Int -> Int -> IO (Ptr Word8)
+
+-- foreign import ccall unsafe "c_test.c" temp_test128 :: IO ()
+
+----------------------------------------------------------------------------------------------------
+
+-- Haskell datatypes to model the different AES modes:
+data N128
+data N192
+data N256
+
+data IntelAES n = IntelAES { aesKeyRaw :: B.ByteString }
+
+{-# INLINE unpackKey #-}
+unpackKey (IntelAES {aesKeyRaw}) = kptr
+  -- TODO: ASSERT that key is the right length and offset is zero...
+  where 
+  (kptr,koff,klen) = BI.toForeignPtr aesKeyRaw
+
+{-# INLINE template #-}
+template core keysize ctx@(IntelAES {aesKeyRaw}) plaintext = 
+--	 unsafeDupablePerformIO $
+	 unsafePerformIO $
+	 do let kfptr                   = unpackKey ctx 
+		(in_fptr,in_off,in_len) = BI.toForeignPtr plaintext
+		(blocks,r) = quotRem in_len keysize
+	    -- The buffer should be a multiple of the key size (128/192,256 bits):
+	    when (r > 0)$ 
+	       error$ "encryptBlock: block size "++show in_len++
+		      " bytes , but with AES implementation block size must be a multiple of "++show keysize
+
+	    output <- FP.mallocForeignPtrBytes in_len 
+	    FP.withForeignPtr kfptr $ \ keyptr -> 
+	      FP.withForeignPtr in_fptr $ \ inptr -> 
+		FP.withForeignPtr output  $ \ outptr -> 
+		  core inptr outptr keyptr blocks
+
+	    return (BI.fromForeignPtr output 0 in_len)
+
+instance BlockCipher (IntelAES N128) where
+	blockSize    = Tagged 128
+	encryptBlock = template intel_AES_enc128 16
+	decryptBlock = template intel_AES_dec128 16
+        -- What's the right behavior here?  Currently this refuses to
+        -- generate keys if given an insufficient # of bytes.
+	buildKey bytes | B.length bytes >= 16 = Just$ newCtx bytes
+        buildKey _     | otherwise            = Nothing
+	keyLength (IntelAES {aesKeyRaw}) = B.length aesKeyRaw * 8 -- bits
+
+instance Serialize (IntelAES N128) where
+	get = getGeneral 16
+	put = putByteString . aesKeyRaw
+
+-- <boilerplate>
+instance BlockCipher (IntelAES N192) where
+	blockSize    = Tagged 192
+	encryptBlock = template intel_AES_enc192 24
+	decryptBlock = template intel_AES_dec192 24
+	buildKey bytes | B.length bytes >= 24 = Just$ newCtx bytes
+        buildKey _     | otherwise            = Nothing
+	keyLength (IntelAES {aesKeyRaw}) = B.length aesKeyRaw
+instance Serialize (IntelAES N192) where
+	get = getGeneral 24
+	put = putByteString . aesKeyRaw
+instance BlockCipher (IntelAES N256) where
+	blockSize    = Tagged 192
+	encryptBlock = template intel_AES_enc256 32
+	decryptBlock = template intel_AES_dec256 32
+	buildKey bytes | B.length bytes >= 32 = Just$ newCtx bytes
+        buildKey _     | otherwise            = Nothing
+	keyLength (IntelAES {aesKeyRaw}) = B.length aesKeyRaw
+instance Serialize (IntelAES N256) where
+	get = getGeneral 32
+	put = putByteString . aesKeyRaw
+-- </boilerplate>
+
+
+getGeneral :: BlockCipher (IntelAES n) => Int -> Get (IntelAES n)
+getGeneral n = do
+	bs <- getByteString n
+	case buildKey bs of
+		Nothing -> fail "Could not build key from serialized bytestring"
+		Just x  -> return x
+
+newCtx :: B.ByteString -> IntelAES n
+newCtx key = IntelAES key
+
+----------------------------------------------------------------------------------------------------
+-- Testing
+  ------------------------------------------------------------
+
+unpack_ptr :: Storable a => Ptr a -> Int -> IO [a]
+unpack_ptr ptr len = loop len []
+  where 
+  loop 0 acc = return acc
+  loop i acc = do x    <- peekElemOff ptr (i-1)
+		  loop (i-1) (x:acc)
+
+
+-- | This is not a meaningful test yet... one option would be to
+--   reproduce the tests in aessample.c
+testAESNI :: IO ()
+testAESNI = do 
+  let bytes = 256
+  plaintext  <- calloc bytes 1
+  key        <- calloc 16 1
+  ciphertext <- calloc bytes 1
+
+  forM [0..bytes-1] $ \i -> do 
+    pokeElemOff plaintext i (fromIntegral i)
+
+  forM [0..15] $ \i -> do 
+    pokeElemOff key i (fromIntegral i)
+
+  putStrLn$ "Plaintext:" 
+  ls <- unpack_ptr plaintext bytes
+  print ls
+
+  putStrLn$ "Key:" 
+  ls <- unpack_ptr key 16
+  print ls
+
+  putStrLn$ "Cipher text:" 
+  ls <- unpack_ptr ciphertext bytes
+  print ls
+
+  putStrLn$ "\nCalling foreign AES encode routine: byte"
+  -- Divide byte length by 128 bits (16 bytes):
+  intel_AES_enc256 plaintext ciphertext key (bytes `quot` 16)
+  putStrLn$ "Done with foreign call"
+
+  putStrLn$ "Cipher text:" 
+  ls <- unpack_ptr ciphertext bytes
+  print ls
+
+  putStrLn$ "================================================================================" 
+  putStrLn$ "\nNow let's try it as a block cypher... encrypt increasing bytes:"
+  let inp = B.pack $ take bytes [0..]
+      ctxt :: IntelAES N128 = newCtx (B.take 16 inp) 
+      cipher = encryptBlock ctxt inp
+
+      backagain = decryptBlock ctxt cipher
+
+  putStrLn$ "\nCiphertext: "++ show (B.unpack cipher)
+  putStrLn$ "\nAnd back again: "++ show (B.unpack backagain)
+
+  when (not$ backagain == inp) $
+    error "Test failed! Round-trip did not get us back to the plaintext!"
+
+  putStrLn$ "================================================================================" 
+  putStrLn$ "\nFinally lets use it to generate some random numbers:"
+  let 
+      gen2 = mkAESGen 92438653296
+      fn (0,_) = Nothing
+      fn (i,g) = let (n,g') = next g in Just (n, (i-1,g'))
+      nums = unfoldr fn (20,gen2)
+  putStrLn$ "Randoms: " ++ show nums
+
+  ------------------------------------------------------------
+  putStrLn$ "Done."
+  -- putStrLn$ "Next calling test routine in C:"
+  -- temp_test128 
+  -- putStrLn$ "Done with that test routine"
+  
diff --git a/Codec/Encryption/AES.hs b/Codec/Encryption/AES.hs
new file mode 100644
--- /dev/null
+++ b/Codec/Encryption/AES.hs
@@ -0,0 +1,64 @@
+{-# LANGUAGE TypeSynonymInstances #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Codec.Encryption.AES
+-- Copyright   :  (c) Dominic Steinitz 2004
+-- License     :  BSD-style (see the file ReadMe.tex)
+-- 
+-- Maintainer  :  dominic.steinitz@blueyonder.co.uk
+-- Stability   :  experimental
+-- Portability :  portable
+--
+-- Pure Haskell AES implementation.
+-- 
+-- Takes the AES module supplied by Lukasz Anforowicz and wraps it so it can
+-- used with the standard modes.
+--
+-----------------------------------------------------------------------------
+
+module Codec.Encryption.AES (
+   -- * Function Types 
+   encrypt, decrypt, AESKey) where
+
+import Codec.Encryption.AESAux
+import Data.LargeWord
+import Codec.Utils
+import Data.Word
+import Data.Bits
+
+class (Bits a, Integral a) => AESKeyIndirection a
+class AESKeyIndirection a => AESKey a
+
+instance AESKeyIndirection Word128
+instance AESKeyIndirection Word192
+instance AESKeyIndirection Word256
+
+instance AESKey Word128
+instance AESKey Word192
+instance AESKey Word256
+
+-- | Basic AES encryption which takes a key and a block of plaintext 
+-- and returns the encrypted block of ciphertext according to the standard.
+
+encrypt :: AESKey a => a -> Word128 -> Word128
+encrypt k p = 
+   case bitSize k of
+      128 -> f aes128Encrypt k p
+      192 -> f aes192Encrypt k p
+      256 -> f aes256Encrypt k p
+
+f g k p = 
+   fromIntegral $ fromOctets 256 $ 
+      g (i2osp (bitSize k `div` bitSize (0::Octet)) $ fromIntegral k) 
+        (i2osp (bitSize p `div` bitSize (0::Octet)) $ fromIntegral p)
+
+-- | Basic AES decryption which takes a key and a block of ciphertext and
+-- returns the decrypted block of plaintext according to the standard.
+
+decrypt :: AESKey a => a -> Word128 -> Word128
+decrypt k p = 
+   case bitSize k of
+      128 -> f aes128Decrypt k p
+      192 -> f aes192Decrypt k p
+      256 -> f aes256Decrypt k p
+
diff --git a/Codec/Encryption/AESAux.hs b/Codec/Encryption/AESAux.hs
new file mode 100644
--- /dev/null
+++ b/Codec/Encryption/AESAux.hs
@@ -0,0 +1,1008 @@
+-- | Advanced Encryption System (specification can be found in FIPS-197)
+module Codec.Encryption.AESAux(
+	aes128Encrypt,
+	aes192Encrypt,
+	aes256Encrypt,
+	aes128Decrypt,
+	aes192Decrypt,
+	aes256Decrypt,
+) where
+
+import Data.Bits
+import Data.Int(Int)
+import Data.Word(Word32)
+
+import Codec.Utils(Octet)
+
+aes128Encrypt :: [Octet] -- ^ key (16 octets)
+	      -> [Octet] -- ^ msg (16 octets)
+	      -> [Octet] -- ^ enciphered msg (16 octets)
+aes128Encrypt = aesEncrypt 10 4
+
+aes192Encrypt :: [Octet] -- ^ key (24 octets)
+	      -> [Octet] -- ^ msg (16 octets)
+	      -> [Octet] -- ^ enciphered msg (16 octets)
+aes192Encrypt = aesEncrypt 12 6
+
+aes256Encrypt :: [Octet] -- ^ key (32 octets)
+	      -> [Octet] -- ^ msg (16 octets)
+	      -> [Octet] -- ^ enciphered msg (16 octets)
+aes256Encrypt = aesEncrypt 14 8
+
+aes128Decrypt :: [Octet] -- ^ key (16 octets)
+	      -> [Octet] -- ^ enciphered msg (16 octets)
+	      -> [Octet] -- ^ deciphered msg (16 octets)
+aes128Decrypt = aesDecrypt 10 4
+
+aes192Decrypt :: [Octet] -- ^ key (24 octets)
+	      -> [Octet] -- ^ enciphered msg (16 octets)
+	      -> [Octet] -- ^ deciphered msg (16 octets)
+aes192Decrypt = aesDecrypt 12 6
+
+aes256Decrypt :: [Octet] -- ^ key (32 octets)
+	      -> [Octet] -- ^ enciphered msg (16 octets)
+	      -> [Octet] -- ^ deciphered msg (16 octets)
+aes256Decrypt = aesDecrypt 14 8
+
+aesEncrypt :: Int     -- ^ nr 
+	   -> Int     -- ^ nk
+	   -> [Octet] -- ^ key
+	   -> [Octet] -- ^ msg
+	   -> [Octet] -- ^ enciphered msg
+aesEncrypt nr nk key 
+		[i00, i10, i20, i30,
+		 i01, i11, i21, i31,
+		 i02, i12, i22, i32,
+		 i03, i13, i23, i33] =
+		[fo o00, fo o10, fo o20, fo o30,
+		 fo o01, fo o11, fo o21, fo o31,
+		 fo o02, fo o12, fo o22, fo o32,
+		 fo o03, fo o13, fo o23, fo o33]
+	where State (o00, o01, o02, o03)	 
+		    (o10, o11, o12, o13)	 
+		    (o20, o21, o22, o23)	 
+		    (o30, o31, o32, o33) = transform (
+		    	State(fi i00, fi i01, fi i02, fi i03)
+		    	     (fi i10, fi i11, fi i12, fi i13)
+		    	     (fi i20, fi i21, fi i22, fi i23)
+		    	     (fi i30, fi i31, fi i32, fi i33))
+	      fi = (fromIntegral :: Octet -> Word32)		     
+	      fo = (fromIntegral :: Word32 -> Octet)		     
+	      (kt0:kts) = genAddRoundKey (generateKeys nr nk key)
+	      transform = foldr (.) kt0 (reverse rest)
+	      mss = replicate (nr - 1) (mixColumns . shiftRows . subBytes)
+	      rest = zipWith (.) kts (mss ++ [shiftRows . subBytes ])
+	      
+
+aesDecrypt :: Int     -- ^ nr 
+	   -> Int     -- ^ nk
+	   -> [Octet] -- ^ key
+	   -> [Octet] -- ^ enciphered msg
+	   -> [Octet] -- ^ deciphered msg
+aesDecrypt nr nk key 
+		[i00, i10, i20, i30,
+		 i01, i11, i21, i31,
+		 i02, i12, i22, i32,
+		 i03, i13, i23, i33] =
+		[fo o00, fo o10, fo o20, fo o30,
+		 fo o01, fo o11, fo o21, fo o31,
+		 fo o02, fo o12, fo o22, fo o32,
+		 fo o03, fo o13, fo o23, fo o33]
+	where State (o00, o01, o02, o03)	 
+		    (o10, o11, o12, o13)	 
+		    (o20, o21, o22, o23)	 
+		    (o30, o31, o32, o33) = transform (
+		    	State(fi i00, fi i01, fi i02, fi i03)
+		    	     (fi i10, fi i11, fi i12, fi i13)
+		    	     (fi i20, fi i21, fi i22, fi i23)
+		    	     (fi i30, fi i31, fi i32, fi i33))
+	      fi = (fromIntegral :: Octet -> Word32)		     
+	      fo = (fromIntegral :: Word32 -> Octet)		     
+	      (kt0:kts) = reverse (genAddRoundKey (generateKeys nr nk key))
+	      transform = foldr (.) kt0 (reverse rest)
+	      ssm = replicate (nr - 1) 
+	      			(subBytesRev . shiftRowsRev . mixColumnsRev)
+	      rest = zipWith (.) kts ([subBytesRev . shiftRowsRev] ++ ssm)
+	      
+
+
+data State =  State !(Word32, Word32, Word32, Word32)
+		    !(Word32, Word32, Word32, Word32)
+		    !(Word32, Word32, Word32, Word32)
+		    !(Word32, Word32, Word32, Word32)
+
+sbox :: Word32 -> Word32
+sboxRev :: Word32 -> Word32
+
+sbox 0x00 = 0x63
+sbox 0x01 = 0x7C
+sbox 0x02 = 0x77
+sbox 0x03 = 0x7B
+sbox 0x04 = 0xF2
+sbox 0x05 = 0x6B
+sbox 0x06 = 0x6F
+sbox 0x07 = 0xC5
+
+sbox 0x08 = 0x30
+sbox 0x09 = 0x01
+sbox 0x0a = 0x67
+sbox 0x0b = 0x2B
+sbox 0x0c = 0xFE
+sbox 0x0d = 0xD7
+sbox 0x0e = 0xAB
+sbox 0x0f = 0x76
+
+sbox 0x10 = 0xCA
+sbox 0x11 = 0x82
+sbox 0x12 = 0xC9
+sbox 0x13 = 0x7D
+sbox 0x14 = 0xFA
+sbox 0x15 = 0x59
+sbox 0x16 = 0x47
+sbox 0x17 = 0xF0
+
+sbox 0x18 = 0xAD
+sbox 0x19 = 0xD4
+sbox 0x1a = 0xA2
+sbox 0x1b = 0xAF
+sbox 0x1c = 0x9C
+sbox 0x1d = 0xA4
+sbox 0x1e = 0x72
+sbox 0x1f = 0xC0
+
+sbox 0x20 = 0xB7
+sbox 0x21 = 0xFD
+sbox 0x22 = 0x93
+sbox 0x23 = 0x26
+sbox 0x24 = 0x36
+sbox 0x25 = 0x3F
+sbox 0x26 = 0xF7
+sbox 0x27 = 0xCC
+
+sbox 0x28 = 0x34
+sbox 0x29 = 0xA5
+sbox 0x2a = 0xE5
+sbox 0x2b = 0xF1
+sbox 0x2c = 0x71
+sbox 0x2d = 0xD8
+sbox 0x2e = 0x31
+sbox 0x2f = 0x15
+
+sbox 0x30 = 0x04
+sbox 0x31 = 0xC7
+sbox 0x32 = 0x23
+sbox 0x33 = 0xC3
+sbox 0x34 = 0x18
+sbox 0x35 = 0x96
+sbox 0x36 = 0x05
+sbox 0x37 = 0x9A
+
+sbox 0x38 = 0x07
+sbox 0x39 = 0x12
+sbox 0x3a = 0x80
+sbox 0x3b = 0xE2
+sbox 0x3c = 0xEB
+sbox 0x3d = 0x27
+sbox 0x3e = 0xB2
+sbox 0x3f = 0x75
+
+sbox 0x40 = 0x09
+sbox 0x41 = 0x83
+sbox 0x42 = 0x2C
+sbox 0x43 = 0x1A
+sbox 0x44 = 0x1B
+sbox 0x45 = 0x6E
+sbox 0x46 = 0x5A
+sbox 0x47 = 0xA0
+
+sbox 0x48 = 0x52
+sbox 0x49 = 0x3B
+sbox 0x4a = 0xD6
+sbox 0x4b = 0xB3
+sbox 0x4c = 0x29
+sbox 0x4d = 0xE3
+sbox 0x4e = 0x2F
+sbox 0x4f = 0x84
+
+sbox 0x50 = 0x53
+sbox 0x51 = 0xD1
+sbox 0x52 = 0x00
+sbox 0x53 = 0xED
+sbox 0x54 = 0x20
+sbox 0x55 = 0xFC
+sbox 0x56 = 0xB1
+sbox 0x57 = 0x5B
+
+sbox 0x58 = 0x6A
+sbox 0x59 = 0xCB
+sbox 0x5a = 0xBE
+sbox 0x5b = 0x39
+sbox 0x5c = 0x4A
+sbox 0x5d = 0x4C
+sbox 0x5e = 0x58
+sbox 0x5f = 0xCF
+
+sbox 0x60 = 0xD0
+sbox 0x61 = 0xEF
+sbox 0x62 = 0xAA
+sbox 0x63 = 0xFB
+sbox 0x64 = 0x43
+sbox 0x65 = 0x4D
+sbox 0x66 = 0x33
+sbox 0x67 = 0x85
+
+sbox 0x68 = 0x45
+sbox 0x69 = 0xF9
+sbox 0x6a = 0x02
+sbox 0x6b = 0x7F
+sbox 0x6c = 0x50
+sbox 0x6d = 0x3C
+sbox 0x6e = 0x9F
+sbox 0x6f = 0xA8
+
+sbox 0x70 = 0x51
+sbox 0x71 = 0xA3
+sbox 0x72 = 0x40
+sbox 0x73 = 0x8F
+sbox 0x74 = 0x92
+sbox 0x75 = 0x9D
+sbox 0x76 = 0x38
+sbox 0x77 = 0xF5
+
+sbox 0x78 = 0xBC
+sbox 0x79 = 0xB6
+sbox 0x7a = 0xDA
+sbox 0x7b = 0x21
+sbox 0x7c = 0x10
+sbox 0x7d = 0xFF
+sbox 0x7e = 0xF3
+sbox 0x7f = 0xD2
+
+sbox 0x80 = 0xCD
+sbox 0x81 = 0x0C
+sbox 0x82 = 0x13
+sbox 0x83 = 0xEC
+sbox 0x84 = 0x5F
+sbox 0x85 = 0x97
+sbox 0x86 = 0x44
+sbox 0x87 = 0x17
+
+sbox 0x88 = 0xC4
+sbox 0x89 = 0xA7
+sbox 0x8a = 0x7E
+sbox 0x8b = 0x3D
+sbox 0x8c = 0x64
+sbox 0x8d = 0x5D
+sbox 0x8e = 0x19
+sbox 0x8f = 0x73
+
+sbox 0x90 = 0x60
+sbox 0x91 = 0x81
+sbox 0x92 = 0x4F
+sbox 0x93 = 0xDC
+sbox 0x94 = 0x22
+sbox 0x95 = 0x2A
+sbox 0x96 = 0x90
+sbox 0x97 = 0x88
+
+sbox 0x98 = 0x46
+sbox 0x99 = 0xEE
+sbox 0x9a = 0xB8
+sbox 0x9b = 0x14
+sbox 0x9c = 0xDE
+sbox 0x9d = 0x5E
+sbox 0x9e = 0x0B
+sbox 0x9f = 0xDB
+
+sbox 0xa0 = 0xE0
+sbox 0xa1 = 0x32
+sbox 0xa2 = 0x3A
+sbox 0xa3 = 0x0A
+sbox 0xa4 = 0x49
+sbox 0xa5 = 0x06
+sbox 0xa6 = 0x24
+sbox 0xa7 = 0x5C
+
+sbox 0xa8 = 0xC2
+sbox 0xa9 = 0xD3
+sbox 0xaa = 0xAC
+sbox 0xab = 0x62
+sbox 0xac = 0x91
+sbox 0xad = 0x95
+sbox 0xae = 0xE4
+sbox 0xaf = 0x79
+
+sbox 0xb0 = 0xE7
+sbox 0xb1 = 0xC8
+sbox 0xb2 = 0x37
+sbox 0xb3 = 0x6D
+sbox 0xb4 = 0x8D
+sbox 0xb5 = 0xD5
+sbox 0xb6 = 0x4E
+sbox 0xb7 = 0xA9
+
+sbox 0xb8 = 0x6C
+sbox 0xb9 = 0x56
+sbox 0xba = 0xF4
+sbox 0xbb = 0xEA
+sbox 0xbc = 0x65
+sbox 0xbd = 0x7A
+sbox 0xbe = 0xAE
+sbox 0xbf = 0x08
+
+sbox 0xc0 = 0xBA
+sbox 0xc1 = 0x78
+sbox 0xc2 = 0x25
+sbox 0xc3 = 0x2E
+sbox 0xc4 = 0x1C
+sbox 0xc5 = 0xA6
+sbox 0xc6 = 0xB4
+sbox 0xc7 = 0xC6
+
+sbox 0xc8 = 0xE8
+sbox 0xc9 = 0xDD
+sbox 0xca = 0x74
+sbox 0xcb = 0x1F
+sbox 0xcc = 0x4B
+sbox 0xcd = 0xBD
+sbox 0xce = 0x8B
+sbox 0xcf = 0x8A
+
+sbox 0xd0 = 0x70
+sbox 0xd1 = 0x3E
+sbox 0xd2 = 0xB5
+sbox 0xd3 = 0x66
+sbox 0xd4 = 0x48
+sbox 0xd5 = 0x03
+sbox 0xd6 = 0xF6
+sbox 0xd7 = 0x0E
+
+sbox 0xd8 = 0x61
+sbox 0xd9 = 0x35
+sbox 0xda = 0x57
+sbox 0xdb = 0xB9
+sbox 0xdc = 0x86
+sbox 0xdd = 0xC1
+sbox 0xde = 0x1D
+sbox 0xdf = 0x9E
+
+sbox 0xe0 = 0xE1
+sbox 0xe1 = 0xF8
+sbox 0xe2 = 0x98
+sbox 0xe3 = 0x11
+sbox 0xe4 = 0x69
+sbox 0xe5 = 0xD9
+sbox 0xe6 = 0x8E
+sbox 0xe7 = 0x94
+
+sbox 0xe8 = 0x9B
+sbox 0xe9 = 0x1E
+sbox 0xea = 0x87
+sbox 0xeb = 0xE9
+sbox 0xec = 0xCE
+sbox 0xed = 0x55
+sbox 0xee = 0x28
+sbox 0xef = 0xDF
+
+sbox 0xf0 = 0x8C
+sbox 0xf1 = 0xA1
+sbox 0xf2 = 0x89
+sbox 0xf3 = 0x0D
+sbox 0xf4 = 0xBF
+sbox 0xf5 = 0xE6
+sbox 0xf6 = 0x42
+sbox 0xf7 = 0x68
+
+sbox 0xf8 = 0x41
+sbox 0xf9 = 0x99
+sbox 0xfa = 0x2D
+sbox 0xfb = 0x0F
+sbox 0xfc = 0xB0
+sbox 0xfd = 0x54
+sbox 0xfe = 0xBB
+sbox 0xff = 0x16
+
+{----}
+
+sboxRev 0x63 = 0x00
+sboxRev 0x7C = 0x01
+sboxRev 0x77 = 0x02
+sboxRev 0x7B = 0x03
+sboxRev 0xF2 = 0x04
+sboxRev 0x6B = 0x05
+sboxRev 0x6F = 0x06
+sboxRev 0xC5 = 0x07
+
+sboxRev 0x30 = 0x08
+sboxRev 0x01 = 0x09
+sboxRev 0x67 = 0x0a
+sboxRev 0x2B = 0x0b
+sboxRev 0xFE = 0x0c
+sboxRev 0xD7 = 0x0d
+sboxRev 0xAB = 0x0e
+sboxRev 0x76 = 0x0f
+
+sboxRev 0xCA = 0x10
+sboxRev 0x82 = 0x11
+sboxRev 0xC9 = 0x12
+sboxRev 0x7D = 0x13
+sboxRev 0xFA = 0x14
+sboxRev 0x59 = 0x15
+sboxRev 0x47 = 0x16
+sboxRev 0xF0 = 0x17
+
+sboxRev 0xAD = 0x18
+sboxRev 0xD4 = 0x19
+sboxRev 0xA2 = 0x1a
+sboxRev 0xAF = 0x1b
+sboxRev 0x9C = 0x1c
+sboxRev 0xA4 = 0x1d
+sboxRev 0x72 = 0x1e
+sboxRev 0xC0 = 0x1f
+
+sboxRev 0xB7 = 0x20
+sboxRev 0xFD = 0x21
+sboxRev 0x93 = 0x22
+sboxRev 0x26 = 0x23
+sboxRev 0x36 = 0x24
+sboxRev 0x3F = 0x25
+sboxRev 0xF7 = 0x26
+sboxRev 0xCC = 0x27
+
+sboxRev 0x34 = 0x28
+sboxRev 0xA5 = 0x29
+sboxRev 0xE5 = 0x2a
+sboxRev 0xF1 = 0x2b
+sboxRev 0x71 = 0x2c
+sboxRev 0xD8 = 0x2d
+sboxRev 0x31 = 0x2e
+sboxRev 0x15 = 0x2f
+
+sboxRev 0x04 = 0x30
+sboxRev 0xC7 = 0x31
+sboxRev 0x23 = 0x32
+sboxRev 0xC3 = 0x33
+sboxRev 0x18 = 0x34
+sboxRev 0x96 = 0x35
+sboxRev 0x05 = 0x36
+sboxRev 0x9A = 0x37
+
+sboxRev 0x07 = 0x38
+sboxRev 0x12 = 0x39
+sboxRev 0x80 = 0x3a
+sboxRev 0xE2 = 0x3b
+sboxRev 0xEB = 0x3c
+sboxRev 0x27 = 0x3d
+sboxRev 0xB2 = 0x3e
+sboxRev 0x75 = 0x3f
+
+sboxRev 0x09 = 0x40
+sboxRev 0x83 = 0x41
+sboxRev 0x2C = 0x42
+sboxRev 0x1A = 0x43
+sboxRev 0x1B = 0x44
+sboxRev 0x6E = 0x45
+sboxRev 0x5A = 0x46
+sboxRev 0xA0 = 0x47
+
+sboxRev 0x52 = 0x48
+sboxRev 0x3B = 0x49
+sboxRev 0xD6 = 0x4a
+sboxRev 0xB3 = 0x4b
+sboxRev 0x29 = 0x4c
+sboxRev 0xE3 = 0x4d
+sboxRev 0x2F = 0x4e
+sboxRev 0x84 = 0x4f
+
+sboxRev 0x53 = 0x50
+sboxRev 0xD1 = 0x51
+sboxRev 0x00 = 0x52
+sboxRev 0xED = 0x53
+sboxRev 0x20 = 0x54
+sboxRev 0xFC = 0x55
+sboxRev 0xB1 = 0x56
+sboxRev 0x5B = 0x57
+
+sboxRev 0x6A = 0x58
+sboxRev 0xCB = 0x59
+sboxRev 0xBE = 0x5a
+sboxRev 0x39 = 0x5b
+sboxRev 0x4A = 0x5c
+sboxRev 0x4C = 0x5d
+sboxRev 0x58 = 0x5e
+sboxRev 0xCF = 0x5f
+
+sboxRev 0xD0 = 0x60
+sboxRev 0xEF = 0x61
+sboxRev 0xAA = 0x62
+sboxRev 0xFB = 0x63
+sboxRev 0x43 = 0x64
+sboxRev 0x4D = 0x65
+sboxRev 0x33 = 0x66
+sboxRev 0x85 = 0x67
+
+sboxRev 0x45 = 0x68
+sboxRev 0xF9 = 0x69
+sboxRev 0x02 = 0x6a
+sboxRev 0x7F = 0x6b
+sboxRev 0x50 = 0x6c
+sboxRev 0x3C = 0x6d
+sboxRev 0x9F = 0x6e
+sboxRev 0xA8 = 0x6f
+
+sboxRev 0x51 = 0x70
+sboxRev 0xA3 = 0x71
+sboxRev 0x40 = 0x72
+sboxRev 0x8F = 0x73
+sboxRev 0x92 = 0x74
+sboxRev 0x9D = 0x75
+sboxRev 0x38 = 0x76
+sboxRev 0xF5 = 0x77
+
+sboxRev 0xBC = 0x78
+sboxRev 0xB6 = 0x79
+sboxRev 0xDA = 0x7a
+sboxRev 0x21 = 0x7b
+sboxRev 0x10 = 0x7c
+sboxRev 0xFF = 0x7d
+sboxRev 0xF3 = 0x7e
+sboxRev 0xD2 = 0x7f
+
+sboxRev 0xCD = 0x80
+sboxRev 0x0C = 0x81
+sboxRev 0x13 = 0x82
+sboxRev 0xEC = 0x83
+sboxRev 0x5F = 0x84
+sboxRev 0x97 = 0x85
+sboxRev 0x44 = 0x86
+sboxRev 0x17 = 0x87
+
+sboxRev 0xC4 = 0x88
+sboxRev 0xA7 = 0x89
+sboxRev 0x7E = 0x8a
+sboxRev 0x3D = 0x8b
+sboxRev 0x64 = 0x8c
+sboxRev 0x5D = 0x8d
+sboxRev 0x19 = 0x8e
+sboxRev 0x73 = 0x8f
+
+sboxRev 0x60 = 0x90
+sboxRev 0x81 = 0x91
+sboxRev 0x4F = 0x92
+sboxRev 0xDC = 0x93
+sboxRev 0x22 = 0x94
+sboxRev 0x2A = 0x95
+sboxRev 0x90 = 0x96
+sboxRev 0x88 = 0x97
+
+sboxRev 0x46 = 0x98
+sboxRev 0xEE = 0x99
+sboxRev 0xB8 = 0x9a
+sboxRev 0x14 = 0x9b
+sboxRev 0xDE = 0x9c
+sboxRev 0x5E = 0x9d
+sboxRev 0x0B = 0x9e
+sboxRev 0xDB = 0x9f
+
+sboxRev 0xE0 = 0xa0
+sboxRev 0x32 = 0xa1
+sboxRev 0x3A = 0xa2
+sboxRev 0x0A = 0xa3
+sboxRev 0x49 = 0xa4
+sboxRev 0x06 = 0xa5
+sboxRev 0x24 = 0xa6
+sboxRev 0x5C = 0xa7
+
+sboxRev 0xC2 = 0xa8
+sboxRev 0xD3 = 0xa9
+sboxRev 0xAC = 0xaa
+sboxRev 0x62 = 0xab
+sboxRev 0x91 = 0xac
+sboxRev 0x95 = 0xad
+sboxRev 0xE4 = 0xae
+sboxRev 0x79 = 0xaf
+
+sboxRev 0xE7 = 0xb0
+sboxRev 0xC8 = 0xb1
+sboxRev 0x37 = 0xb2
+sboxRev 0x6D = 0xb3
+sboxRev 0x8D = 0xb4
+sboxRev 0xD5 = 0xb5
+sboxRev 0x4E = 0xb6
+sboxRev 0xA9 = 0xb7
+
+sboxRev 0x6C = 0xb8
+sboxRev 0x56 = 0xb9
+sboxRev 0xF4 = 0xba
+sboxRev 0xEA = 0xbb
+sboxRev 0x65 = 0xbc
+sboxRev 0x7A = 0xbd
+sboxRev 0xAE = 0xbe
+sboxRev 0x08 = 0xbf
+
+sboxRev 0xBA = 0xc0
+sboxRev 0x78 = 0xc1
+sboxRev 0x25 = 0xc2
+sboxRev 0x2E = 0xc3
+sboxRev 0x1C = 0xc4
+sboxRev 0xA6 = 0xc5
+sboxRev 0xB4 = 0xc6
+sboxRev 0xC6 = 0xc7
+
+sboxRev 0xE8 = 0xc8
+sboxRev 0xDD = 0xc9
+sboxRev 0x74 = 0xca
+sboxRev 0x1F = 0xcb
+sboxRev 0x4B = 0xcc
+sboxRev 0xBD = 0xcd
+sboxRev 0x8B = 0xce
+sboxRev 0x8A = 0xcf
+
+sboxRev 0x70 = 0xd0
+sboxRev 0x3E = 0xd1
+sboxRev 0xB5 = 0xd2
+sboxRev 0x66 = 0xd3
+sboxRev 0x48 = 0xd4
+sboxRev 0x03 = 0xd5
+sboxRev 0xF6 = 0xd6
+sboxRev 0x0E = 0xd7
+
+sboxRev 0x61 = 0xd8
+sboxRev 0x35 = 0xd9
+sboxRev 0x57 = 0xda
+sboxRev 0xB9 = 0xdb
+sboxRev 0x86 = 0xdc
+sboxRev 0xC1 = 0xdd
+sboxRev 0x1D = 0xde
+sboxRev 0x9E = 0xdf
+
+sboxRev 0xE1 = 0xe0
+sboxRev 0xF8 = 0xe1
+sboxRev 0x98 = 0xe2
+sboxRev 0x11 = 0xe3
+sboxRev 0x69 = 0xe4
+sboxRev 0xD9 = 0xe5
+sboxRev 0x8E = 0xe6
+sboxRev 0x94 = 0xe7
+
+sboxRev 0x9B = 0xe8
+sboxRev 0x1E = 0xe9
+sboxRev 0x87 = 0xea
+sboxRev 0xE9 = 0xeb
+sboxRev 0xCE = 0xec
+sboxRev 0x55 = 0xed
+sboxRev 0x28 = 0xee
+sboxRev 0xDF = 0xef
+
+sboxRev 0x8C = 0xf0
+sboxRev 0xA1 = 0xf1
+sboxRev 0x89 = 0xf2
+sboxRev 0x0D = 0xf3
+sboxRev 0xBF = 0xf4
+sboxRev 0xE6 = 0xf5
+sboxRev 0x42 = 0xf6
+sboxRev 0x68 = 0xf7
+
+sboxRev 0x41 = 0xf8
+sboxRev 0x99 = 0xf9
+sboxRev 0x2D = 0xfa
+sboxRev 0x0F = 0xfb
+sboxRev 0xB0 = 0xfc
+sboxRev 0x54 = 0xfd
+sboxRev 0xBB = 0xfe
+sboxRev 0x16 = 0xff
+
+xtime :: Word32 -> Word32
+xtime x = b
+	where	a = x `shiftL` 1
+		b = if a .&. (0x0100) == 0 then a else a `xor` 0x11b
+
+xtimeX2 :: Word32 -> Word32
+--xtimeX2 = xtime . xtime
+xtimeX2 x = c
+	where	a = x `shiftL` 2
+		b = if a .&. (0x0200) == 0 then a else a `xor` 0x236
+		c = if b .&. (0x0100) == 0 then b else b `xor` 0x11b
+
+xtimeX3 :: Word32 -> Word32
+--xtimeX3 = xtime . xtime . xtime
+xtimeX3 x = d
+	where	a = x `shiftL` 3
+		b = if a .&. (0x0400) == 0 then a else a `xor` 0x46c
+		c = if b .&. (0x0200) == 0 then b else b `xor` 0x236
+		d = if c .&. (0x0100) == 0 then c else c `xor` 0x11b
+
+xtime03 :: Word32 -> Word32
+xtime03 x = x `xor` (xtime x)
+
+xtime0e :: Word32 -> Word32 
+xtime0e x = xtime (x `xor` (xtime (x `xor` (xtime x))))
+
+xtime09 :: Word32 -> Word32 
+xtime09 x = x `xor` (xtimeX3 x)
+
+xtime0d :: Word32 -> Word32 
+xtime0d x = x `xor` (xtimeX2 (x `xor` (xtime x)))
+
+xtime0b :: Word32 -> Word32 
+xtime0b x = x `xor` (xtime (x `xor` (xtimeX2 x)))
+
+generateKey :: Int -> Int -> Word32 -> Word32 -> Word32
+generateKey nk i wIminus1 wIminusNk = 
+		(temp' `xor` wIminusNk)
+	where temp' = 
+		if (i `mod` nk) == 0 then (subword(rotword temp)) `xor` rcon
+		else if (nk > 6) && ((i `mod` nk) == 4) then subword temp
+		else temp
+	      temp = wIminus1	
+	      subword :: Word32 -> Word32
+	      subword w = (a `shiftL` 24) .|. (b `shiftL` 16) .|.
+	      		  (c `shiftL` 8) .|. d
+			  where a = sbox ((w `shiftR` 24) .&. 0xff)
+			        b = sbox ((w `shiftR` 16) .&. 0xff)
+			        c = sbox ((w `shiftR`  8) .&. 0xff)
+			        d = sbox ( w             .&. 0xff)
+	      rotword :: Word32 -> Word32
+	      rotword w = w `rotateL` 8 			
+	      rcon :: Word32
+	      rcon = ((fromIntegral rconMSB)::Word32) `shiftL` 24
+	      rconMSB = (iterate xtime 0x01) !! ((i `div` nk) - 1)
+	
+wordify :: [Octet] -> [Word32]
+wordify [] = []
+wordify octets = firstWord:otherWords
+	where
+		(firstWord, otherOctets) = getWord32 octets
+		otherWords = wordify otherOctets
+
+generateKeys :: Int -> Int -> [Octet] -> [Word32]
+generateKeys nr nk mainKey = 
+		-- assert ((nk * 4) == length mainKey) $
+		(take (4 * (nr + 1)) xs)
+	where   
+		xs = (wordify mainKey) ++ (zipWith3 (generateKey nk)
+						(drop nk [0,1..])
+						(drop (nk - 1) xs)
+						xs
+					)
+
+subBytes :: State -> State
+subBytes (State (s00, s01, s02, s03)
+		(s10, s11, s12, s13)
+	 	(s20, s21, s22, s23)
+	 	(s30, s31, s32, s33)) = 
+	  State (sbox s00, sbox s01, sbox s02, sbox s03)
+ 		(sbox s10, sbox s11, sbox s12, sbox s13)
+		(sbox s20, sbox s21, sbox s22, sbox s23)
+		(sbox s30, sbox s31, sbox s32, sbox s33)
+
+subBytesRev :: State -> State
+subBytesRev (State (s00, s01, s02, s03)
+		   (s10, s11, s12, s13)
+	 	   (s20, s21, s22, s23)
+	 	   (s30, s31, s32, s33)) = 
+	  State (sboxRev s00, sboxRev s01, sboxRev s02, sboxRev s03)
+  		(sboxRev s10, sboxRev s11, sboxRev s12, sboxRev s13)
+  		(sboxRev s20, sboxRev s21, sboxRev s22, sboxRev s23)
+  		(sboxRev s30, sboxRev s31, sboxRev s32, sboxRev s33)
+
+shiftRows :: State -> State		
+shiftRows (State (s00, s01, s02, s03)
+		 (s10, s11, s12, s13)
+	 	 (s20, s21, s22, s23)
+	 	 (s30, s31, s32, s33)) = 
+	  State (s00, s01, s02, s03)
+ 		(s11, s12, s13, s10)
+		(s22, s23, s20, s21)
+		(s33, s30, s31, s32)
+
+shiftRowsRev :: State -> State		
+shiftRowsRev (State (s00, s01, s02, s03)
+		    (s10, s11, s12, s13)
+	 	    (s20, s21, s22, s23)
+	 	    (s30, s31, s32, s33)) = 
+	  State (s00, s01, s02, s03)
+ 		(s13, s10, s11, s12)
+		(s22, s23, s20, s21)
+		(s31, s32, s33, s30)
+
+mixColumn:: (Word32, Word32, Word32, Word32) -> (Word32, Word32, Word32, Word32)
+mixColumn (s0,s1,s2,s3) = 
+	((xtime   s0) `xor` (xtime03 s1) `xor`          s2  `xor`          s3 ,
+	          s0  `xor` (xtime   s1) `xor` (xtime03 s2) `xor`          s3 ,
+	          s0  `xor`          s1  `xor` (xtime   s2) `xor` (xtime03 s3),
+	 (xtime03 s0) `xor`          s1  `xor`          s2  `xor` (xtime   s3))
+
+mixColumns :: State -> State		
+mixColumns (State (s00, s01, s02, s03)
+		  (s10, s11, s12, s13)
+	 	  (s20, s21, s22, s23)
+	 	  (s30, s31, s32, s33)) = 
+	  State (r00, r01, r02, r03)
+ 		(r10, r11, r12, r13)
+		(r20, r21, r22, r23)
+		(r30, r31, r32, r33)
+	where (r00, r10, r20, r30) = mixColumn (s00, s10, s20, s30)
+	      (r01, r11, r21, r31) = mixColumn (s01, s11, s21, s31)
+	      (r02, r12, r22, r32) = mixColumn (s02, s12, s22, s32)
+	      (r03, r13, r23, r33) = mixColumn (s03, s13, s23, s33)
+
+mixColumnRev :: (Word32, Word32, Word32, Word32) 
+		-> (Word32, Word32, Word32, Word32)
+mixColumnRev (s0,s1,s2,s3) = 
+	((xtime0e s0) `xor` (xtime0b s1) `xor` (xtime0d s2) `xor` (xtime09 s3),
+	 (xtime09 s0) `xor` (xtime0e s1) `xor` (xtime0b s2) `xor` (xtime0d s3),
+	 (xtime0d s0) `xor` (xtime09 s1) `xor` (xtime0e s2) `xor` (xtime0b s3),
+	 (xtime0b s0) `xor` (xtime0d s1) `xor` (xtime09 s2) `xor` (xtime0e s3))
+
+mixColumnsRev :: State -> State		
+mixColumnsRev (State (s00, s01, s02, s03)
+		  (s10, s11, s12, s13)
+	 	  (s20, s21, s22, s23)
+	 	  (s30, s31, s32, s33)) = 
+	  State (r00, r01, r02, r03)
+ 		(r10, r11, r12, r13)
+		(r20, r21, r22, r23)
+		(r30, r31, r32, r33)
+	where (r00, r10, r20, r30) = mixColumnRev (s00, s10, s20, s30)
+	      (r01, r11, r21, r31) = mixColumnRev (s01, s11, s21, s31)
+	      (r02, r12, r22, r32) = mixColumnRev (s02, s12, s22, s32)
+	      (r03, r13, r23, r33) = mixColumnRev (s03, s13, s23, s33)
+
+addRoundKey :: State -> State -> State
+addRoundKey (State (k00, k01, k02, k03)
+		   (k10, k11, k12, k13)
+		   (k20, k21, k22, k23)
+	 	   (k30, k31, k32, k33))   
+	    (State (s00, s01, s02, s03)
+		   (s10, s11, s12, s13)
+		   (s20, s21, s22, s23)
+	 	   (s30, s31, s32, s33)) = 
+	  State (s00 `xor` k00, s01 `xor` k01, s02 `xor` k02, s03 `xor` k03)
+ 		(s10 `xor` k10, s11 `xor` k11, s12 `xor` k12, s13 `xor` k13)
+		(s20 `xor` k20, s21 `xor` k21, s22 `xor` k22, s23 `xor` k23)
+		(s30 `xor` k30, s31 `xor` k31, s32 `xor` k32, s33 `xor` k33)
+
+genAddRoundKey :: [Word32] -> [State -> State]
+genAddRoundKey [] = []
+genAddRoundKey (a:b:c:d:ks) = (addRoundKey k):(genAddRoundKey ks)
+	where k = State (fromIntegral s00, fromIntegral s01,
+			 fromIntegral s02, fromIntegral s03)
+			(fromIntegral s10, fromIntegral s11,
+			 fromIntegral s12, fromIntegral s13)
+			(fromIntegral s20, fromIntegral s21,
+			 fromIntegral s22, fromIntegral s23)
+			(fromIntegral s30, fromIntegral s31,
+			 fromIntegral s32, fromIntegral s33) 
+	      [s00, s10, s20, s30] = putWord32 a 		
+	      [s01, s11, s21, s31] = putWord32 b 		
+	      [s02, s12, s22, s32] = putWord32 c 		
+	      [s03, s13, s23, s33] = putWord32 d 		
+
+getWord32 :: [Octet] -> (Word32, [Octet])
+getWord32 (a:b:c:d:xs) = (x, xs)
+	where 
+		x = ((fromIntegral a) `shiftL` 24) .|. 
+		    ((fromIntegral b) `shiftL` 16) .|. 
+		    ((fromIntegral c) `shiftL`  8) .|. 
+		    ((fromIntegral d)            ) 
+
+putWord32 :: Word32 -> [Octet]
+--a bit slower putWord32 x = map fromIntegral [a,b,c,d]
+putWord32 x = [fromIntegral a, fromIntegral b, fromIntegral c, fromIntegral d]
+	where
+		a = (x `shiftR` 24) 
+		b = (x `shiftR` 16) .&. 255
+		c = (x `shiftR`  8) .&. 255
+		d = (x            ) .&. 255
+
+{-
+testGenerateKeys128 :: Test
+testGenerateKeys128 = 
+	let key = [0x2b, 0x7e, 0x15, 0x16,
+		   0x28, 0xae, 0xd2, 0xa6,
+		   0xab, 0xf7, 0x15, 0x88,
+		   0x09, 0xcf, 0x4f, 0x3c]
+	    expected = [0x2b7e1516, 0x28aed2a6, 0xabf71588, 0x09cf4f3c,
+	    		0xa0fafe17, 0x88542cb1, 0x23a33939, 0x2a6c7605,
+			0xf2c295f2, 0x7a96b943, 0x5935807a, 0x7359f67f,
+			0x3d80477d, 0x4716fe3e, 0x1e237e44, 0x6d7a883b,
+			0xef44a541, 0xa8525b7f, 0xb671253b, 0xdb0bad00,
+			0xd4d1c6f8, 0x7c839d87, 0xcaf2b8bc, 0x11f915bc,
+			0x6d88a37a, 0x110b3efd, 0xdbf98641, 0xca0093fd,
+			0x4e54f70e, 0x5f5fc9f3, 0x84a64fb2, 0x4ea6dc4f,
+			0xead27321, 0xb58dbad2, 0x312bf560, 0x7f8d292f,
+			0xac7766f3, 0x19fadc21, 0x28d12941, 0x575c006e,
+			0xd014f9a8, 0xc9ee2589, 0xe13f0cc8, 0xb6630ca6
+			]
+	in TestCase (do
+		assertEqual "" expected (generateKeys 10 4 key)
+	)
+
+
+testGenerateKeys192 :: Test
+testGenerateKeys192 = 
+	let key = [0x8e, 0x73, 0xb0, 0xf7,
+		   0xda, 0x0e, 0x64, 0x52,
+		   0xc8, 0x10, 0xf3, 0x2b,
+		   0x80, 0x90, 0x79, 0xe5,
+		   0x62, 0xf8, 0xea, 0xd2,
+		   0x52, 0x2c, 0x6b, 0x7b]
+	    expected = [0x8e73b0f7, 0xda0e6452, 0xc810f32b, 0x809079e5,
+	    		0x62f8ead2, 0x522c6b7b, 0xfe0c91f7, 0x2402f5a5,
+			0xec12068e, 0x6c827f6b, 0x0e7a95b9, 0x5c56fec2,
+			0x4db7b4bd, 0x69b54118, 0x85a74796, 0xe92538fd,
+			0xe75fad44, 0xbb095386, 0x485af057, 0x21efb14f
+			]
+	in TestCase (do
+		assertEqual "" expected
+			(take (length expected) (generateKeys 12 6 key))
+	)
+
+testGenerateKeys256 :: Test
+testGenerateKeys256 = 
+	let key = [0x60, 0x3d, 0xeb, 0x10,
+		   0x15, 0xca, 0x71, 0xbe,
+		   0x2b, 0x73, 0xae, 0xf0,
+		   0x85, 0x7d, 0x77, 0x81,
+		   0x1f, 0x35, 0x2c, 0x07,
+		   0x3b, 0x61, 0x08, 0xd7,
+		   0x2d, 0x98, 0x10, 0xa3,
+		   0x09, 0x14, 0xdf, 0xf4]
+	    expected = [0x603deb10, 0x15ca71be, 0x2b73aef0, 0x857d7781,
+	    		0x1f352c07, 0x3b6108d7, 0x2d9810a3, 0x0914dff4,
+			0x9ba35411, 0x8e6925af, 0xa51a8b5f, 0x2067fcde,
+			0xa8b09c1a, 0x93d194cd, 0xbe49846e, 0xb75d5b9a,
+			0xd59aecb8, 0x5bf3c917, 0xfee94248, 0xde8ebe96
+			]
+	in TestCase (do
+		assertEqual "" expected 
+			(take (length expected) (generateKeys 14 8 key))
+	)
+
+testAes128 :: Test
+testAes128 = 
+	let key = [0x2b, 0x7e, 0x15, 0x16,
+		   0x28, 0xae, 0xd2, 0xa6,
+		   0xab, 0xf7, 0x15, 0x88,
+		   0x09, 0xcf, 0x4f, 0x3c]
+	    input = [0x32, 0x43, 0xf6, 0xa8, 
+	    	     0x88, 0x5a, 0x30, 0x8d,
+		     0x31, 0x31, 0x98, 0xa2,
+		     0xe0, 0x37, 0x07, 0x34]
+	    output = [0x39, 0x25, 0x84, 0x1d,
+	    	      0x02, 0xdc, 0x09, 0xfb,
+		      0xdc, 0x11, 0x85, 0x97,
+		      0x19, 0x6a, 0x0b, 0x32]
+	in TestCase (do
+		assertEqual "encrypt test" output (aes128Encrypt key input)
+		assertEqual "encrypt/decrypt test" input 
+				(aes128Decrypt key (aes128Encrypt key input))
+	)
+
+testAesRandom :: Test
+testAesRandom = 
+	TestCase (do
+		key128 <- getRandomOctets 16 
+		key192 <- getRandomOctets 24 
+		key256 <- getRandomOctets 32 
+		msg <- getRandomOctets 16 
+		assertEqual "aes128" msg 
+			(aes128Decrypt key128 (aes128Encrypt key128 msg))
+		assertEqual "aes192" msg 
+			(aes192Decrypt key192 (aes192Encrypt key192 msg))
+		assertEqual "aes256" msg 
+			(aes256Decrypt key256 (aes256Encrypt key256 msg))
+	)
+
+-- | HUnit tests
+tests :: Test
+tests = TestList [
+		TestLabel "testGenerateKeys128" testGenerateKeys128,
+		TestLabel "testGenerateKeys192" testGenerateKeys192,
+		TestLabel "testGenerateKeys256" testGenerateKeys256,
+		TestLabel "testAes128" testAes128,
+		TestLabel "testAesRandom" testAesRandom
+	]
+-}
+
diff --git a/Codec/Encryption/BurtonRNGSlow.hs b/Codec/Encryption/BurtonRNGSlow.hs
new file mode 100644
--- /dev/null
+++ b/Codec/Encryption/BurtonRNGSlow.hs
@@ -0,0 +1,83 @@
+
+{- | 
+
+   This module includes two all-haskell implementations of Burton
+   Smith's algorithm for a statistically-sound binary tree of random
+   number generators.  See the following thread:
+
+   <http://www.mail-archive.com/haskell-cafe@haskell.org/msg83901.html>
+
+   Generally, Codec.Crypto.IntelAES should be used in favor of this
+   module, but it is included for benchmarking purposes.
+
+-}
+
+module Codec.Encryption.BurtonRNGSlow
+    (
+     mkBurtonGen_reference,
+     mkBurtonGen
+     -- Plus, instances exported of course.
+    )
+where 
+
+import System.Random (RandomGen, next, split)
+import Crypto.Random.DRBG ()
+
+import Codec.Encryption.AES (encrypt)
+import Data.LargeWord
+
+-- import Debug.Trace
+
+--------------------------------------------------------------------------------
+-- Reference implementation.
+
+-- | Type of random number generators
+--   This is a very simple but extremely inefficient vesion.
+data RNG_ref = RNG_ref {-# UNPACK #-} !Word128 -- Seed
+                       {-# UNPACK #-} !Word128 -- Counter
+next128 (RNG_ref k c) = (encrypt k c, RNG_ref k (c+1))
+
+-- | This instance is inefficient because it creates 128bits of
+--   randomness but only uses an Int-sized (32 or 64 bit) subset of
+--   them.
+instance RandomGen RNG_ref where
+  next g = (fromIntegral n, g')
+   where (n,g') = next128 g
+  split g@(RNG_ref k c) = (g', mkBurtonGen_reference n)
+   where (n,g') = next128 g
+
+-- | Extra slow reference implementation.
+mkBurtonGen_reference :: Word128 -> RNG_ref
+mkBurtonGen_reference seed = RNG_ref seed 0
+
+--------------------------------------------------------------------------------
+bits_in_int = round $ 1 + logBase 2 (fromIntegral (maxBound :: Int))
+steps = 128 `quot` bits_in_int
+
+-- | Type representing a more efficient random number generator that
+-- | still uses an all-Haskell implementation.
+data RNG = RNG {-# UNPACK #-} !Word128 -- Seed
+               {-# UNPACK #-} !Word128 -- Last batch of random bits generated.
+	       {-# UNPACK #-} !Word128 -- Counter
+	       {-# UNPACK #-} !Int     -- Phase/step
+
+-- | The idea with this one is that once we generate 128 bits of
+--   randomness we parcel it out into two or four ints.
+mkBurtonGen :: Word128 -> RNG
+mkBurtonGen seed = RNG seed (encrypt seed 0) 1 0
+
+next128' (RNG k _ c _) = RNG k (encrypt k c) (c+1) 0
+
+instance RandomGen RNG where
+  -- In this scenario its time to generate a new batch of bits:
+  --  next g@(RNG k bits c s) | s == steps = next (next128' g)
+
+-- FIXME: ASSUMES 64 BIT INTS  -- NONPORTABLE:
+  -- This takes advantage the structure of the Word128 type:
+  next g@(RNG k bits c 0) = (fromIntegral (loHalf bits), RNG k bits c 1)
+  next g@(RNG k bits c 1) = (fromIntegral (hiHalf bits), next128' g)
+
+  -- We waste some random bits here:
+  split g@(RNG k bits c s) = (g', next128' g')
+   where g' = next128' g
+
diff --git a/Codec/Utils.hs b/Codec/Utils.hs
new file mode 100644
--- /dev/null
+++ b/Codec/Utils.hs
@@ -0,0 +1,138 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Codec.Utils
+-- Copyright   :  (c) Dominic Steinitz 2003
+-- License     :  BSD-style (see the file ReadMe.tex)
+-- 
+-- Maintainer  :  dominic.steinitz@blueyonder.co.uk
+-- Stability   :  experimental
+-- Portability :  portable
+--
+-- Utilities for coding and decoding.
+--
+-----------------------------------------------------------------------------
+
+module Codec.Utils (
+   -- * Types and Constants
+   Octet,
+   msb,
+   -- * Octet Conversion Functions
+   fromTwosComp, toTwosComp,
+   toOctets, fromOctets,
+   listFromOctets, listToOctets,
+   i2osp
+	      ) where
+
+import Data.Word
+import Data.Bits
+
+powersOf n = 1 : (map (*n) (powersOf n))
+
+toBase x = 
+   map fromIntegral .
+   reverse .
+   map (flip mod x) .
+   takeWhile (/=0) .
+   iterate (flip div x)
+
+-- | Take a number a convert it to base n as a list of octets.
+
+toOctets :: (Integral a, Integral b) => a -> b -> [Octet]
+toOctets n x = (toBase n . fromIntegral) x
+
+-- | This is used to (approximately) get back to a starting word list.
+-- For example, if you have a list of 3 Word8 and try to convert them to
+-- a Word32, the Word32 will get null-padded, and without correction, you
+-- will get 4 Word8s when converting back. This corrects it.
+-- Unfortunately, it also means you will have errors if trying to convert
+-- Word8 lists with nulls on the end.
+trimNulls :: [Word8] -> [Word8]
+trimNulls = reverse . (dropWhile (== 0)) . reverse
+
+-- | Converts a list of numbers into a list of octets.
+-- The resultant list has nulls trimmed from the end to make this the dual
+-- of listFromOctets (except when the original octet list ended with nulls;
+-- see 'trimNulls').
+listToOctets :: (Bits a, Integral a) => [a] -> [Octet]
+listToOctets x = trimNulls $ concat paddedOctets where
+    paddedOctets :: [[Octet]]
+    paddedOctets = map (padTo bytes) rawOctets
+    rawOctets :: [[Octet]]
+    rawOctets = map (reverse . toOctets 256) x
+    padTo :: Int -> [Octet] -> [Octet]
+    padTo x y = take x $ y ++ repeat 0
+    bytes :: Int
+    bytes = bitSize (head x) `div` 8
+
+-- | The basic type for encoding and decoding.
+
+type Octet = Word8
+
+-- | The most significant bit of an 'Octet'.
+
+msb :: Int
+msb = bitSize (undefined::Octet) - 1
+
+-- | Take a list of octets (a number expressed in base n) and convert it
+--   to a number.
+
+fromOctets :: (Integral a, Integral b) => a -> [Octet] -> b
+fromOctets n x = 
+   fromIntegral $ 
+   sum $ 
+   zipWith (*) (powersOf n) (reverse (map fromIntegral x))
+
+-- | See 'listToOctets'.
+listFromOctets :: (Integral a, Bits a) => [Octet] -> [a]
+listFromOctets [] = []
+listFromOctets x = result where
+    result = first : rest
+    first = fromOctets 256 first'
+    first' = reverse $ take bytes x
+    rest = listFromOctets $ drop bytes x
+    bytes = bitSize first `div` 8
+
+-- | Take the length of the required number of octets and convert the 
+--   number to base 256 padding it out to the required length. If the
+--   required length is less than the number of octets of the converted
+--   number then return the converted number. NB this is different from
+--   the standard <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf>
+--   but mimics how replicate behaves.
+
+i2osp :: Integral a => Int -> a -> [Octet]
+i2osp l y = 
+   pad ++ z
+      where
+         pad = replicate (l - unPaddedLen) (0x00::Octet)
+	 z = toOctets 256 y
+	 unPaddedLen = length z
+
+-- | Convert from twos complement.
+
+fromTwosComp :: Integral a => [Octet] -> a
+fromTwosComp x =  conv x
+   where conv []       = 0
+         conv w@(x:xs) = if (testBit x msb)
+                            then neg w
+                            else pos w
+         neg w@(x:xs)  = let z=(clearBit x msb):xs in
+                            fromIntegral((fromOctets 256 z)-
+                                         (128*(256^((length w)-1))))
+         pos w         = fromIntegral(fromOctets 256 w)
+
+toTwosComp :: Integral a => a -> [Octet]
+toTwosComp x
+   | x < 0     = reverse . plusOne . reverse . (map complement) $ u
+   | x == 0    = [0x00]
+   | otherwise = u
+   where z@(y:ys) = toBase 256 (abs x)
+         u        = if testBit y msb
+                       then 0x00:z
+                       else z
+
+plusOne :: [Octet] -> [Octet]
+plusOne [] = [1]
+plusOne (x:xs) =
+   if x == 0xff
+      then 0x00:(plusOne xs)
+      else (x+1):xs
diff --git a/Data/LargeWord.hs b/Data/LargeWord.hs
new file mode 100644
--- /dev/null
+++ b/Data/LargeWord.hs
@@ -0,0 +1,153 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Data.LargeWord
+-- Copyright   :  (c) Dominic Steinitz 2004
+-- License     :  BSD-style (see the file ReadMe.tex)
+-- 
+-- Maintainer  :  dominic.steinitz@blueyonder.co.uk
+-- Stability   :  experimental
+-- Portability :  portable
+--
+-- Provides Word128, Word192 and Word256 and a way of producing other
+-- large words if required.
+--
+-----------------------------------------------------------------------------
+
+module Data.LargeWord
+   (LargeKey,Word96,Word128,Word160,Word192,Word224,Word256,
+   loHalf, hiHalf) where
+
+import Data.Word
+import Data.Bits
+import Numeric
+import Data.Char
+
+-- Keys have certain capabilities.
+
+class LargeWord a where
+   largeWordToInteger :: a -> Integer
+   integerToLargeWord :: Integer -> a
+   largeWordPlus :: a -> a -> a
+   largeWordAnd :: a -> a -> a
+   largeWordOr :: a -> a -> a
+   largeWordShift :: a -> Int -> a
+   largeWordXor :: a -> a -> a
+   largeBitSize :: a -> Int
+
+-- Word32 is a key in the obvious way.
+
+instance LargeWord Word32 where
+   largeWordToInteger = toInteger
+   integerToLargeWord = fromInteger
+   largeWordPlus = (+)
+   largeWordAnd = (.&.)
+   largeWordOr = (.|.)
+   largeWordShift = shift
+   largeWordXor = xor
+   largeBitSize = bitSize
+
+-- Word64 is a key in the obvious way.
+
+instance LargeWord Word64 where
+   largeWordToInteger = toInteger
+   integerToLargeWord = fromInteger
+   largeWordPlus = (+)
+   largeWordAnd = (.&.)
+   largeWordOr = (.|.)
+   largeWordShift = shift
+   largeWordXor = xor
+   largeBitSize = bitSize
+
+-- Define larger keys from smaller ones.
+
+data LargeKey a b = LargeKey a b
+   deriving (Eq, Ord)
+
+{-# INLINE loHalf #-}
+loHalf (LargeKey a b) = a
+{-# INLINE hiHalf #-}
+hiHalf (LargeKey a b) = b
+
+instance (Ord a, Bits a, LargeWord a, Bits b, LargeWord b) =>
+   LargeWord (LargeKey a b) where
+      largeWordToInteger (LargeKey lo hi) =
+         largeWordToInteger lo + (2^(bitSize lo)) * largeWordToInteger hi
+      integerToLargeWord x =
+         let (h,l) =  x `quotRem` (2^(bitSize lo))
+             (lo,hi) = (integerToLargeWord l, integerToLargeWord h) in
+                LargeKey lo hi
+      largeWordPlus (LargeKey alo ahi) (LargeKey blo bhi) =
+         LargeKey lo' hi' where
+            lo' = alo + blo
+            hi' = ahi + bhi + if lo' < alo then 1 else 0
+      largeWordAnd (LargeKey alo ahi) (LargeKey blo bhi) =
+         LargeKey lo' hi' where
+            lo' = alo .&. blo
+            hi' = ahi .&. bhi
+      largeWordOr (LargeKey alo ahi) (LargeKey blo bhi) =
+         LargeKey lo' hi' where
+            lo' = alo .|. blo
+            hi' = ahi .|. bhi
+      largeWordXor (LargeKey alo ahi) (LargeKey blo bhi) =
+         LargeKey lo' hi' where
+            lo' = alo `xor` blo
+            hi' = ahi `xor` bhi
+      largeWordShift w 0 = w
+      largeWordShift (LargeKey lo hi) x =
+         if bitSize lo < bitSize hi
+            then LargeKey (shift lo x) 
+                          (shift hi x .|. (shift (conv lo) (x - (bitSize lo))))
+            else LargeKey (shift lo x)
+                          (shift hi x .|. (conv $ shift lo (x - (bitSize lo))))
+         where conv = integerToLargeWord . largeWordToInteger
+      largeBitSize ~(LargeKey lo hi) = largeBitSize lo + largeBitSize hi
+
+instance (Ord a, Bits a, LargeWord a, Bits b, LargeWord b) => Show (LargeKey a b) where
+   showsPrec p = showInt . largeWordToInteger
+
+instance (Ord a, Bits a, LargeWord a, Bits b, LargeWord b) => 
+   Num (LargeKey a b) where
+      (+) = largeWordPlus
+      fromInteger = integerToLargeWord 
+
+-- Larger keys are instances of Bits provided their constituents are keys.
+
+instance (Ord a, Bits a, LargeWord a, Bits b, LargeWord b) => 
+   Bits (LargeKey a b) where
+      (.&.) = largeWordAnd
+      (.|.) = largeWordOr
+      xor = largeWordXor
+      shift = largeWordShift
+      bitSize = largeBitSize
+
+instance (Ord a, Bits a, Bounded a, Integral a, LargeWord a, 
+                 Bits b, Bounded b, Integral b, LargeWord b) => 
+   Bounded (LargeKey a b) where
+      minBound = 0
+      maxBound =
+         result where
+            result =
+               fromIntegral $
+               (1 + fromIntegral (maxBound `asTypeOf` (boflk result)))*
+                  (1 + fromIntegral (maxBound `asTypeOf` (aoflk result))) - 1
+
+aoflk :: (LargeKey a b) -> a
+aoflk = undefined
+boflk :: (LargeKey a b) -> b
+boflk = undefined
+
+instance (Ord a, Bits a, LargeWord a, Ord b, Bits b, LargeWord b) =>
+   Integral (LargeKey a b) where
+      toInteger = largeWordToInteger
+
+instance (Ord a, Bits a, LargeWord a, Ord b, Bits b, LargeWord b) =>
+   Real (LargeKey a b)
+
+instance Enum (LargeKey a b)
+
+type Word96  = LargeKey Word32 Word64
+type Word128 = LargeKey Word64 Word64
+type Word160 = LargeKey Word32 Word128
+type Word192 = LargeKey Word64 Word128
+type Word224 = LargeKey Word32 Word192
+type Word256 = LargeKey Word64 Word192
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,38 @@
+
+The haskell source code in this package is licensed under a BSD3 license (listed below).
+
+Note, right now this package also includes a copy of just a few files
+from Dominic Steinitz's Crypto library.  This is hopefully temporary
+-- a minor API change is the only reason for the duplication.
+However, I verified that the included files ALSO have a BSD license.
+
+-Ryan Newton
+
+
+BSD3 Full Text:
+--------------------------------------------------------------------------------
+
+Copyright (c) <year>, <copyright holder>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * 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.
+    * Neither the name of the <organization> nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 <COPYRIGHT HOLDER> 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,157 @@
+#!/usr/bin/env runhaskell
+import Distribution.Simple
+
+import Distribution.Simple.UserHooks
+import Distribution.Simple.PreProcess
+import Distribution.Simple.Setup
+import Distribution.PackageDescription	
+import Distribution.Simple.LocalBuildInfo	
+import System.Cmd(system) 
+import System.Exit
+import qualified System.Info as Info
+import System.IO.Unsafe
+import System.Directory
+import Data.Maybe
+import Data.List
+import Data.IORef
+import Debug.Trace
+
+main = do
+  putStrLn$ "  [intel-aes] Running Setup.hs..."
+
+  defaultMainWithHooks $
+   simpleUserHooks 
+    { postConf  = my_postConf
+    , confHook  = my_conf
+    , preBuild  = my_preBuild
+    , buildHook = my_build
+    , instHook  = my_install
+    , cleanHook = my_clean
+    }
+
+-- A file will be our global variable:
+tmpfile = ".temp.install_dir.txt"
+
+--------------------------------------------------------------------------------
+my_clean :: PackageDescription -> () -> UserHooks -> CleanFlags -> IO ()
+my_clean desc () hooks flags = do 
+  putStrLn$ "\n  [intel-aes] Running external clean via Makefile"
+  setCurrentDirectory "./cbits/"
+  system "make clean"
+  setCurrentDirectory ".."
+  putStrLn$ "  [intel-aes] Done.  Now running normal cabal clean action.\n"
+  (cleanHook simpleUserHooks) desc () hooks flags
+
+--------------------------------------------------------------------------------
+my_conf :: (GenericPackageDescription, HookedBuildInfo) -> ConfigFlags -> IO LocalBuildInfo
+my_conf (gpd,hbi) flags = do 
+  (confHook simpleUserHooks) (gpd,hbi) flags
+
+--------------------------------------------------------------------------------
+-- we override postConf to keep it from complaining about a missing library:
+my_postConf :: Args -> ConfigFlags -> PackageDescription -> LocalBuildInfo -> IO ()
+my_postConf args conf desc localinfo = do
+  let buildinfos = allBuildInfo desc
+      desc2 = stripDesc desc
+  putStrLn$ "  [intel-aes] Extra libraries initially: "++ show (map extraLibs buildinfos)
+  putStrLn$ "  [intel-aes] Stripped extra libraries to: "++ show (map extraLibs $ allBuildInfo desc2)
+
+  desc3 <- patchDesc desc2 localinfo
+  -- Now call the default hook with a stripped down version:
+  (postConf simpleUserHooks) args conf desc3 localinfo
+
+
+--------------------------------------------------------------------------------
+-- Patch a package description for our quirky builda:
+patchDesc desc localinfo = do
+  let libd  = libdir$ absoluteInstallDirs desc localinfo NoCopyDest
+  -- This is lame but I'm not sure how to get the same information at the preBuild step.
+  -- writeIORef global_var_hack libd
+  putStrLn$ "  [intel-aes] Determined install dir to be: " ++ show libd 
+  writeFile tmpfile libd
+  putStrLn$ "  [intel-aes] Recorded install dir in " ++ show tmpfile
+ 
+  root <- getCurrentDirectory
+  -- Let's try a friendlier way to change the options:
+  let Just lib = library desc
+      lbi  = libBuildInfo lib 
+      oldO = ldOptions  lbi
+      -- I'm not sure what the best policy is.  For now I'm adding
+      -- BOTH the build dir and the eventual install dir...
+      -- This will allow the package to function when it is built-but-not-installed.
+      newO = ("-Wl,-rpath=" ++ libd) : 
+	     ("-Wl,-rpath=" ++ cbitsd) : 
+	     oldO
+      cbitsd = root++"/cbits/"
+      newlbi = lbi { ldOptions = newO 
+		   , extraLibDirs = cbitsd : extraLibDirs lbi }
+      -- Whew... nested record updates are painful:
+      desc3 = desc { library = Just (lib { libBuildInfo = newlbi})}
+
+  putStrLn$ "  [intel-aes] Modified package info. " 
+  return desc3
+
+
+----------------------------------------
+-- Strip out the special extra-libraries: entry
+stripDesc desc = 
+       desc { library     = fmap stripLib (library desc) 
+  	    , executables = map  stripExe (executables desc)
+	    }
+stripLib lib = lib { libBuildInfo = stripBI (libBuildInfo lib) }
+stripExe exe = exe { buildInfo = stripBI (buildInfo exe) }
+stripBI bi   = bi  { extraLibs = filter filt (extraLibs bi) }
+
+filt str = not (isInfixOf "intel_aes" str)
+
+------------------------------------------------------------
+my_preBuild :: Args -> BuildFlags -> IO HookedBuildInfo
+my_preBuild args flags = do 
+  putStrLn$ "\n================================================================================"
+  let 
+      ext = case Info.os of 
+	      "linux"   -> ".so"
+	      "mac"     -> ".dylib"
+	      "windows" -> ".dll"
+	      _         -> error$ "Unexpected "
+      cached_so = "./cbits/prebuilt/libintel_aes_"++ Info.os ++"_"++ Info.arch ++ ext
+      dest = "./cbits/libintel_aes"++ext
+  e <- doesFileExist cached_so
+  if e then do 
+      putStrLn$ "  [intel-aes] Using prebuilt dynamic library: "++ cached_so
+      copyFile cached_so dest
+      putStrLn$ "  [intel-aes] Done copying into position: "++ dest
+  else do     
+      putStrLn$ "  [intel-aes] Running Makefile to build C/asm source..."
+      rootdir <- getCurrentDirectory 
+      setCurrentDirectory "./cbits/"
+      system "make"
+      setCurrentDirectory rootdir
+      putStrLn$ "  [intel-aes] Done with external build job."
+  putStrLn$ "================================================================================\n"
+
+  (preBuild simpleUserHooks) args flags
+
+--------------------------------------------------------------------------------
+my_build :: PackageDescription -> LocalBuildInfo -> UserHooks -> BuildFlags -> IO ()
+my_build desc linfo hooks flags = do 
+  putStrLn$ "  [intel-aes] Build action started."
+  desc2 <- patchDesc desc linfo
+  (buildHook simpleUserHooks) desc2 linfo hooks flags
+  putStrLn$ "  [intel-aes] Build action finished.\n\n"
+
+--------------------------------------------------------------------------------
+my_install :: PackageDescription -> LocalBuildInfo -> UserHooks -> InstallFlags -> IO ()
+my_install desc linfo hooks flags = do 
+  putStrLn$ "  [intel-aes] Install action:"
+  putStrLn$ "\n================================================================================"
+  desc2 <- patchDesc desc linfo
+  libd <- readFile tmpfile 
+  let dest = (libd ++ "/libintel_aes.so")
+  putStrLn$ "  [intel-aes] Copying shared library to: " ++ show dest
+  system$ "mkdir -p "++ libd -- NONPORTABLE
+  copyFile "./cbits/libintel_aes.so" dest
+  putStrLn$ "  [intel-aes] Done copying."
+  -- removeFile tmpfile -- Might install more than once, right?
+  putStrLn$ "================================================================================\n"
+  (instHook simpleUserHooks) desc2 linfo hooks flags
diff --git a/SimpleRNGBench.hs b/SimpleRNGBench.hs
new file mode 100644
--- /dev/null
+++ b/SimpleRNGBench.hs
@@ -0,0 +1,363 @@
+#!/usr/bin/env runhaskell
+{-# LANGUAGE BangPatterns, ScopedTypeVariables, ForeignFunctionInterface #-}
+-- | A simple script to do some very basic timing of the RNGs.
+
+--   It is important that we also run established stastical tests on
+--   these RNGs a some point...
+
+module Main where
+
+import qualified Codec.Encryption.BurtonRNGSlow as BS
+
+--import qualified Codec.Crypto.IntelAES.GladmanAES  as GA
+import qualified Codec.Crypto.GladmanAES           as GA
+import qualified Codec.Crypto.IntelAES.AESNI       as NI
+import qualified Codec.Crypto.IntelAES             as IA
+import qualified Codec.Crypto.ConvertRNG           as CR
+-- import qualified Codec.Crypto.AES.Random        as Svein
+
+import System.Exit (exitSuccess, exitFailure)
+import System.Environment
+import System.Random
+import System.Posix    (sleep)
+import System.CPUTime  (getCPUTime)
+-- import Data.Time.Clock (diffUTCTime)
+import System.CPUTime.Rdtsc
+import System.Console.GetOpt
+
+import GHC.Conc
+import Control.Concurrent
+import Control.Monad 
+import Control.Concurrent.Chan
+import Control.Exception
+
+import Crypto.Random (CryptoRandomGen(..))
+
+import Data.IORef
+import Data.List
+import Data.Int
+import Data.Word
+import Data.List.Split
+import Data.Serialize
+import qualified Data.ByteString as B
+import Text.Printf
+
+import Foreign.Ptr
+import Foreign.ForeignPtr
+import Foreign.Storable (peek,poke)
+
+import Benchmark.BinSearch
+
+----------------------------------------------------------------------------------------------------
+-- TEMP: MOVE ME ELSEWHERE:
+
+mkAESGen_gladman :: Int -> CR.CRGtoRG (CR.BCtoCRG (GA.AES GA.N128))
+mkAESGen_gladman int = CR.convertCRG gen
+ where
+  Right (gen :: CR.BCtoCRG (GA.AES GA.N128)) = newGen (B.append halfseed halfseed )
+  halfseed = encode word64
+  word64 = fromIntegral int :: Word64
+
+
+mkAESGen_gladman0 :: Int -> CR.CRGtoRG0 (CR.BCtoCRG (GA.AES GA.N128))
+mkAESGen_gladman0 int = CR.CRGtoRG0 gen
+ where
+  Right (gen :: CR.BCtoCRG (GA.AES GA.N128)) = newGen (B.append halfseed halfseed )
+  halfseed = encode word64
+  word64 = fromIntegral int :: Word64
+
+
+----------------------------------------------------------------------------------------------------
+-- Miscellaneous helpers:
+
+-- I cannot *believe* there is not a standard call or an
+-- easily-findable hackage library supporting locale-based printing of
+-- numbers. [2011.01.28]
+commaint :: Integral a => a -> String
+commaint n = 
+   reverse $
+   concat $
+   intersperse "," $ 
+   chunk 3 $ 
+   reverse (show n)
+
+padleft n str | length str >= n = str
+padleft n str | otherwise       = take (n - length str) (repeat ' ') ++ str
+
+padright n str | length str >= n = str
+padright n str | otherwise       = str ++ take (n - length str) (repeat ' ')
+
+fmt_num n = if n < 100 
+	    then printf "%.2f" n
+	    else commaint (round n)
+
+-- WARNING! This is not actually good enough.  Even if we use forkOS
+-- we would have to go further and pin the OS thread (e.g. in linux)
+-- to keep the OS from waking up the process on a different core.
+measure_freq :: IO Int64
+measure_freq = do 
+   -- We measure the clock frequency on a bound thread.
+   -- Otherwise we can get really screwy results from rdtsc if we
+   -- migrate physical threads when we sleep or threadDelay.
+   tmpchan <- newChan
+   forkOS $ do 
+      t1 <- rdtsc
+      -- sleep 1
+      threadDelay (1000*1000)
+      t2 <- rdtsc
+      -- Just to be careful let's make sure this doesn't happen (this was how I found the problem before forkOS):
+      when (t2 < t1) $ 
+        putStrLn$ "WARNING: rdtsc not monotonically increasing, first "++show t1++" then "++show t2++" on the same OS thread"
+      writeChan tmpchan (if t2>t1 then t2-t1 else t1-t2)
+   freq <- readChan tmpchan
+   return (fromIntegral freq)
+
+-- This version simply busy-waits to stay on the same core:
+-- WOW! I'm STILL experiencing the non-monotonic rdtsc, even when not compiled with -threaded.
+-- It can't be overflow can it?  The counter should be 64 bit...
+--
+-- UPDATE: [2011.01.28] This was a bug in the rdtsc package that dropping the precision to 32 bits.
+measure_freq2 :: IO Int64
+measure_freq2 = do 
+  let second = 1000 * 1000 * 1000 * 1000 -- picoseconds are annoying
+  t1 <- rdtsc 
+  start <- getCPUTime
+  let loop !n !last = 
+       do t2 <- rdtsc 
+	  when (t2 < last) $
+	       putStrLn$ "COUNTERS WRAPPED "++ show (last,t2) 
+	  cput <- getCPUTime		
+	  if (cput - start < second) 
+	   then loop (n+1) t2
+	   else return (n,t2)
+  (n,t2) <- loop 0 t1
+  putStrLn$ "  Approx getCPUTime calls per second: "++ commaint n
+  when (t2 < t1) $ 
+    putStrLn$ "WARNING: rdtsc not monotonically increasing, first "++show t1++" then "++show t2++" on the same OS thread"
+
+  return$ fromIntegral (t2 - t1)
+
+----------------------------------------------------------------------------------------------------
+-- Drivers to get random numbers repeatedly.
+
+incr !counter = 
+  do -- modifyIORef counter (+1)d
+     -- Incrementing counter strictly (avoiding stack overflow) is annoying:
+     c <- readIORef counter
+     let c' = c+1
+     evaluate c'
+     writeIORef counter c'     
+
+loop :: RandomGen g => IORef Int -> (Int,g) -> IO b
+loop !counter !(!n,!g) = 
+  do incr counter
+--     putStr (show n); putChar ' '
+     loop counter (next g)
+
+data NoopRNG = NoopRNG
+instance RandomGen NoopRNG where 
+  split g = (g,g)
+  next g  = (0,g)
+
+--foreign import ccall "cbits/c_test.c" blast_rands :: Ptr Int -> Ptr Int -> IO ()
+
+type Kern = Int -> Ptr Int -> IO ()
+
+-- [2011.01.28] Changing this to take "count" and "accumulator ptr" as arguments:
+foreign import ccall "cbits/c_test.c" blast_rands :: Kern
+foreign import ccall "cbits/c_test.c" store_loop  :: Kern
+foreign import ccall unsafe "stdlib.hs" rand :: IO Int
+
+loop2 :: IORef Int -> IO ()
+loop2 !counter = 
+  do incr counter
+     n <- rand
+     loop2 counter 
+
+
+----------------------------------------------------------------------------------------------------
+-- Timing:
+
+timeit numthreads freq msg mkgen =
+  do 
+     counters <- forM [1..numthreads] (const$ newIORef 1) 
+     tids <- forM counters $ \counter -> 
+	        forkIO $ loop counter (next$ mkgen 23852358661234)   
+     threadDelay (1000*1000) -- One second
+     mapM_ killThread tids
+
+     finals <- mapM readIORef counters
+     let mean :: Double = fromIntegral (foldl1 (+) finals) / fromIntegral numthreads
+         cycles_per :: Double = fromIntegral freq / mean
+     print_result (round mean) msg cycles_per
+
+print_result total msg cycles_per = 
+     putStrLn$ "    "++ padleft 11 (commaint total) ++" random ints generated "++ padright 27 ("["++msg++"]") ++" ~ "
+	       ++ fmt_num cycles_per ++" cycles/int"
+
+
+-- FIXME: This isn't working yet because when the C call goes into a tight infinite loop killThread hangs...
+-- KEEPING AROUND ONLY FOR FUTURE INVESTIGATION
+------------------------------------------------------------
+time_c :: Int -> Int64 -> (Ptr Int -> Ptr Int -> IO ()) -> IO Int
+time_c numthreads freq ffn = do 
+  counter :: ForeignPtr Int <- mallocForeignPtr
+  sum     :: ForeignPtr Int <- mallocForeignPtr
+  tid <- forkOS $ 
+	 withForeignPtr counter $ \ cntr ->
+	 withForeignPtr sum $ \ sm ->
+          ffn cntr sm
+  threadDelay (1000*1000) -- One second
+  stat <- threadStatus tid
+  putStrLn$ "Thread making foreign call's status: "++ show stat
+  putStrLn$ "Killing thread running the foreign C call...\n"
+  killThread tid -- This will hang!!!
+  putStrLn$ "Killed.\n"
+  total <- withForeignPtr counter peek 
+  putStrLn$ "Got total: " ++ show total
+  return total
+------------------------------------------------------------
+
+
+-- This version flips things around, and assume something about the
+-- timing so that we can run a fixed number of randoms and time it.
+-- (We could do binary search here.)
+time_c2 :: Int -> Int64 -> String -> (Int -> Ptr Int -> IO ()) -> IO Int
+time_c2 numthreads freq msg ffn = do 
+  ptr     :: ForeignPtr Int <- mallocForeignPtr
+
+  let kern = if numthreads == 1
+	     then ffn
+	     else replicate_kernel numthreads ffn 
+      wrapped n = withForeignPtr ptr (kern$ fromIntegral n)
+  (n,t) <- binSearch False 1 (1.0, 1.05) wrapped
+
+  -- ONLY if we're in multi-threaded mode do we then run again with
+  -- that input size on all threads:
+----------------------------------------
+-- NOTE, this approach is TOO SLOW.  For workloads that take a massive
+-- parallel slowdown it doesn't make sense to use the same input size
+-- in serial and in parallel.
+-- DISABLING:
+{-
+  (n2,t2) <- 
+    if numthreads > 1 then do
+      ptrs <- mapM (const mallocForeignPtr) [1..numthreads]
+      tmpchan <- newChan
+      putStrLn$ "       [forking threads for multithreaded measurement, input size "++ show n++"]"
+      start <- getCPUTime
+      tids <- forM ptrs $ \ptr -> forkIO $ 
+	       do withForeignPtr ptr (ffn$ fromIntegral n)
+		  writeChan tmpchan ()     
+      forM ptrs $ \_ -> readChan tmpchan
+      end <- getCPUTime
+      let t2 :: Double = fromIntegral (end-start) / 1000000000000.0
+      putStrLn$ "       [joined threads, time "++ show t2 ++"]"
+      return (n * fromIntegral numthreads, t2)
+    else do 
+      return (n,t)
+-}
+----------------------------------------
+
+  let total_per_second = round $ fromIntegral n * (1 / t)
+      cycles_per = fromIntegral freq * t / fromIntegral n
+  print_result total_per_second msg cycles_per
+  return total_per_second
+
+-- This lifts the C kernel to operate 
+replicate_kernel :: Int -> Kern -> Kern
+replicate_kernel numthreads kern n ptr = do
+  ptrs <- forM [1..numthreads]
+	    (const mallocForeignPtr) 
+  tmpchan <- newChan
+  -- let childwork = ceiling$ fromIntegral n / fromIntegral numthreads
+  let childwork = n -- Keep it the same.. interested in per-thread throughput.
+  -- Fork/join pattern:
+  tids <- forM ptrs $ \ptr -> forkIO $ 
+	   withForeignPtr ptr $ \p -> do
+	      kern (fromIntegral childwork) p
+	      result <- peek p
+	      writeChan tmpchan result
+
+  results <- forM [1..numthreads] $ \_ -> 
+	       readChan tmpchan
+  -- Meaningless semantics here... sum the child ptrs and write to the input one:
+  poke ptr (foldl1 (+) results)
+  return ()
+
+----------------------------------------------------------------------------------------------------
+-- Main Script
+
+data Flag = NoC | Help | Test
+  deriving (Show, Eq)
+
+options = 
+   [ Option ['h']  ["help"]  (NoArg Help)  "print program help"
+   , Option []     ["noC"]   (NoArg NoC)   "omit C benchmarks, haskell only"
+   , Option ['t']  ["test"]  (NoArg Test)  "run some basic tests"
+   ]
+
+  
+main = do 
+   argv <- getArgs
+   let (opts,_,other) = getOpt Permute options argv
+
+   when (Test `elem` opts)$ do
+       IA.testIntelAES
+       NI.testAESNI
+       exitSuccess
+
+   when (not$ null other) $ do
+       putStrLn$ "ERROR: Unrecognized options: " 
+       mapM_ putStr other
+       exitFailure
+
+   when (Help `elem` opts) $ do
+       putStr$ usageInfo "Benchmark random number generation" options
+       exitSuccess
+
+   putStrLn$ "\nHow many random numbers can we generate in a second on one thread?"
+
+   t1 <- rdtsc
+   t2 <- rdtsc
+   putStrLn ("  Cost of rdtsc (ffi call):    " ++ show (t2 - t1))
+
+   freq <- measure_freq2
+   putStrLn$ "  Approx clock frequency:  " ++ commaint freq
+
+--   svein <- Svein.newAESGen
+
+   let gamut th = do
+       putStrLn$ "  First, timing with System.Random interface:"
+       timeit th freq "constant zero gen" (const NoopRNG)
+       timeit th freq "System.Random stdGen" mkStdGen
+       timeit th freq "PureHaskell/reference" BS.mkBurtonGen_reference
+       timeit th freq "PureHaskell"           BS.mkBurtonGen
+--       timeit th freq "Gladman inefficient"     GA.mkAESGen0
+--       timeit th freq "Gladman"                 GA.mkAESGen
+       timeit th freq "Gladman inefficient"     mkAESGen_gladman0
+       timeit th freq "Gladman"                 mkAESGen_gladman
+       timeit th freq "Compound gladman/intel"  IA.mkAESGen
+--       timeit th freq "Svein's Gladman package" (const svein)
+       timeit th freq "IntelAES inefficient"    NI.mkAESGen0
+       timeit th freq "IntelAES"                NI.mkAESGen
+
+
+       when (not$ NoC `elem` opts) $ do
+	  putStrLn$ "  Comparison to C's rand():"
+	  time_c2 th freq "ptr store in C loop"   store_loop
+	  time_c2 th freq "rand/store in C loop"  blast_rands
+	  time_c2 th freq "rand in Haskell loop" (\n ptr -> forM_ [1..n]$ \_ -> rand )
+	  time_c2 th freq "rand/store in Haskell loop"  (\n ptr -> forM_ [1..n]$ \_ -> do n <- rand; poke ptr n )
+	  return ()
+          -- timeit 1 freq "rand / Haskell loop" mkBurtonGen
+
+   gamut 1
+
+   when (numCapabilities > 1) $ do 
+--   when (False) $ do 
+       putStrLn$ "\nNow "++ show numCapabilities ++" threads, reporting mean randoms-per-second-per-thread:"
+       gamut numCapabilities
+       return ()
+
+   putStrLn$ "Finished."
diff --git a/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/Makefile b/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/Makefile
new file mode 100644
--- /dev/null
+++ b/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/Makefile
@@ -0,0 +1,48 @@
+
+UNAME=$(shell uname -m)
+
+# Must be 86 (for 32bit compiler) or 64 (for 64bit compiler)
+ARCH=64
+# Must be 32 or 64:
+SZ=64
+
+STATIC=lib/x$(ARCH)/libintel_aes.a
+DYNAMIC=lib/x$(ARCH)/libintel_aes.so
+
+SRC= src/intel_aes.c \
+     asm/x$(ARCH)/iaesx$(ARCH).s \
+     asm/x$(ARCH)/do_rdtsc.s
+
+OBJ= obj/x$(ARCH)/intel_aes.o \
+     obj/x$(ARCH)/iaesx$(ARCH).o \
+     obj/x$(ARCH)/do_rdtsc.o
+
+GCC=gcc
+YASM=yasm
+YASMFLAGS= -D__linux__ -g dwarf2 -f elf$(SZ) 
+
+all: $(STATIC) $(DYNAMIC)
+	cp lib/x$(ARCH)/* ../../
+
+$(STATIC): $(OBJ)
+	@mkdir -p lib/x$(ARCH)
+	ar -r $@ $(OBJ)
+
+$(DYNAMIC): $(OBJ)
+	@mkdir -p lib/x$(ARCH)
+	$(GCC) -shared -dynamic  -o $(DYNAMIC) $(OBJ)
+
+obj/x$(ARCH)/do_rdtsc.o:  asm/x$(ARCH)/do_rdtsc.s
+	@mkdir -p obj/x$(ARCH)
+	$(YASM) $(YASMFLAGS) $< -o $@
+
+obj/x$(ARCH)/iaesx$(ARCH).o:  asm/x$(ARCH)/iaesx$(ARCH).s
+	@mkdir -p obj/x$(ARCH)
+	$(YASM) $(YASMFLAGS) $< -o $@
+
+obj/x$(ARCH)/intel_aes.o:  src/intel_aes.c
+	@mkdir -p obj/x$(ARCH)
+	$(GCC) -fPIC -O3 -g -Iinclude/ -c $< -o $@
+
+clean:
+	rm -f $(STATIC) $(DYNAMIC) $(OBJ)
diff --git a/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/asm/x64/do_rdtsc.s b/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/asm/x64/do_rdtsc.s
new file mode 100644
--- /dev/null
+++ b/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/asm/x64/do_rdtsc.s
@@ -0,0 +1,37 @@
+[bits 64]
+[CPU intelnop]
+
+; Copyright (c) 2010, Intel Corporation
+; All rights reserved.
+; 
+; Redistribution and use in source and binary forms, with or without 
+; modification, are permitted provided that the following conditions are met:
+; 
+;     * Redistributions of source code must retain the above copyright notice, 
+;       this list of conditions and the following disclaimer.
+;     * 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.
+;     * Neither the name of Intel Corporation nor the names of its contributors 
+;       may be used to endorse or promote products derived from this software 
+;       without specific prior written permission.
+; 
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+
+align 16
+global do_rdtsc
+do_rdtsc:
+
+	rdtsc
+	shl rdx, 32
+	or  rax, rdx
+	ret	0
diff --git a/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/asm/x64/iaesx64.s b/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/asm/x64/iaesx64.s
new file mode 100644
--- /dev/null
+++ b/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/asm/x64/iaesx64.s
@@ -0,0 +1,2054 @@
+[bits 64]
+[CPU intelnop]
+
+; Copyright (c) 2010, Intel Corporation
+; All rights reserved.
+; 
+; Redistribution and use in source and binary forms, with or without 
+; modification, are permitted provided that the following conditions are met:
+; 
+;     * Redistributions of source code must retain the above copyright notice, 
+;       this list of conditions and the following disclaimer.
+;     * 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.
+;     * Neither the name of Intel Corporation nor the names of its contributors 
+;       may be used to endorse or promote products derived from this software 
+;       without specific prior written permission.
+; 
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+
+%macro linux_setup 0
+%ifdef __linux__
+	mov rcx, rdi
+	mov rdx, rsi
+%endif
+%endmacro
+
+%macro inversekey 1
+	movdqu  xmm1,%1
+	aesimc	xmm0,xmm1
+	movdqu	%1,xmm0
+%endmacro
+
+%macro aesdeclast1 1
+	aesdeclast	xmm0,%1
+%endmacro
+
+%macro aesenclast1 1
+	aesenclast	xmm0,%1
+%endmacro
+
+%macro aesdec1 1
+	aesdec	xmm0,%1
+%endmacro
+
+%macro aesenc1 1
+	aesenc	xmm0,%1
+%endmacro
+
+
+%macro aesdeclast1_u 1
+	movdqu xmm4,%1
+	aesdeclast	xmm0,xmm4
+%endmacro
+
+%macro aesenclast1_u 1
+	movdqu xmm4,%1
+	aesenclast	xmm0,xmm4
+%endmacro
+
+%macro aesdec1_u 1
+	movdqu xmm4,%1
+	aesdec	xmm0,xmm4
+%endmacro
+
+%macro aesenc1_u 1
+	movdqu xmm4,%1
+	aesenc	xmm0,xmm4
+%endmacro
+ 
+%macro aesdec4 1
+	movdqa	xmm4,%1
+
+	aesdec	xmm0,xmm4
+	aesdec	xmm1,xmm4
+	aesdec	xmm2,xmm4
+	aesdec	xmm3,xmm4
+
+%endmacro
+
+%macro aesdeclast4 1
+	movdqa	xmm4,%1
+
+	aesdeclast	xmm0,xmm4
+	aesdeclast	xmm1,xmm4
+	aesdeclast	xmm2,xmm4
+	aesdeclast	xmm3,xmm4
+
+%endmacro
+
+
+%macro aesenc4 1
+	movdqa	xmm4,%1
+
+	aesenc	xmm0,xmm4
+	aesenc	xmm1,xmm4
+	aesenc	xmm2,xmm4
+	aesenc	xmm3,xmm4
+
+%endmacro
+
+%macro aesenclast4 1
+	movdqa	xmm4,%1
+
+	aesenclast	xmm0,xmm4
+	aesenclast	xmm1,xmm4
+	aesenclast	xmm2,xmm4
+	aesenclast	xmm3,xmm4
+
+%endmacro
+
+
+%macro load_and_inc4 1
+	movdqa	xmm4,%1
+	movdqa	xmm0,xmm5
+	movdqa  xmm1,xmm5
+	paddq	xmm1,[counter_add_one wrt rip]
+	movdqa  xmm2,xmm5
+	paddq	xmm2,[counter_add_two wrt rip]
+	movdqa  xmm3,xmm5
+	paddq	xmm3,[counter_add_three wrt rip]
+	pxor	xmm0,xmm4
+	paddq	xmm5,[counter_add_four wrt rip]
+	pxor	xmm1,xmm4
+	pxor	xmm2,xmm4
+	pxor	xmm3,xmm4
+%endmacro
+
+%macro xor_with_input4 1
+	movdqu xmm4,[%1]
+	pxor xmm0,xmm4
+	movdqu xmm4,[%1+16]
+	pxor xmm1,xmm4
+	movdqu xmm4,[%1+32]
+	pxor xmm2,xmm4
+	movdqu xmm4,[%1+48]
+	pxor xmm3,xmm4
+%endmacro
+
+
+
+%macro load_and_xor4 2
+	movdqa	xmm4,%2
+	movdqu	xmm0,[%1 + 0*16]
+	pxor	xmm0,xmm4
+	movdqu	xmm1,[%1 + 1*16]
+	pxor	xmm1,xmm4
+	movdqu	xmm2,[%1 + 2*16]
+	pxor	xmm2,xmm4
+	movdqu	xmm3,[%1 + 3*16]
+	pxor	xmm3,xmm4
+%endmacro
+
+%macro store4 1
+	movdqu [%1 + 0*16],xmm0
+	movdqu [%1 + 1*16],xmm1
+	movdqu [%1 + 2*16],xmm2
+	movdqu [%1 + 3*16],xmm3
+%endmacro
+
+%macro copy_round_keys 3
+	movdqu xmm4,[%2 + ((%3)*16)]
+	movdqa [%1 + ((%3)*16)],xmm4
+%endmacro
+
+
+%macro key_expansion_1_192 1
+		;; Assumes the xmm3 includes all zeros at this point. 
+        pshufd xmm2, xmm2, 11111111b        
+        shufps xmm3, xmm1, 00010000b        
+        pxor xmm1, xmm3        
+        shufps xmm3, xmm1, 10001100b
+        pxor xmm1, xmm3        
+		pxor xmm1, xmm2		
+		movdqu [rdx+%1], xmm1			
+%endmacro
+
+; Calculate w10 and w11 using calculated w9 and known w4-w5
+%macro key_expansion_2_192 1				
+		movdqa xmm5, xmm4
+		pslldq xmm5, 4
+		shufps xmm6, xmm1, 11110000b
+		pxor xmm6, xmm5
+		pxor xmm4, xmm6
+		pshufd xmm7, xmm4, 00001110b 
+		movdqu [rdx+%1], xmm7
+%endmacro
+
+
+section .data
+align 16
+shuffle_mask:
+DD 0FFFFFFFFh
+DD 03020100h
+DD 07060504h
+DD 0B0A0908h
+
+
+align 16
+counter_add_one:
+DD 1
+DD 0
+DD 0
+DD 0
+
+counter_add_two:
+DD 2
+DD 0
+DD 0
+DD 0
+
+counter_add_three:
+DD 3
+DD 0
+DD 0
+DD 0
+
+counter_add_four:
+DD 4
+DD 0
+DD 0
+DD 0
+
+
+
+section .text
+
+align 16
+key_expansion256:
+
+    pshufd xmm2, xmm2, 011111111b
+
+    movdqa xmm4, xmm1
+    pshufb xmm4, xmm5
+    pxor xmm1, xmm4
+    pshufb xmm4, xmm5
+    pxor xmm1, xmm4
+    pshufb xmm4, xmm5
+    pxor xmm1, xmm4
+    pxor xmm1, xmm2
+
+    movdqu [rdx], xmm1
+    add rdx, 0x10
+    
+    aeskeygenassist xmm4, xmm1, 0
+    pshufd xmm2, xmm4, 010101010b
+
+    movdqa xmm4, xmm3
+    pshufb xmm4, xmm5
+    pxor xmm3, xmm4
+    pshufb xmm4, xmm5
+    pxor xmm3, xmm4
+    pshufb xmm4, xmm5
+    pxor xmm3, xmm4
+    pxor xmm3, xmm2
+
+    movdqu [rdx], xmm3
+    add rdx, 0x10
+
+    ret
+
+
+
+align 16
+key_expansion128: 
+    pshufd xmm2, xmm2, 0xFF;
+    movdqa xmm3, xmm1
+    pshufb xmm3, xmm5
+    pxor xmm1, xmm3
+    pshufb xmm3, xmm5
+    pxor xmm1, xmm3
+    pshufb xmm3, xmm5
+    pxor xmm1, xmm3
+    pxor xmm1, xmm2
+
+    ; storing the result in the key schedule array
+    movdqu [rdx], xmm1
+    add rdx, 0x10                    
+    ret
+
+
+
+
+
+
+align 16
+global iEncExpandKey128
+iEncExpandKey128:
+
+		linux_setup
+
+        movdqu xmm1, [rcx]    ; loading the key
+
+        movdqu [rdx], xmm1
+
+        movdqa xmm5, [shuffle_mask wrt rip]
+
+        add rdx,16
+
+        aeskeygenassist xmm2, xmm1, 0x1     ; Generating round key 1
+        call key_expansion128
+        aeskeygenassist xmm2, xmm1, 0x2     ; Generating round key 2
+        call key_expansion128
+        aeskeygenassist xmm2, xmm1, 0x4     ; Generating round key 3
+        call key_expansion128
+        aeskeygenassist xmm2, xmm1, 0x8     ; Generating round key 4
+        call key_expansion128
+        aeskeygenassist xmm2, xmm1, 0x10    ; Generating round key 5
+        call key_expansion128
+        aeskeygenassist xmm2, xmm1, 0x20    ; Generating round key 6
+        call key_expansion128
+        aeskeygenassist xmm2, xmm1, 0x40    ; Generating round key 7
+        call key_expansion128
+        aeskeygenassist xmm2, xmm1, 0x80    ; Generating round key 8
+        call key_expansion128
+        aeskeygenassist xmm2, xmm1, 0x1b    ; Generating round key 9
+        call key_expansion128
+        aeskeygenassist xmm2, xmm1, 0x36    ; Generating round key 10
+        call key_expansion128
+
+		ret 
+
+
+
+align 16
+global iEncExpandKey192
+iEncExpandKey192:
+
+		linux_setup
+		sub rsp,64+8
+		movdqa	[rsp],xmm6
+		movdqa	[rsp+16],xmm7
+
+
+        movq xmm7, [rcx+16]	; loading the AES key
+        movq [rdx+16], xmm7  ; Storing key in memory where all key expansion 
+        pshufd xmm4, xmm7, 01001111b
+        movdqu xmm1, [rcx]	; loading the AES key
+        movdqu [rdx], xmm1  ; Storing key in memory where all key expansion 
+			
+        pxor xmm3, xmm3		; Set xmm3 to be all zeros. Required for the key_expansion. 
+        pxor xmm6, xmm6		; Set xmm3 to be all zeros. Required for the key_expansion. 
+
+        aeskeygenassist xmm2, xmm4, 0x1     ; Complete round key 1 and generate round key 2 
+        key_expansion_1_192 24
+		key_expansion_2_192 40				
+
+        aeskeygenassist xmm2, xmm4, 0x2     ; Generate round key 3 and part of round key 4
+        key_expansion_1_192 48
+		key_expansion_2_192 64				
+
+        aeskeygenassist xmm2, xmm4, 0x4     ; Complete round key 4 and generate round key 5
+        key_expansion_1_192 72
+		key_expansion_2_192 88
+		
+        aeskeygenassist xmm2, xmm4, 0x8     ; Generate round key 6 and part of round key 7
+        key_expansion_1_192 96
+		key_expansion_2_192 112
+		
+        aeskeygenassist xmm2, xmm4, 0x10     ; Complete round key 7 and generate round key 8 
+        key_expansion_1_192 120
+		key_expansion_2_192 136				
+
+        aeskeygenassist xmm2, xmm4, 0x20     ; Generate round key 9 and part of round key 10
+        key_expansion_1_192 144
+		key_expansion_2_192 160				
+
+        aeskeygenassist xmm2, xmm4, 0x40     ; Complete round key 10 and generate round key 11
+        key_expansion_1_192 168
+		key_expansion_2_192 184				
+
+        aeskeygenassist xmm2, xmm4, 0x80     ; Generate round key 12
+        key_expansion_1_192 192
+
+
+		movdqa	xmm6,[rsp]
+		movdqa	xmm7,[rsp+16]
+		add rsp,64+8
+
+		ret 
+
+
+
+
+align 16
+global iDecExpandKey128
+iDecExpandKey128:
+
+	linux_setup
+	push rcx
+	push rdx
+	sub rsp,16+8
+
+	call iEncExpandKey128
+
+	add rsp,16+8
+	pop rdx
+	pop rcx
+
+	inversekey [rdx + 1*16]
+	inversekey [rdx + 2*16]
+	inversekey [rdx + 3*16]
+	inversekey [rdx + 4*16]
+	inversekey [rdx + 5*16]
+	inversekey [rdx + 6*16]
+	inversekey [rdx + 7*16]
+	inversekey [rdx + 8*16]
+	inversekey [rdx + 9*16]
+
+	ret
+
+
+align 16
+global iDecExpandKey192
+iDecExpandKey192:
+
+	linux_setup
+	push rcx
+	push rdx
+	sub rsp,16+8
+
+	call iEncExpandKey192
+
+	add rsp,16+8
+	pop rdx
+	pop rcx
+
+	
+	inversekey [rdx + 1*16]
+	inversekey [rdx + 2*16]
+	inversekey [rdx + 3*16]
+	inversekey [rdx + 4*16]
+	inversekey [rdx + 5*16]
+	inversekey [rdx + 6*16]
+	inversekey [rdx + 7*16]
+	inversekey [rdx + 8*16]
+	inversekey [rdx + 9*16]
+	inversekey [rdx + 10*16]
+	inversekey [rdx + 11*16]
+
+	ret
+
+
+
+align 16
+global iDecExpandKey256
+iDecExpandKey256:
+
+	linux_setup
+	push rcx
+	push rdx
+	sub rsp,16+8
+
+	call iEncExpandKey256
+
+	add rsp,16+8
+	pop rdx
+	pop rcx
+
+	inversekey [rdx + 1*16]
+	inversekey [rdx + 2*16]
+	inversekey [rdx + 3*16]
+	inversekey [rdx + 4*16]
+	inversekey [rdx + 5*16]
+	inversekey [rdx + 6*16]
+	inversekey [rdx + 7*16]
+	inversekey [rdx + 8*16]
+	inversekey [rdx + 9*16]
+	inversekey [rdx + 10*16]
+	inversekey [rdx + 11*16]
+	inversekey [rdx + 12*16]
+	inversekey [rdx + 13*16]
+
+	ret
+	
+
+	
+	
+align 16
+global iEncExpandKey256
+iEncExpandKey256:
+
+	linux_setup
+
+    movdqu xmm1, [rcx]    ; loading the key
+    movdqu xmm3, [rcx+16]
+    movdqu [rdx], xmm1  ; Storing key in memory where all key schedule will be stored
+    movdqu [rdx+16], xmm3 
+    
+    add rdx,32
+
+    movdqa xmm5, [shuffle_mask wrt rip]  ; this mask is used by key_expansion
+
+    aeskeygenassist xmm2, xmm3, 0x1     ; 
+    call key_expansion256
+    aeskeygenassist xmm2, xmm3, 0x2     ; 
+    call key_expansion256
+    aeskeygenassist xmm2, xmm3, 0x4     ; 
+    call key_expansion256
+    aeskeygenassist xmm2, xmm3, 0x8     ; 
+    call key_expansion256
+    aeskeygenassist xmm2, xmm3, 0x10    ; 
+    call key_expansion256
+    aeskeygenassist xmm2, xmm3, 0x20    ; 
+    call key_expansion256
+    aeskeygenassist xmm2, xmm3, 0x40    ; 
+;    call key_expansion256 
+
+    pshufd xmm2, xmm2, 011111111b
+
+    movdqa xmm4, xmm1
+    pshufb xmm4, xmm5
+    pxor xmm1, xmm4
+    pshufb xmm4, xmm5
+    pxor xmm1, xmm4
+    pshufb xmm4, xmm5
+    pxor xmm1, xmm4
+    pxor xmm1, xmm2
+
+    movdqu [rdx], xmm1
+
+
+	ret 
+	
+	
+	
+
+
+
+align 16
+global iDec128
+iDec128:
+
+	linux_setup
+	sub rsp,16*16+8
+
+
+	mov eax,[rcx+32] ; numblocks
+	mov rdx,[rcx]
+	mov r8,[rcx+8]
+	mov rcx,[rcx+16]
+	
+	sub r8,rdx
+
+	test eax,eax
+	jz end_dec128
+
+	cmp eax,4
+	jl	lp128decsingle
+
+	test	rcx,0xf
+	jz		lp128decfour
+	
+	copy_round_keys rsp,rcx,0
+	copy_round_keys rsp,rcx,1
+	copy_round_keys rsp,rcx,2
+	copy_round_keys rsp,rcx,3
+	copy_round_keys rsp,rcx,4
+	copy_round_keys rsp,rcx,5
+	copy_round_keys rsp,rcx,6
+	copy_round_keys rsp,rcx,7
+	copy_round_keys rsp,rcx,8
+	copy_round_keys rsp,rcx,9
+	copy_round_keys rsp,rcx,10
+	mov rcx,rsp	
+	
+	
+
+align 16
+lp128decfour:
+	
+	test eax,eax
+	jz end_dec128
+
+	cmp eax,4
+	jl	lp128decsingle
+
+	load_and_xor4 rdx, [rcx+10*16]
+	add rdx,16*4
+	aesdec4 [rcx+9*16]
+	aesdec4 [rcx+8*16]
+	aesdec4 [rcx+7*16]
+	aesdec4 [rcx+6*16]
+	aesdec4 [rcx+5*16]
+	aesdec4 [rcx+4*16]
+	aesdec4 [rcx+3*16]
+	aesdec4 [rcx+2*16]
+	aesdec4 [rcx+1*16]
+	aesdeclast4 [rcx+0*16]
+	
+	sub eax,4
+	store4 r8+rdx-(16*4)
+	jmp lp128decfour
+
+
+	align 16
+lp128decsingle:
+
+	movdqu xmm0, [rdx]
+	movdqu xmm4,[rcx+10*16]
+	pxor xmm0, xmm4
+	aesdec1_u [rcx+9*16]
+	aesdec1_u [rcx+8*16]
+	aesdec1_u [rcx+7*16]
+	aesdec1_u [rcx+6*16]
+	aesdec1_u [rcx+5*16]
+	aesdec1_u [rcx+4*16]
+	aesdec1_u [rcx+3*16]
+	aesdec1_u [rcx+2*16]
+	aesdec1_u [rcx+1*16]
+	aesdeclast1_u [rcx+0*16]
+
+	add rdx, 16
+	movdqu  [r8 + rdx - 16], xmm0
+	dec eax
+	jnz lp128decsingle
+
+end_dec128:
+
+	add rsp,16*16+8
+	ret
+
+
+align 16
+global iDec128_CBC
+iDec128_CBC:
+	
+	linux_setup
+	sub rsp,16*16+8
+
+	mov r9,rcx
+	mov rax,[rcx+24]
+	movdqu	xmm5,[rax]
+	
+	mov eax,[rcx+32] ; numblocks
+	mov rdx,[rcx]
+	mov r8,[rcx+8]
+	mov rcx,[rcx+16]
+	
+	
+	sub r8,rdx
+
+
+	test eax,eax
+	jz end_dec128_CBC
+
+	cmp eax,4
+	jl	lp128decsingle_CBC
+
+	test	rcx,0xf
+	jz		lp128decfour_CBC
+	
+	copy_round_keys rsp,rcx,0
+	copy_round_keys rsp,rcx,1
+	copy_round_keys rsp,rcx,2
+	copy_round_keys rsp,rcx,3
+	copy_round_keys rsp,rcx,4
+	copy_round_keys rsp,rcx,5
+	copy_round_keys rsp,rcx,6
+	copy_round_keys rsp,rcx,7
+	copy_round_keys rsp,rcx,8
+	copy_round_keys rsp,rcx,9
+	copy_round_keys rsp,rcx,10
+	mov rcx,rsp	
+
+
+align 16
+lp128decfour_CBC:
+	
+	test eax,eax
+	jz end_dec128_CBC
+
+	cmp eax,4
+	jl	lp128decsingle_CBC
+
+	load_and_xor4 rdx, [rcx+10*16]
+	add rdx,16*4
+	aesdec4 [rcx+9*16]
+	aesdec4 [rcx+8*16]
+	aesdec4 [rcx+7*16]
+	aesdec4 [rcx+6*16]
+	aesdec4 [rcx+5*16]
+	aesdec4 [rcx+4*16]
+	aesdec4 [rcx+3*16]
+	aesdec4 [rcx+2*16]
+	aesdec4 [rcx+1*16]
+	aesdeclast4 [rcx+0*16]
+
+	pxor	xmm0,xmm5
+	movdqu	xmm4,[rdx - 16*4 + 0*16]
+	pxor	xmm1,xmm4
+	movdqu	xmm4,[rdx - 16*4 + 1*16]
+	pxor	xmm2,xmm4
+	movdqu	xmm4,[rdx - 16*4 + 2*16]
+	pxor	xmm3,xmm4
+	movdqu	xmm5,[rdx - 16*4 + 3*16]
+	
+	sub eax,4
+	store4 r8+rdx-(16*4)
+	jmp lp128decfour_CBC
+
+
+	align 16
+lp128decsingle_CBC:
+
+	movdqu xmm0, [rdx]
+	movdqa	xmm1,xmm0
+	movdqu xmm4,[rcx+10*16]
+	pxor xmm0, xmm4
+	aesdec1_u [rcx+9*16]
+	aesdec1_u [rcx+8*16]
+	aesdec1_u [rcx+7*16]
+	aesdec1_u [rcx+6*16]
+	aesdec1_u [rcx+5*16]
+	aesdec1_u [rcx+4*16]
+	aesdec1_u [rcx+3*16]
+	aesdec1_u [rcx+2*16]
+	aesdec1_u [rcx+1*16]
+	aesdeclast1_u [rcx+0*16]
+
+	pxor	xmm0,xmm5
+	movdqa	xmm5,xmm1
+	add rdx, 16
+	movdqu  [r8 + rdx - 16], xmm0
+	dec eax
+	jnz lp128decsingle_CBC
+
+end_dec128_CBC:
+
+	mov	   r9,[r9+24]
+	movdqu [r9],xmm5
+	add rsp,16*16+8
+	ret
+
+
+align 16
+global iDec192_CBC
+iDec192_CBC:
+
+	linux_setup
+	sub rsp,16*16+8
+
+	mov r9,rcx
+	mov rax,[rcx+24]
+	movdqu	xmm5,[rax]
+	
+	mov eax,[rcx+32] ; numblocks
+	mov rdx,[rcx]
+	mov r8,[rcx+8]
+	mov rcx,[rcx+16]
+	
+	
+	sub r8,rdx
+
+	test eax,eax
+	jz end_dec192_CBC
+
+	cmp eax,4
+	jl	lp192decsingle_CBC
+
+	test	rcx,0xf
+	jz		lp192decfour_CBC
+	
+	copy_round_keys rsp,rcx,0
+	copy_round_keys rsp,rcx,1
+	copy_round_keys rsp,rcx,2
+	copy_round_keys rsp,rcx,3
+	copy_round_keys rsp,rcx,4
+	copy_round_keys rsp,rcx,5
+	copy_round_keys rsp,rcx,6
+	copy_round_keys rsp,rcx,7
+	copy_round_keys rsp,rcx,8
+	copy_round_keys rsp,rcx,9
+	copy_round_keys rsp,rcx,10
+	copy_round_keys rsp,rcx,11
+	copy_round_keys rsp,rcx,12
+	mov rcx,rsp	
+
+
+align 16
+lp192decfour_CBC:
+	
+	test eax,eax
+	jz end_dec192_CBC
+
+	cmp eax,4
+	jl	lp192decsingle_CBC
+
+	load_and_xor4 rdx, [rcx+12*16]
+	add rdx,16*4
+	aesdec4 [rcx+11*16]
+	aesdec4 [rcx+10*16]
+	aesdec4 [rcx+9*16]
+	aesdec4 [rcx+8*16]
+	aesdec4 [rcx+7*16]
+	aesdec4 [rcx+6*16]
+	aesdec4 [rcx+5*16]
+	aesdec4 [rcx+4*16]
+	aesdec4 [rcx+3*16]
+	aesdec4 [rcx+2*16]
+	aesdec4 [rcx+1*16]
+	aesdeclast4 [rcx+0*16]
+
+	pxor	xmm0,xmm5
+	movdqu	xmm4,[rdx - 16*4 + 0*16]
+	pxor	xmm1,xmm4
+	movdqu	xmm4,[rdx - 16*4 + 1*16]
+	pxor	xmm2,xmm4
+	movdqu	xmm4,[rdx - 16*4 + 2*16]
+	pxor	xmm3,xmm4
+	movdqu	xmm5,[rdx - 16*4 + 3*16]
+	
+	sub eax,4
+	store4 r8+rdx-(16*4)
+	jmp lp192decfour_CBC
+
+
+	align 16
+lp192decsingle_CBC:
+
+	movdqu xmm0, [rdx]
+	movdqu xmm4,[rcx+12*16]
+	movdqa	xmm1,xmm0
+	pxor xmm0, xmm4
+	aesdec1_u [rcx+11*16]
+	aesdec1_u [rcx+10*16]
+	aesdec1_u [rcx+9*16]
+	aesdec1_u [rcx+8*16]
+	aesdec1_u [rcx+7*16]
+	aesdec1_u [rcx+6*16]
+	aesdec1_u [rcx+5*16]
+	aesdec1_u [rcx+4*16]
+	aesdec1_u [rcx+3*16]
+	aesdec1_u [rcx+2*16]
+	aesdec1_u [rcx+1*16]
+	aesdeclast1_u [rcx+0*16]
+
+	pxor	xmm0,xmm5
+	movdqa	xmm5,xmm1
+	add rdx, 16
+	movdqu  [r8 + rdx - 16], xmm0
+	dec eax
+	jnz lp192decsingle_CBC
+
+end_dec192_CBC:
+
+	mov	   r9,[r9+24]
+	movdqu [r9],xmm5
+	add rsp,16*16+8
+	ret
+
+
+
+
+align 16
+global iDec256_CBC
+iDec256_CBC:
+
+	linux_setup
+	sub rsp,16*16+8
+
+	mov r9,rcx
+	mov rax,[rcx+24]
+	movdqu	xmm5,[rax]
+	
+	mov eax,[rcx+32] ; numblocks
+	mov rdx,[rcx]
+	mov r8,[rcx+8]
+	mov rcx,[rcx+16]
+	
+	
+	sub r8,rdx
+
+	test eax,eax
+	jz end_dec256_CBC
+
+	cmp eax,4
+	jl	lp256decsingle_CBC
+
+	test	rcx,0xf
+	jz		lp256decfour_CBC
+	
+	copy_round_keys rsp,rcx,0
+	copy_round_keys rsp,rcx,1
+	copy_round_keys rsp,rcx,2
+	copy_round_keys rsp,rcx,3
+	copy_round_keys rsp,rcx,4
+	copy_round_keys rsp,rcx,5
+	copy_round_keys rsp,rcx,6
+	copy_round_keys rsp,rcx,7
+	copy_round_keys rsp,rcx,8
+	copy_round_keys rsp,rcx,9
+	copy_round_keys rsp,rcx,10
+	copy_round_keys rsp,rcx,11
+	copy_round_keys rsp,rcx,12
+	copy_round_keys rsp,rcx,13
+	copy_round_keys rsp,rcx,14
+	mov rcx,rsp	
+
+align 16
+lp256decfour_CBC:
+	
+	test eax,eax
+	jz end_dec256_CBC
+
+	cmp eax,4
+	jl	lp256decsingle_CBC
+
+	load_and_xor4 rdx, [rcx+14*16]
+	add rdx,16*4
+	aesdec4 [rcx+13*16]
+	aesdec4 [rcx+12*16]
+	aesdec4 [rcx+11*16]
+	aesdec4 [rcx+10*16]
+	aesdec4 [rcx+9*16]
+	aesdec4 [rcx+8*16]
+	aesdec4 [rcx+7*16]
+	aesdec4 [rcx+6*16]
+	aesdec4 [rcx+5*16]
+	aesdec4 [rcx+4*16]
+	aesdec4 [rcx+3*16]
+	aesdec4 [rcx+2*16]
+	aesdec4 [rcx+1*16]
+	aesdeclast4 [rcx+0*16]
+
+	pxor	xmm0,xmm5
+	movdqu	xmm4,[rdx - 16*4 + 0*16]
+	pxor	xmm1,xmm4
+	movdqu	xmm4,[rdx - 16*4 + 1*16]
+	pxor	xmm2,xmm4
+	movdqu	xmm4,[rdx - 16*4 + 2*16]
+	pxor	xmm3,xmm4
+	movdqu	xmm5,[rdx - 16*4 + 3*16]
+	
+	sub eax,4
+	store4 r8+rdx-(16*4)
+	jmp lp256decfour_CBC
+
+
+	align 16
+lp256decsingle_CBC:
+
+	movdqu xmm0, [rdx]
+	movdqu xmm4,[rcx+14*16]
+	movdqa	xmm1,xmm0
+	pxor xmm0, xmm4
+	aesdec1_u [rcx+13*16]
+	aesdec1_u [rcx+12*16]
+	aesdec1_u [rcx+11*16]
+	aesdec1_u [rcx+10*16]
+	aesdec1_u [rcx+9*16]
+	aesdec1_u [rcx+8*16]
+	aesdec1_u [rcx+7*16]
+	aesdec1_u [rcx+6*16]
+	aesdec1_u [rcx+5*16]
+	aesdec1_u [rcx+4*16]
+	aesdec1_u [rcx+3*16]
+	aesdec1_u [rcx+2*16]
+	aesdec1_u [rcx+1*16]
+	aesdeclast1_u [rcx+0*16]
+
+	pxor	xmm0,xmm5
+	movdqa	xmm5,xmm1
+	add rdx, 16
+	movdqu  [r8 + rdx - 16], xmm0
+	dec eax
+	jnz lp256decsingle_CBC
+
+end_dec256_CBC:
+
+	mov	   r9,[r9+24]
+	movdqu [r9],xmm5
+	add rsp,16*16+8
+	ret
+
+
+
+
+
+align 16
+global iDec192
+iDec192:
+
+	linux_setup
+	sub rsp,16*16+8
+
+	mov eax,[rcx+32] ; numblocks
+	mov rdx,[rcx]
+	mov r8,[rcx+8]
+	mov rcx,[rcx+16]
+	
+	sub r8,rdx
+	
+	test eax,eax
+	jz end_dec192
+
+	cmp eax,4
+	jl	lp192decsingle
+	
+	test	rcx,0xf
+	jz		lp192decfour
+	
+	copy_round_keys rsp,rcx,0
+	copy_round_keys rsp,rcx,1
+	copy_round_keys rsp,rcx,2
+	copy_round_keys rsp,rcx,3
+	copy_round_keys rsp,rcx,4
+	copy_round_keys rsp,rcx,5
+	copy_round_keys rsp,rcx,6
+	copy_round_keys rsp,rcx,7
+	copy_round_keys rsp,rcx,8
+	copy_round_keys rsp,rcx,9
+	copy_round_keys rsp,rcx,10
+	copy_round_keys rsp,rcx,11
+	copy_round_keys rsp,rcx,12
+	mov rcx,rsp	
+
+align 16
+lp192decfour:
+	
+	test eax,eax
+	jz end_dec192
+
+	cmp eax,4
+	jl	lp192decsingle
+
+	load_and_xor4 rdx, [rcx+12*16]
+	add rdx,16*4
+	aesdec4 [rcx+11*16]
+	aesdec4 [rcx+10*16]
+	aesdec4 [rcx+9*16]
+	aesdec4 [rcx+8*16]
+	aesdec4 [rcx+7*16]
+	aesdec4 [rcx+6*16]
+	aesdec4 [rcx+5*16]
+	aesdec4 [rcx+4*16]
+	aesdec4 [rcx+3*16]
+	aesdec4 [rcx+2*16]
+	aesdec4 [rcx+1*16]
+	aesdeclast4 [rcx+0*16]
+	
+	sub eax,4
+	store4 r8+rdx-(16*4)
+	jmp lp192decfour
+
+
+	align 16
+lp192decsingle:
+
+	movdqu xmm0, [rdx]
+	movdqu xmm4,[rcx+12*16]
+	pxor xmm0, xmm4
+	aesdec1_u [rcx+11*16]
+	aesdec1_u [rcx+10*16]
+	aesdec1_u [rcx+9*16]
+	aesdec1_u [rcx+8*16]
+	aesdec1_u [rcx+7*16]
+	aesdec1_u [rcx+6*16]
+	aesdec1_u [rcx+5*16]
+	aesdec1_u [rcx+4*16]
+	aesdec1_u [rcx+3*16]
+	aesdec1_u [rcx+2*16]
+	aesdec1_u [rcx+1*16]
+	aesdeclast1_u [rcx+0*16]
+
+	add rdx, 16
+	movdqu  [r8 + rdx - 16], xmm0
+	dec eax
+	jnz lp192decsingle
+
+end_dec192:
+
+	add rsp,16*16+8
+	ret
+
+
+
+
+align 16
+global iDec256
+iDec256:
+
+	linux_setup
+	sub rsp,16*16+8
+	
+	mov eax,[rcx+32] ; numblocks
+	mov rdx,[rcx]
+	mov r8,[rcx+8]
+	mov rcx,[rcx+16]
+	
+	sub r8,rdx
+
+
+	test eax,eax
+	jz end_dec256
+	
+	cmp eax,4
+	jl lp256dec
+
+	test	rcx,0xf
+	jz		lp256dec4
+	
+	copy_round_keys rsp,rcx,0
+	copy_round_keys rsp,rcx,1
+	copy_round_keys rsp,rcx,2
+	copy_round_keys rsp,rcx,3
+	copy_round_keys rsp,rcx,4
+	copy_round_keys rsp,rcx,5
+	copy_round_keys rsp,rcx,6
+	copy_round_keys rsp,rcx,7
+	copy_round_keys rsp,rcx,8
+	copy_round_keys rsp,rcx,9
+	copy_round_keys rsp,rcx,10
+	copy_round_keys rsp,rcx,11
+	copy_round_keys rsp,rcx,12
+	copy_round_keys rsp,rcx,13
+	copy_round_keys rsp,rcx,14
+	mov rcx,rsp	
+
+	
+	align 16
+lp256dec4:	
+	test eax,eax
+	jz end_dec256
+	
+	cmp eax,4
+	jl lp256dec
+	
+	load_and_xor4 rdx,[rcx+14*16]
+	add rdx, 4*16
+	aesdec4 [rcx+13*16]
+	aesdec4 [rcx+12*16]
+	aesdec4 [rcx+11*16]
+	aesdec4 [rcx+10*16]
+	aesdec4 [rcx+9*16]
+	aesdec4 [rcx+8*16]
+	aesdec4 [rcx+7*16]
+	aesdec4 [rcx+6*16]
+	aesdec4 [rcx+5*16]
+	aesdec4 [rcx+4*16]
+	aesdec4 [rcx+3*16]
+	aesdec4 [rcx+2*16]
+	aesdec4 [rcx+1*16]
+	aesdeclast4 [rcx+0*16]
+
+	store4 r8+rdx-16*4
+	sub eax,4
+	jmp lp256dec4	
+	
+	align 16
+lp256dec:
+
+	movdqu xmm0, [rdx]
+	movdqu xmm4,[rcx+14*16]
+	add rdx, 16
+	pxor xmm0, xmm4                    ; Round 0 (only xor)
+	aesdec1_u [rcx+13*16]
+	aesdec1_u [rcx+12*16]
+	aesdec1_u [rcx+11*16]
+	aesdec1_u [rcx+10*16]
+	aesdec1_u [rcx+9*16]
+	aesdec1_u [rcx+8*16]
+	aesdec1_u [rcx+7*16]
+	aesdec1_u [rcx+6*16]
+	aesdec1_u [rcx+5*16]
+	aesdec1_u [rcx+4*16]
+	aesdec1_u [rcx+3*16]
+	aesdec1_u [rcx+2*16]
+	aesdec1_u [rcx+1*16]
+	aesdeclast1_u [rcx+0*16]
+
+		; Store output encrypted data into CIPHERTEXT array
+	movdqu  [r8+rdx-16], xmm0
+	dec eax
+	jnz lp256dec
+
+end_dec256:
+	
+	add rsp,16*16+8
+	ret
+
+
+
+
+
+
+align 16
+global iEnc128
+iEnc128:
+
+	linux_setup
+	sub rsp,16*16+8
+	
+	mov eax,[rcx+32] ; numblocks
+	mov rdx,[rcx]
+	mov r8,[rcx+8]
+	mov rcx,[rcx+16]
+	
+	sub r8,rdx
+
+
+	test eax,eax
+	jz end_enc128
+	
+	cmp eax,4
+	jl lp128encsingle
+
+	test	rcx,0xf
+	jz		lpenc128four
+	
+	copy_round_keys rsp,rcx,0
+	copy_round_keys rsp,rcx,1
+	copy_round_keys rsp,rcx,2
+	copy_round_keys rsp,rcx,3
+	copy_round_keys rsp,rcx,4
+	copy_round_keys rsp,rcx,5
+	copy_round_keys rsp,rcx,6
+	copy_round_keys rsp,rcx,7
+	copy_round_keys rsp,rcx,8
+	copy_round_keys rsp,rcx,9
+	copy_round_keys rsp,rcx,10
+	mov rcx,rsp	
+
+
+	align 16	
+	
+lpenc128four:
+	
+	test eax,eax
+	jz end_enc128
+	
+	cmp eax,4
+	jl lp128encsingle
+
+	load_and_xor4 rdx,[rcx+0*16]
+	add rdx,4*16
+	aesenc4	[rcx+1*16]
+	aesenc4	[rcx+2*16]
+	aesenc4	[rcx+3*16]
+	aesenc4	[rcx+4*16]
+	aesenc4	[rcx+5*16]
+	aesenc4	[rcx+6*16]
+	aesenc4	[rcx+7*16]
+	aesenc4	[rcx+8*16]
+	aesenc4	[rcx+9*16]
+	aesenclast4	[rcx+10*16]
+	
+	store4 r8+rdx-16*4
+	sub eax,4
+	jmp lpenc128four
+	
+	align 16
+lp128encsingle:
+
+	movdqu xmm0, [rdx]
+	movdqu xmm4,[rcx+0*16]
+	add rdx, 16
+	pxor xmm0, xmm4
+	aesenc1_u [rcx+1*16]
+	aesenc1_u [rcx+2*16]
+	aesenc1_u [rcx+3*16]
+	aesenc1_u [rcx+4*16]     
+	aesenc1_u [rcx+5*16]
+	aesenc1_u [rcx+6*16]
+	aesenc1_u [rcx+7*16]
+	aesenc1_u [rcx+8*16]
+	aesenc1_u [rcx+9*16]
+	aesenclast1_u [rcx+10*16]
+
+		; Store output encrypted data into CIPHERTEXT array
+	movdqu  [r8+rdx-16], xmm0
+	dec eax
+	jnz lp128encsingle
+
+end_enc128:
+
+	add rsp,16*16+8
+	ret
+
+
+align 16
+global iEnc128_CTR
+iEnc128_CTR:
+
+	linux_setup
+
+	mov r9,rcx
+	mov rax,[rcx+24]
+	movdqu xmm5,[rax]
+
+
+	sub rsp,16*16+8
+	
+	mov eax,[rcx+32] ; numblocks
+	mov rdx,[rcx]
+	mov r8,[rcx+8]
+	mov rcx,[rcx+16]
+	
+	sub r8,rdx
+
+
+	test eax,eax
+	jz end_encctr128
+	
+	cmp eax,4
+	jl lp128encctrsingle
+
+	test	rcx,0xf
+	jz		lpencctr128four
+	
+	copy_round_keys rsp,rcx,0
+	copy_round_keys rsp,rcx,1
+	copy_round_keys rsp,rcx,2
+	copy_round_keys rsp,rcx,3
+	copy_round_keys rsp,rcx,4
+	copy_round_keys rsp,rcx,5
+	copy_round_keys rsp,rcx,6
+	copy_round_keys rsp,rcx,7
+	copy_round_keys rsp,rcx,8
+	copy_round_keys rsp,rcx,9
+	copy_round_keys rsp,rcx,10
+	mov rcx,rsp	
+
+
+	align 16	
+	
+lpencctr128four:
+	
+	test eax,eax
+	jz end_encctr128
+	
+	cmp eax,4
+	jl lp128encctrsingle
+
+	load_and_inc4 [rcx+0*16]
+	add rdx,4*16
+	aesenc4	[rcx+1*16]
+	aesenc4	[rcx+2*16]
+	aesenc4	[rcx+3*16]
+	aesenc4	[rcx+4*16]
+	aesenc4	[rcx+5*16]
+	aesenc4	[rcx+6*16]
+	aesenc4	[rcx+7*16]
+	aesenc4	[rcx+8*16]
+	aesenc4	[rcx+9*16]
+	aesenclast4	[rcx+10*16]
+	xor_with_input4 rdx-(4*16)
+	
+	store4 r8+rdx-16*4
+	sub eax,4
+	jmp lpencctr128four
+	
+	align 16
+lp128encctrsingle:
+
+	movdqa xmm0,xmm5
+	paddq	xmm5,[counter_add_one wrt rip]
+	add rdx, 16
+	movdqu xmm4,[rcx+0*16]
+	pxor xmm0, xmm4
+	aesenc1_u [rcx+1*16]
+	aesenc1_u [rcx+2*16]
+	aesenc1_u [rcx+3*16]
+	aesenc1_u [rcx+4*16]     
+	aesenc1_u [rcx+5*16]
+	aesenc1_u [rcx+6*16]
+	aesenc1_u [rcx+7*16]
+	aesenc1_u [rcx+8*16]
+	aesenc1_u [rcx+9*16]
+	aesenclast1_u [rcx+10*16]
+	movdqu xmm4, [rdx-16]
+	pxor  xmm0,xmm4
+
+		; Store output encrypted data into CIPHERTEXT array
+	movdqu  [r8+rdx-16], xmm0
+	dec eax
+	jnz lp128encctrsingle
+
+end_encctr128:
+
+	mov	   r9,[r9+24]
+	movdqu [r9],xmm5
+	add rsp,16*16+8
+	ret
+
+
+
+align 16
+global iEnc192_CTR
+iEnc192_CTR:
+
+	linux_setup
+
+	mov r9,rcx
+	mov rax,[rcx+24]
+	movdqu xmm5,[rax]
+
+
+	sub rsp,16*16+8
+	
+	mov eax,[rcx+32] ; numblocks
+	mov rdx,[rcx]
+	mov r8,[rcx+8]
+	mov rcx,[rcx+16]
+	
+	sub r8,rdx
+
+
+	test eax,eax
+	jz end_encctr192
+	
+	cmp eax,4
+	jl lp192encctrsingle
+
+	test	rcx,0xf
+	jz		lpencctr192four
+	
+	copy_round_keys rsp,rcx,0
+	copy_round_keys rsp,rcx,1
+	copy_round_keys rsp,rcx,2
+	copy_round_keys rsp,rcx,3
+	copy_round_keys rsp,rcx,4
+	copy_round_keys rsp,rcx,5
+	copy_round_keys rsp,rcx,6
+	copy_round_keys rsp,rcx,7
+	copy_round_keys rsp,rcx,8
+	copy_round_keys rsp,rcx,9
+	copy_round_keys rsp,rcx,10
+	copy_round_keys rsp,rcx,11
+	copy_round_keys rsp,rcx,12
+	mov rcx,rsp	
+
+
+	align 16	
+	
+lpencctr192four:
+	
+	test eax,eax
+	jz end_encctr192
+	
+	cmp eax,4
+	jl lp192encctrsingle
+
+	load_and_inc4 [rcx+0*16]
+	add rdx,4*16
+	aesenc4	[rcx+1*16]
+	aesenc4	[rcx+2*16]
+	aesenc4	[rcx+3*16]
+	aesenc4	[rcx+4*16]
+	aesenc4	[rcx+5*16]
+	aesenc4	[rcx+6*16]
+	aesenc4	[rcx+7*16]
+	aesenc4	[rcx+8*16]
+	aesenc4	[rcx+9*16]
+	aesenc4	[rcx+10*16]
+	aesenc4	[rcx+11*16]
+	aesenclast4	[rcx+12*16]
+	xor_with_input4 rdx-(4*16)
+	
+	store4 r8+rdx-16*4
+	sub eax,4
+	jmp lpencctr192four
+	
+	align 16
+lp192encctrsingle:
+
+	movdqa xmm5,xmm0
+	movdqu xmm4,[rcx+0*16]
+	paddq	xmm5,[counter_add_one wrt rip]
+	add rdx, 16
+	pxor xmm0, xmm4
+	aesenc1_u [rcx+1*16]
+	aesenc1_u [rcx+2*16]
+	aesenc1_u [rcx+3*16]
+	aesenc1_u [rcx+4*16]     
+	aesenc1_u [rcx+5*16]
+	aesenc1_u [rcx+6*16]
+	aesenc1_u [rcx+7*16]
+	aesenc1_u [rcx+8*16]
+	aesenc1_u [rcx+9*16]
+	aesenc1_u [rcx+10*16]
+	aesenc1_u [rcx+11*16]
+	aesenclast1_u [rcx+12*16]
+	movdqu xmm4, [rdx]
+	pxor  xmm0,xmm4
+
+		; Store output encrypted data into CIPHERTEXT array
+	movdqu  [r8+rdx-16], xmm0
+	dec eax
+	jnz lp192encctrsingle
+
+end_encctr192:
+
+	mov	   r9,[r9+24]
+	movdqu [r9],xmm5
+	add rsp,16*16+8
+	ret
+
+
+align 16
+global iEnc256_CTR
+iEnc256_CTR:
+
+	linux_setup
+
+	mov r9,rcx
+	mov rax,[rcx+24]
+	movdqu xmm5,[rax]
+
+
+	sub rsp,16*16+8
+	
+	mov eax,[rcx+32] ; numblocks
+	mov rdx,[rcx]
+	mov r8,[rcx+8]
+	mov rcx,[rcx+16]
+	
+	sub r8,rdx
+
+
+	test eax,eax
+	jz end_encctr256
+	
+	cmp eax,4
+	jl lp256encctrsingle
+
+	test	rcx,0xf
+	jz		lpencctr256four
+	
+	copy_round_keys rsp,rcx,0
+	copy_round_keys rsp,rcx,1
+	copy_round_keys rsp,rcx,2
+	copy_round_keys rsp,rcx,3
+	copy_round_keys rsp,rcx,4
+	copy_round_keys rsp,rcx,5
+	copy_round_keys rsp,rcx,6
+	copy_round_keys rsp,rcx,7
+	copy_round_keys rsp,rcx,8
+	copy_round_keys rsp,rcx,9
+	copy_round_keys rsp,rcx,10
+	copy_round_keys rsp,rcx,11
+	copy_round_keys rsp,rcx,12
+	copy_round_keys rsp,rcx,13
+	copy_round_keys rsp,rcx,14
+	mov rcx,rsp	
+
+
+	align 16	
+	
+lpencctr256four:
+	
+	test eax,eax
+	jz end_encctr256
+	
+	cmp eax,4
+	jl lp256encctrsingle
+
+	load_and_inc4 [rcx+0*16]
+	add rdx,4*16
+	aesenc4	[rcx+1*16]
+	aesenc4	[rcx+2*16]
+	aesenc4	[rcx+3*16]
+	aesenc4	[rcx+4*16]
+	aesenc4	[rcx+5*16]
+	aesenc4	[rcx+6*16]
+	aesenc4	[rcx+7*16]
+	aesenc4	[rcx+8*16]
+	aesenc4	[rcx+9*16]
+	aesenc4	[rcx+10*16]
+	aesenc4	[rcx+11*16]
+	aesenc4	[rcx+12*16]
+	aesenc4	[rcx+13*16]
+	aesenclast4	[rcx+14*16]
+	xor_with_input4 rdx-(4*16)
+	
+	store4 r8+rdx-16*4
+	sub eax,4
+	jmp lpencctr256four
+	
+	align 16
+lp256encctrsingle:
+
+	movdqa xmm5,xmm0
+	movdqu xmm4,[rcx+0*16]
+	paddq	xmm5,[counter_add_one wrt rip]
+	add rdx, 16
+	pxor xmm0, xmm4
+	aesenc1_u [rcx+1*16]
+	aesenc1_u [rcx+2*16]
+	aesenc1_u [rcx+3*16]
+	aesenc1_u [rcx+4*16]     
+	aesenc1_u [rcx+5*16]
+	aesenc1_u [rcx+6*16]
+	aesenc1_u [rcx+7*16]
+	aesenc1_u [rcx+8*16]
+	aesenc1_u [rcx+9*16]
+	aesenc1_u [rcx+10*16]
+	aesenc1_u [rcx+11*16]
+	aesenc1_u [rcx+12*16]
+	aesenc1_u [rcx+13*16]
+	aesenclast1_u [rcx+14*16]
+	movdqu xmm4, [rdx]
+	pxor  xmm0,xmm4
+
+		; Store output encrypted data into CIPHERTEXT array
+	movdqu  [r8+rdx-16], xmm0
+	dec eax
+	jnz lp256encctrsingle
+
+end_encctr256:
+
+	mov	   r9,[r9+24]
+	movdqu [r9],xmm5
+	add rsp,16*16+8
+	ret
+
+
+
+
+
+
+
+align 16
+global iEnc128_CBC
+iEnc128_CBC:
+
+	linux_setup
+	sub rsp,16*16+8
+	
+	mov r9,rcx
+	mov rax,[rcx+24]
+	movdqu xmm1,[rax]
+	
+	mov eax,[rcx+32] ; numblocks
+	mov rdx,[rcx]
+	mov r8,[rcx+8]
+	mov rcx,[rcx+16]
+	
+	sub r8,rdx
+
+
+	test	rcx,0xf
+	jz		lp128encsingle_CBC
+	
+	copy_round_keys rsp,rcx,0
+	copy_round_keys rsp,rcx,1
+	copy_round_keys rsp,rcx,2
+	copy_round_keys rsp,rcx,3
+	copy_round_keys rsp,rcx,4
+	copy_round_keys rsp,rcx,5
+	copy_round_keys rsp,rcx,6
+	copy_round_keys rsp,rcx,7
+	copy_round_keys rsp,rcx,8
+	copy_round_keys rsp,rcx,9
+	copy_round_keys rsp,rcx,10
+	mov rcx,rsp	
+
+
+	align 16	
+	
+lp128encsingle_CBC:
+
+	movdqu xmm0, [rdx]
+	movdqu xmm4,[rcx+0*16]
+	add rdx, 16
+	pxor xmm0, xmm1
+	pxor xmm0, xmm4
+	aesenc1 [rcx+1*16]
+	aesenc1 [rcx+2*16]
+	aesenc1 [rcx+3*16]
+	aesenc1 [rcx+4*16]     
+	aesenc1 [rcx+5*16]
+	aesenc1 [rcx+6*16]
+	aesenc1 [rcx+7*16]
+	aesenc1 [rcx+8*16]
+	aesenc1 [rcx+9*16]
+	aesenclast1 [rcx+10*16]
+	movdqa xmm1,xmm0
+
+		; Store output encrypted data into CIPHERTEXT array
+	movdqu  [r8+rdx-16], xmm0
+	dec eax
+	jnz lp128encsingle_CBC
+
+	mov	   r9,[r9+24]
+	movdqu [r9],xmm1
+	add rsp,16*16+8
+	ret
+
+
+align 16
+global iEnc192_CBC
+iEnc192_CBC:
+
+	linux_setup
+	sub rsp,16*16+8
+	mov r9,rcx
+	mov rax,[rcx+24]
+	movdqu xmm1,[rax]
+	
+	mov eax,[rcx+32] ; numblocks
+	mov rdx,[rcx]
+	mov r8,[rcx+8]
+	mov rcx,[rcx+16]
+	
+	sub r8,rdx
+
+	test	rcx,0xf
+	jz		lp192encsingle_CBC
+	
+	copy_round_keys rsp,rcx,0
+	copy_round_keys rsp,rcx,1
+	copy_round_keys rsp,rcx,2
+	copy_round_keys rsp,rcx,3
+	copy_round_keys rsp,rcx,4
+	copy_round_keys rsp,rcx,5
+	copy_round_keys rsp,rcx,6
+	copy_round_keys rsp,rcx,7
+	copy_round_keys rsp,rcx,8
+	copy_round_keys rsp,rcx,9
+	copy_round_keys rsp,rcx,10
+	copy_round_keys rsp,rcx,11
+	copy_round_keys rsp,rcx,12
+	mov rcx,rsp	
+
+
+
+	align 16	
+	
+lp192encsingle_CBC:
+
+	movdqu xmm0, [rdx]
+	movdqu xmm4, [rcx+0*16]
+	add rdx, 16
+	pxor xmm0, xmm1
+	pxor xmm0, xmm4
+	aesenc1 [rcx+1*16]
+	aesenc1 [rcx+2*16]
+	aesenc1 [rcx+3*16]
+	aesenc1 [rcx+4*16]     
+	aesenc1 [rcx+5*16]
+	aesenc1 [rcx+6*16]
+	aesenc1 [rcx+7*16]
+	aesenc1 [rcx+8*16]
+	aesenc1 [rcx+9*16]
+	aesenc1 [rcx+10*16]
+	aesenc1 [rcx+11*16]
+	aesenclast1 [rcx+12*16]
+	movdqa xmm1,xmm0
+
+		; Store output encrypted data into CIPHERTEXT array
+	movdqu  [r8+rdx-16], xmm0
+	dec eax
+	jnz lp192encsingle_CBC
+
+	mov	   r9,[r9+24]
+	movdqu [r9],xmm1
+
+	add rsp,16*16+8
+	ret
+
+
+align 16
+global iEnc256_CBC
+iEnc256_CBC:
+
+	linux_setup
+	sub rsp,16*16+8
+	
+	mov r9,rcx
+	mov rax,[rcx+24]
+	movdqu xmm1,[rax]
+	
+	mov eax,[rcx+32] ; numblocks
+	mov rdx,[rcx]
+	mov r8,[rcx+8]
+	mov rcx,[rcx+16]
+	
+	sub r8,rdx
+
+	test	rcx,0xf
+	jz		lp256encsingle_CBC
+	
+	copy_round_keys rsp,rcx,0
+	copy_round_keys rsp,rcx,1
+	copy_round_keys rsp,rcx,2
+	copy_round_keys rsp,rcx,3
+	copy_round_keys rsp,rcx,4
+	copy_round_keys rsp,rcx,5
+	copy_round_keys rsp,rcx,6
+	copy_round_keys rsp,rcx,7
+	copy_round_keys rsp,rcx,8
+	copy_round_keys rsp,rcx,9
+	copy_round_keys rsp,rcx,10
+	copy_round_keys rsp,rcx,11
+	copy_round_keys rsp,rcx,12
+	copy_round_keys rsp,rcx,13
+	copy_round_keys rsp,rcx,14
+	mov rcx,rsp	
+
+	align 16	
+	
+lp256encsingle_CBC:
+
+	movdqu xmm0, [rdx]
+	movdqu xmm4, [rcx+0*16]
+	add rdx, 16
+	pxor xmm0, xmm1
+	pxor xmm0, xmm4
+	aesenc1 [rcx+1*16]
+	aesenc1 [rcx+2*16]
+	aesenc1 [rcx+3*16]
+	aesenc1 [rcx+4*16]     
+	aesenc1 [rcx+5*16]
+	aesenc1 [rcx+6*16]
+	aesenc1 [rcx+7*16]
+	aesenc1 [rcx+8*16]
+	aesenc1 [rcx+9*16]
+	aesenc1 [rcx+10*16]
+	aesenc1 [rcx+11*16]
+	aesenc1 [rcx+12*16]
+	aesenc1 [rcx+13*16]
+	aesenclast1 [rcx+14*16]
+	movdqa xmm1,xmm0
+
+		; Store output encrypted data into CIPHERTEXT array
+	movdqu  [r8+rdx-16], xmm0
+	dec eax
+	jnz lp256encsingle_CBC
+
+	mov	   r9,[r9+24]
+	movdqu [r9],xmm1
+	add rsp,16*16+8
+	ret
+
+
+
+
+align 16
+global iEnc192
+iEnc192:
+
+	linux_setup
+	sub rsp,16*16+8
+	
+	mov eax,[rcx+32] ; numblocks
+	mov rdx,[rcx]
+	mov r8,[rcx+8]
+	mov rcx,[rcx+16]
+	
+	sub r8,rdx
+
+	test eax,eax
+	jz end_enc192
+	
+	cmp eax,4
+	jl lp192encsingle
+
+	test	rcx,0xf
+	jz		lpenc192four
+	
+	copy_round_keys rsp,rcx,0
+	copy_round_keys rsp,rcx,1
+	copy_round_keys rsp,rcx,2
+	copy_round_keys rsp,rcx,3
+	copy_round_keys rsp,rcx,4
+	copy_round_keys rsp,rcx,5
+	copy_round_keys rsp,rcx,6
+	copy_round_keys rsp,rcx,7
+	copy_round_keys rsp,rcx,8
+	copy_round_keys rsp,rcx,9
+	copy_round_keys rsp,rcx,10
+	copy_round_keys rsp,rcx,11
+	copy_round_keys rsp,rcx,12
+	mov rcx,rsp	
+
+
+	align 16	
+	
+lpenc192four:
+	
+	test eax,eax
+	jz end_enc192
+	
+	cmp eax,4
+	jl lp192encsingle
+
+	load_and_xor4 rdx,[rcx+0*16]
+	add rdx,4*16
+	aesenc4	[rcx+1*16]
+	aesenc4	[rcx+2*16]
+	aesenc4	[rcx+3*16]
+	aesenc4	[rcx+4*16]
+	aesenc4	[rcx+5*16]
+	aesenc4	[rcx+6*16]
+	aesenc4	[rcx+7*16]
+	aesenc4	[rcx+8*16]
+	aesenc4	[rcx+9*16]
+	aesenc4	[rcx+10*16]
+	aesenc4	[rcx+11*16]
+	aesenclast4	[rcx+12*16]
+	
+	store4 r8+rdx-16*4
+	sub eax,4
+	jmp lpenc192four
+	
+	align 16
+lp192encsingle:
+
+	movdqu xmm0, [rdx]
+	movdqu xmm4, [rcx+0*16]
+	add rdx, 16
+	pxor xmm0, xmm4
+	aesenc1_u [rcx+1*16]
+	aesenc1_u [rcx+2*16]
+	aesenc1_u [rcx+3*16]
+	aesenc1_u [rcx+4*16]     
+	aesenc1_u [rcx+5*16]
+	aesenc1_u [rcx+6*16]
+	aesenc1_u [rcx+7*16]
+	aesenc1_u [rcx+8*16]
+	aesenc1_u [rcx+9*16]
+	aesenc1_u [rcx+10*16]
+	aesenc1_u [rcx+11*16]
+	aesenclast1_u [rcx+12*16]
+
+		; Store output encrypted data into CIPHERTEXT array
+	movdqu  [r8+rdx-16], xmm0
+	dec eax
+	jnz lp192encsingle
+
+end_enc192:
+
+	add rsp,16*16+8
+	ret
+
+
+
+
+
+
+align 16
+global iEnc256
+iEnc256:
+
+	linux_setup
+	sub rsp,16*16+8
+	
+	mov eax,[rcx+32] ; numblocks
+	mov rdx,[rcx]
+	mov r8,[rcx+8]
+	mov rcx,[rcx+16]
+
+	sub r8,rdx	
+
+
+	test eax,eax
+	jz end_enc256
+
+	cmp eax,4
+	jl lp256enc
+
+	test	rcx,0xf
+	jz		lp256enc4
+	
+	copy_round_keys rsp,rcx,0
+	copy_round_keys rsp,rcx,1
+	copy_round_keys rsp,rcx,2
+	copy_round_keys rsp,rcx,3
+	copy_round_keys rsp,rcx,4
+	copy_round_keys rsp,rcx,5
+	copy_round_keys rsp,rcx,6
+	copy_round_keys rsp,rcx,7
+	copy_round_keys rsp,rcx,8
+	copy_round_keys rsp,rcx,9
+	copy_round_keys rsp,rcx,10
+	copy_round_keys rsp,rcx,11
+	copy_round_keys rsp,rcx,12
+	copy_round_keys rsp,rcx,13
+	copy_round_keys rsp,rcx,14
+	mov rcx,rsp	
+
+
+	align 16
+	
+lp256enc4:
+	test eax,eax
+	jz end_enc256
+
+	cmp eax,4
+	jl lp256enc
+
+
+	load_and_xor4 rdx,[rcx+0*16]
+	add rdx, 16*4
+	aesenc4 [rcx+1*16]
+	aesenc4 [rcx+2*16]
+	aesenc4 [rcx+3*16]
+	aesenc4 [rcx+4*16]
+	aesenc4 [rcx+5*16]
+	aesenc4 [rcx+6*16]
+	aesenc4 [rcx+7*16]
+	aesenc4 [rcx+8*16]
+	aesenc4 [rcx+9*16]
+	aesenc4 [rcx+10*16]
+	aesenc4 [rcx+11*16]
+	aesenc4 [rcx+12*16]
+	aesenc4 [rcx+13*16]
+	aesenclast4 [rcx+14*16]
+
+	store4  r8+rdx-16*4
+	sub eax,4
+	jmp lp256enc4
+	
+	align 16
+lp256enc:
+
+	movdqu xmm0, [rdx]
+	movdqu xmm4, [rcx+0*16]
+	add rdx, 16
+	pxor xmm0, xmm4
+	aesenc1_u [rcx+1*16]
+	aesenc1_u [rcx+2*16]
+	aesenc1_u [rcx+3*16]
+	aesenc1_u [rcx+4*16]
+	aesenc1_u [rcx+5*16]
+	aesenc1_u [rcx+6*16]
+	aesenc1_u [rcx+7*16]
+	aesenc1_u [rcx+8*16]
+	aesenc1_u [rcx+9*16]
+	aesenc1_u [rcx+10*16]
+	aesenc1_u [rcx+11*16]
+	aesenc1_u [rcx+12*16]
+	aesenc1_u [rcx+13*16]
+	aesenclast1_u [rcx+14*16]
+
+		; Store output encrypted data into CIPHERTEXT array
+	movdqu  [r8+rdx-16], xmm0
+	dec eax
+	jnz lp256enc
+
+end_enc256:
+
+	add rsp,16*16+8
+	ret
diff --git a/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/asm/x86/do_rdtsc.s b/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/asm/x86/do_rdtsc.s
new file mode 100644
--- /dev/null
+++ b/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/asm/x86/do_rdtsc.s
@@ -0,0 +1,35 @@
+[bits 32]
+[CPU intelnop]
+
+; Copyright (c) 2010, Intel Corporation
+; All rights reserved.
+; 
+; Redistribution and use in source and binary forms, with or without 
+; modification, are permitted provided that the following conditions are met:
+; 
+;     * Redistributions of source code must retain the above copyright notice, 
+;       this list of conditions and the following disclaimer.
+;     * 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.
+;     * Neither the name of Intel Corporation nor the names of its contributors 
+;       may be used to endorse or promote products derived from this software 
+;       without specific prior written permission.
+; 
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+
+align 16
+global _do_rdtsc
+_do_rdtsc:
+
+	rdtsc
+	ret
diff --git a/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/asm/x86/iaesx86.s b/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/asm/x86/iaesx86.s
new file mode 100644
--- /dev/null
+++ b/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/asm/x86/iaesx86.s
@@ -0,0 +1,2183 @@
+[bits 32]
+[CPU intelnop]
+
+; Copyright (c) 2010, Intel Corporation
+; All rights reserved.
+; 
+; Redistribution and use in source and binary forms, with or without 
+; modification, are permitted provided that the following conditions are met:
+; 
+;     * Redistributions of source code must retain the above copyright notice, 
+;       this list of conditions and the following disclaimer.
+;     * 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.
+;     * Neither the name of Intel Corporation nor the names of its contributors 
+;       may be used to endorse or promote products derived from this software 
+;       without specific prior written permission.
+; 
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+
+
+%macro inversekey 1
+	movdqu  xmm1,%1
+	aesimc	xmm0,xmm1
+	movdqu	%1,xmm0
+%endmacro
+
+
+%macro aesdec4 1
+	movdqa	xmm4,%1
+
+	aesdec	xmm0,xmm4
+	aesdec	xmm1,xmm4
+	aesdec	xmm2,xmm4
+	aesdec	xmm3,xmm4
+
+%endmacro
+
+
+%macro aesdeclast4 1
+	movdqa	xmm4,%1
+
+	aesdeclast	xmm0,xmm4
+	aesdeclast	xmm1,xmm4
+	aesdeclast	xmm2,xmm4
+	aesdeclast	xmm3,xmm4
+
+%endmacro
+
+
+%macro aesenc4 1
+	movdqa	xmm4,%1
+
+	aesenc	xmm0,xmm4
+	aesenc	xmm1,xmm4
+	aesenc	xmm2,xmm4
+	aesenc	xmm3,xmm4
+
+%endmacro
+
+%macro aesenclast4 1
+	movdqa	xmm4,%1
+
+	aesenclast	xmm0,xmm4
+	aesenclast	xmm1,xmm4
+	aesenclast	xmm2,xmm4
+	aesenclast	xmm3,xmm4
+
+%endmacro
+
+
+%macro aesdeclast1 1
+	aesdeclast	xmm0,%1
+%endmacro
+
+%macro aesenclast1 1
+	aesenclast	xmm0,%1
+%endmacro
+
+%macro aesdec1 1
+	aesdec	xmm0,%1
+%endmacro
+
+;abab
+%macro aesenc1 1
+	aesenc	xmm0,%1
+%endmacro
+
+
+%macro aesdeclast1_u 1
+	movdqu xmm4,%1
+	aesdeclast	xmm0,xmm4
+%endmacro
+
+%macro aesenclast1_u 1
+	movdqu xmm4,%1
+	aesenclast	xmm0,xmm4
+%endmacro
+
+%macro aesdec1_u 1
+	movdqu xmm4,%1
+	aesdec	xmm0,xmm4
+%endmacro
+
+%macro aesenc1_u 1
+	movdqu xmm4,%1
+	aesenc	xmm0,xmm4
+%endmacro
+
+
+%macro load_and_xor4 2
+	movdqa	xmm4,%2
+	movdqu	xmm0,[%1 + 0*16]
+	pxor	xmm0,xmm4
+	movdqu	xmm1,[%1 + 1*16]
+	pxor	xmm1,xmm4
+	movdqu	xmm2,[%1 + 2*16]
+	pxor	xmm2,xmm4
+	movdqu	xmm3,[%1 + 3*16]
+	pxor	xmm3,xmm4
+%endmacro
+
+
+%macro load_and_inc4 1
+	movdqa	xmm4,%1
+	movdqa	xmm0,xmm5
+	movdqa  xmm1,xmm5
+	paddq	xmm1,[counter_add_one]
+	movdqa  xmm2,xmm5
+	paddq	xmm2,[counter_add_two]
+	movdqa  xmm3,xmm5
+	paddq	xmm3,[counter_add_three]
+	pxor	xmm0,xmm4
+	paddq	xmm5,[counter_add_four]
+	pxor	xmm1,xmm4
+	pxor	xmm2,xmm4
+	pxor	xmm3,xmm4
+%endmacro
+
+%macro xor_with_input4 1
+	movdqu xmm4,[%1]
+	pxor xmm0,xmm4
+	movdqu xmm4,[%1+16]
+	pxor xmm1,xmm4
+	movdqu xmm4,[%1+32]
+	pxor xmm2,xmm4
+	movdqu xmm4,[%1+48]
+	pxor xmm3,xmm4
+%endmacro
+
+%macro store4 1
+	movdqu [%1 + 0*16],xmm0
+	movdqu [%1 + 1*16],xmm1
+	movdqu [%1 + 2*16],xmm2
+	movdqu [%1 + 3*16],xmm3
+%endmacro
+
+
+%macro copy_round_keys 3
+	movdqu xmm4,[%2 + ((%3)*16)]
+	movdqa [%1 + ((%3)*16)],xmm4
+%endmacro
+
+;abab
+%macro copy_round_keyx 3
+	movdqu xmm4,[%2 + ((%3)*16)]
+	movdqa %1,xmm4
+%endmacro
+
+
+
+%macro key_expansion_1_192 1
+		;; Assumes the xmm3 includes all zeros at this point. 
+        pshufd xmm2, xmm2, 11111111b        
+        shufps xmm3, xmm1, 00010000b        
+        pxor xmm1, xmm3        
+        shufps xmm3, xmm1, 10001100b
+        pxor xmm1, xmm3        
+		pxor xmm1, xmm2		
+		movdqu [edx+%1], xmm1			
+%endmacro
+
+; Calculate w10 and w11 using calculated w9 and known w4-w5
+%macro key_expansion_2_192 1				
+		movdqa xmm5, xmm4
+		pslldq xmm5, 4
+		shufps xmm6, xmm1, 11110000b
+		pxor xmm6, xmm5
+		pxor xmm4, xmm6
+		pshufd xmm7, xmm4, 00001110b 
+		movdqu [edx+%1], xmm7
+%endmacro
+
+
+
+
+
+section .data
+align 16
+shuffle_mask:
+DD 0FFFFFFFFh
+DD 03020100h
+DD 07060504h
+DD 0B0A0908h
+
+align 16
+counter_add_one:
+DD 1
+DD 0
+DD 0
+DD 0
+
+counter_add_two:
+DD 2
+DD 0
+DD 0
+DD 0
+
+counter_add_three:
+DD 3
+DD 0
+DD 0
+DD 0
+
+counter_add_four:
+DD 4
+DD 0
+DD 0
+DD 0
+
+
+section .text
+
+
+
+align 16
+key_expansion256:
+
+    pshufd xmm2, xmm2, 011111111b
+
+    movdqu xmm4, xmm1
+    pshufb xmm4, xmm5
+    pxor xmm1, xmm4
+    pshufb xmm4, xmm5
+    pxor xmm1, xmm4
+    pshufb xmm4, xmm5
+    pxor xmm1, xmm4
+    pxor xmm1, xmm2
+
+    movdqu [edx], xmm1
+    add edx, 0x10
+    
+    aeskeygenassist xmm4, xmm1, 0
+    pshufd xmm2, xmm4, 010101010b
+
+    movdqu xmm4, xmm3
+    pshufb xmm4, xmm5
+    pxor xmm3, xmm4
+    pshufb xmm4, xmm5
+    pxor xmm3, xmm4
+    pshufb xmm4, xmm5
+    pxor xmm3, xmm4
+    pxor xmm3, xmm2
+
+    movdqu [edx], xmm3
+    add edx, 0x10
+
+    ret
+
+
+
+align 16
+key_expansion128: 
+    pshufd xmm2, xmm2, 0xFF;
+    movdqu xmm3, xmm1
+    pshufb xmm3, xmm5
+    pxor xmm1, xmm3
+    pshufb xmm3, xmm5
+    pxor xmm1, xmm3
+    pshufb xmm3, xmm5
+    pxor xmm1, xmm3
+    pxor xmm1, xmm2
+
+    ; storing the result in the key schedule array
+    movdqu [edx], xmm1
+    add edx, 0x10                    
+    ret
+
+
+
+align 16
+global _iEncExpandKey128
+_iEncExpandKey128:
+
+	mov ecx,[esp-4+8]		;input
+	mov edx,[esp-4+12]		;ctx
+
+        movdqu xmm1, [ecx]    ; loading the key
+
+        movdqu [edx], xmm1
+
+        movdqa xmm5, [shuffle_mask]
+
+        add edx,16
+
+        aeskeygenassist xmm2, xmm1, 0x1     ; Generating round key 1
+        call key_expansion128
+        aeskeygenassist xmm2, xmm1, 0x2     ; Generating round key 2
+        call key_expansion128
+        aeskeygenassist xmm2, xmm1, 0x4     ; Generating round key 3
+        call key_expansion128
+        aeskeygenassist xmm2, xmm1, 0x8     ; Generating round key 4
+        call key_expansion128
+        aeskeygenassist xmm2, xmm1, 0x10    ; Generating round key 5
+        call key_expansion128
+        aeskeygenassist xmm2, xmm1, 0x20    ; Generating round key 6
+        call key_expansion128
+        aeskeygenassist xmm2, xmm1, 0x40    ; Generating round key 7
+        call key_expansion128
+        aeskeygenassist xmm2, xmm1, 0x80    ; Generating round key 8
+        call key_expansion128
+        aeskeygenassist xmm2, xmm1, 0x1b    ; Generating round key 9
+        call key_expansion128
+        aeskeygenassist xmm2, xmm1, 0x36    ; Generating round key 10
+        call key_expansion128
+
+	ret
+
+
+align 16
+global _iEncExpandKey192
+_iEncExpandKey192:
+
+	mov ecx,[esp-4+8]		;input
+	mov edx,[esp-4+12]		;ctx
+
+        movq xmm7, [ecx+16]	; loading the AES key
+        movq [edx+16], xmm7  ; Storing key in memory where all key expansion 
+        pshufd xmm4, xmm7, 01001111b
+        movdqu xmm1, [ecx]	; loading the AES key
+        movdqu [edx], xmm1  ; Storing key in memory where all key expansion 
+			
+        pxor xmm3, xmm3		; Set xmm3 to be all zeros. Required for the key_expansion. 
+        pxor xmm6, xmm6		; Set xmm3 to be all zeros. Required for the key_expansion. 
+
+        aeskeygenassist xmm2, xmm4, 0x1     ; Complete round key 1 and generate round key 2 
+        key_expansion_1_192 24
+	key_expansion_2_192 40				
+
+        aeskeygenassist xmm2, xmm4, 0x2     ; Generate round key 3 and part of round key 4
+        key_expansion_1_192 48
+	key_expansion_2_192 64				
+
+        aeskeygenassist xmm2, xmm4, 0x4     ; Complete round key 4 and generate round key 5
+        key_expansion_1_192 72
+	key_expansion_2_192 88
+		
+        aeskeygenassist xmm2, xmm4, 0x8     ; Generate round key 6 and part of round key 7
+        key_expansion_1_192 96
+	key_expansion_2_192 112
+		
+        aeskeygenassist xmm2, xmm4, 0x10     ; Complete round key 7 and generate round key 8 
+        key_expansion_1_192 120
+	key_expansion_2_192 136				
+
+        aeskeygenassist xmm2, xmm4, 0x20     ; Generate round key 9 and part of round key 10
+        key_expansion_1_192 144
+	key_expansion_2_192 160				
+
+        aeskeygenassist xmm2, xmm4, 0x40     ; Complete round key 10 and generate round key 11
+        key_expansion_1_192 168
+	key_expansion_2_192 184				
+
+        aeskeygenassist xmm2, xmm4, 0x80     ; Generate round key 12
+        key_expansion_1_192 192
+
+	ret
+
+
+
+
+
+
+align 16
+global _iDecExpandKey128
+_iDecExpandKey128:
+	push DWORD [esp+8]
+	push DWORD [esp+8]
+	
+	call _iEncExpandKey128
+	add esp,8
+
+	mov edx,[esp-4+12]		;ctx
+	
+	inversekey	[edx + 1*16]
+	inversekey	[edx + 2*16]
+	inversekey	[edx + 3*16]
+	inversekey	[edx + 4*16]
+	inversekey	[edx + 5*16]
+	inversekey	[edx + 6*16]
+	inversekey	[edx + 7*16]
+	inversekey	[edx + 8*16]
+	inversekey	[edx + 9*16]
+
+	ret
+
+
+
+
+align 16
+global _iDecExpandKey192
+_iDecExpandKey192:
+	push DWORD [esp+8]
+	push DWORD [esp+8]
+	
+	call _iEncExpandKey192
+	add esp,8
+
+	mov edx,[esp-4+12]		;ctx
+	
+	inversekey	[edx + 1*16]
+	inversekey	[edx + 2*16]
+	inversekey	[edx + 3*16]
+	inversekey	[edx + 4*16]
+	inversekey	[edx + 5*16]
+	inversekey	[edx + 6*16]
+	inversekey	[edx + 7*16]
+	inversekey	[edx + 8*16]
+	inversekey	[edx + 9*16]
+	inversekey	[edx + 10*16]
+	inversekey	[edx + 11*16]
+
+	ret
+
+
+
+
+align 16
+global _iDecExpandKey256
+_iDecExpandKey256:
+	push DWORD [esp+8]
+	push DWORD [esp+8]
+	
+	call _iEncExpandKey256
+	add esp, 8
+
+	mov edx, [esp-4+12]		;expanded key
+	
+	inversekey	[edx + 1*16]
+	inversekey	[edx + 2*16]
+	inversekey	[edx + 3*16]
+	inversekey	[edx + 4*16]
+	inversekey	[edx + 5*16]
+	inversekey	[edx + 6*16]
+	inversekey	[edx + 7*16]
+	inversekey	[edx + 8*16]
+	inversekey	[edx + 9*16]
+	inversekey	[edx + 10*16]
+	inversekey	[edx + 11*16]
+	inversekey	[edx + 12*16]
+	inversekey	[edx + 13*16]
+
+	ret
+	
+
+	
+	
+align 16
+global _iEncExpandKey256
+_iEncExpandKey256:
+	mov ecx, [esp-4+8]		;input
+	mov edx, [esp-4+12]		;expanded key
+
+
+    movdqu xmm1, [ecx]    ; loading the key
+    movdqu xmm3, [ecx+16]
+    movdqu [edx], xmm1  ; Storing key in memory where all key schedule will be stored
+    movdqu [edx+16], xmm3 
+    
+    add edx,32
+
+    movdqa xmm5, [shuffle_mask]  ; this mask is used by key_expansion
+
+    aeskeygenassist xmm2, xmm3, 0x1     ; 
+    call key_expansion256
+    aeskeygenassist xmm2, xmm3, 0x2     ; 
+    call key_expansion256
+    aeskeygenassist xmm2, xmm3, 0x4     ; 
+    call key_expansion256
+    aeskeygenassist xmm2, xmm3, 0x8     ; 
+    call key_expansion256
+    aeskeygenassist xmm2, xmm3, 0x10    ; 
+    call key_expansion256
+    aeskeygenassist xmm2, xmm3, 0x20    ; 
+    call key_expansion256
+    aeskeygenassist xmm2, xmm3, 0x40    ; 
+;    call key_expansion256 
+
+    pshufd xmm2, xmm2, 011111111b
+
+    movdqu xmm4, xmm1
+    pshufb xmm4, xmm5
+    pxor xmm1, xmm4
+    pshufb xmm4, xmm5
+    pxor xmm1, xmm4
+    pshufb xmm4, xmm5
+    pxor xmm1, xmm4
+    pxor xmm1, xmm2
+
+    movdqu [edx], xmm1
+
+
+	ret
+	
+	
+	
+	
+	
+
+align 16
+global _iDec128
+_iDec128:
+	mov ecx,[esp-4+8]
+	
+	push esi
+	push edi
+	push ebp
+	mov ebp,esp
+	
+	sub esp,16*16
+	and esp,0xfffffff0
+	
+	mov eax,[ecx+16] ; numblocks
+	mov esi,[ecx]
+	mov edi,[ecx+4]
+	mov ecx,[ecx+8]
+
+	sub edi,esi
+	
+	test eax,eax
+	jz end_dec128
+
+	cmp eax,4
+	jl	lp128decsingle
+
+	test	ecx,0xf
+	jz		lp128decfour
+	
+	copy_round_keys esp,ecx,0
+	copy_round_keys esp,ecx,1
+	copy_round_keys esp,ecx,2
+	copy_round_keys esp,ecx,3
+	copy_round_keys esp,ecx,4
+	copy_round_keys esp,ecx,5
+	copy_round_keys esp,ecx,6
+	copy_round_keys esp,ecx,7
+	copy_round_keys esp,ecx,8
+	copy_round_keys esp,ecx,9
+	copy_round_keys esp,ecx,10
+	mov ecx,esp	
+	
+
+align 16
+lp128decfour:
+	
+	test eax,eax
+	jz end_dec128
+
+	cmp eax,4
+	jl	lp128decsingle
+
+	load_and_xor4 esi, [ecx+10*16]
+	add esi,16*4
+	aesdec4 [ecx+9*16]
+	aesdec4 [ecx+8*16]
+	aesdec4 [ecx+7*16]
+	aesdec4 [ecx+6*16]
+	aesdec4 [ecx+5*16]
+	aesdec4 [ecx+4*16]
+	aesdec4 [ecx+3*16]
+	aesdec4 [ecx+2*16]
+	aesdec4 [ecx+1*16]
+	aesdeclast4 [ecx+0*16]
+	
+	sub eax,4
+	store4 esi+edi-(16*4)
+	jmp lp128decfour
+
+
+	align 16
+lp128decsingle:
+
+	movdqu xmm0, [esi]
+	movdqu xmm4,[ecx+10*16]
+	pxor xmm0, xmm4
+	aesdec1_u  [ecx+9*16]
+	aesdec1_u  [ecx+8*16]
+	aesdec1_u  [ecx+7*16]
+	aesdec1_u  [ecx+6*16]
+	aesdec1_u  [ecx+5*16]
+	aesdec1_u  [ecx+4*16]
+	aesdec1_u  [ecx+3*16]
+	aesdec1_u  [ecx+2*16]
+	aesdec1_u  [ecx+1*16]
+	aesdeclast1_u [ecx+0*16]
+
+	add esi, 16
+	movdqu  [edi+esi - 16], xmm0
+	dec eax
+	jnz lp128decsingle
+
+end_dec128:
+
+	mov esp,ebp
+	pop ebp
+	pop edi
+	pop esi
+	
+	ret
+
+
+
+align 16
+global _iDec128_CBC
+_iDec128_CBC:
+	mov ecx,[esp-4+8]
+	
+	push esi
+	push edi
+	push ebp
+	mov ebp,esp
+	sub esp,16*16
+	and esp,0xfffffff0
+	
+	mov eax,[ecx+12]
+	movdqu xmm5,[eax]	;iv
+	
+	mov eax,[ecx+16] ; numblocks
+	mov esi,[ecx]
+	mov edi,[ecx+4]
+	mov ecx,[ecx+8]
+	
+	sub edi,esi
+
+	test eax,eax
+	jz end_dec128_CBC
+
+	cmp eax,4
+	jl	lp128decsingle_CBC
+
+	test	ecx,0xf
+	jz		lp128decfour_CBC
+	
+	copy_round_keys esp,ecx,0
+	copy_round_keys esp,ecx,1
+	copy_round_keys esp,ecx,2
+	copy_round_keys esp,ecx,3
+	copy_round_keys esp,ecx,4
+	copy_round_keys esp,ecx,5
+	copy_round_keys esp,ecx,6
+	copy_round_keys esp,ecx,7
+	copy_round_keys esp,ecx,8
+	copy_round_keys esp,ecx,9
+	copy_round_keys esp,ecx,10
+	mov ecx,esp	
+
+
+align 16
+lp128decfour_CBC:
+	
+	test eax,eax
+	jz end_dec128_CBC
+
+	cmp eax,4
+	jl	lp128decsingle_CBC
+
+	load_and_xor4 esi, [ecx+10*16]
+	add esi,16*4
+	aesdec4 [ecx+9*16]
+	aesdec4 [ecx+8*16]
+	aesdec4 [ecx+7*16]
+	aesdec4 [ecx+6*16]
+	aesdec4 [ecx+5*16]
+	aesdec4 [ecx+4*16]
+	aesdec4 [ecx+3*16]
+	aesdec4 [ecx+2*16]
+	aesdec4 [ecx+1*16]
+	aesdeclast4 [ecx+0*16]
+	
+	pxor	xmm0,xmm5
+	movdqu	xmm4,[esi- 16*4 + 0*16]
+	pxor	xmm1,xmm4
+	movdqu	xmm4,[esi- 16*4 + 1*16]
+	pxor	xmm2,xmm4
+	movdqu	xmm4,[esi- 16*4 + 2*16]
+	pxor	xmm3,xmm4
+	movdqu	xmm5,[esi- 16*4 + 3*16]
+	
+	sub eax,4
+	store4 esi+edi-(16*4)
+	jmp lp128decfour_CBC
+
+
+	align 16
+lp128decsingle_CBC:
+
+	movdqu xmm0, [esi]
+	movdqa xmm1,xmm0
+	movdqu xmm4,[ecx+10*16]
+	pxor xmm0, xmm4
+	aesdec1_u  [ecx+9*16]
+	aesdec1_u  [ecx+8*16]
+	aesdec1_u  [ecx+7*16]
+	aesdec1_u  [ecx+6*16]
+	aesdec1_u  [ecx+5*16]
+	aesdec1_u  [ecx+4*16]
+	aesdec1_u  [ecx+3*16]
+	aesdec1_u  [ecx+2*16]
+	aesdec1_u  [ecx+1*16]
+	aesdeclast1_u [ecx+0*16]
+	
+	pxor	xmm0,xmm5
+	movdqa	xmm5,xmm1
+	
+	add esi, 16
+	movdqu  [edi+esi - 16], xmm0
+	dec eax
+	jnz lp128decsingle_CBC
+
+end_dec128_CBC:
+
+	mov esp,ebp
+	pop ebp
+	pop edi
+	pop esi
+
+	mov ecx,[esp-4+8]   ; first arg
+	mov ecx,[ecx+12]
+	movdqu	[ecx],xmm5 ; store last iv for chaining
+	
+	ret
+
+
+
+
+
+
+align 16
+global _iDec192
+_iDec192:
+	mov ecx,[esp-4+8]
+	
+	push esi
+	push edi
+	push ebp
+	mov ebp,esp
+	
+	sub esp,16*16
+	and esp,0xfffffff0
+	
+	mov eax,[ecx+16] ; numblocks
+	mov esi,[ecx]
+	mov edi,[ecx+4]
+	mov ecx,[ecx+8]
+	
+	sub edi,esi
+
+	test eax,eax
+	jz end_dec192
+
+	cmp eax,4
+	jl	lp192decsingle
+
+	test	ecx,0xf
+	jz		lp192decfour
+	
+	copy_round_keys esp,ecx,0
+	copy_round_keys esp,ecx,1
+	copy_round_keys esp,ecx,2
+	copy_round_keys esp,ecx,3
+	copy_round_keys esp,ecx,4
+	copy_round_keys esp,ecx,5
+	copy_round_keys esp,ecx,6
+	copy_round_keys esp,ecx,7
+	copy_round_keys esp,ecx,8
+	copy_round_keys esp,ecx,9
+	copy_round_keys esp,ecx,10
+	copy_round_keys esp,ecx,11
+	copy_round_keys esp,ecx,12
+	mov ecx,esp	
+
+
+align 16
+lp192decfour:
+	
+	test eax,eax
+	jz end_dec192
+
+	cmp eax,4
+	jl	lp192decsingle
+
+	load_and_xor4 esi, [ecx+12*16]
+	add esi,16*4
+	aesdec4 [ecx+11*16]
+	aesdec4 [ecx+10*16]
+	aesdec4 [ecx+9*16]
+	aesdec4 [ecx+8*16]
+	aesdec4 [ecx+7*16]
+	aesdec4 [ecx+6*16]
+	aesdec4 [ecx+5*16]
+	aesdec4 [ecx+4*16]
+	aesdec4 [ecx+3*16]
+	aesdec4 [ecx+2*16]
+	aesdec4 [ecx+1*16]
+	aesdeclast4 [ecx+0*16]
+	
+	sub eax,4
+	store4 esi+edi-(16*4)
+	jmp lp192decfour
+
+
+	align 16
+lp192decsingle:
+
+	movdqu xmm0, [esi]
+	movdqu xmm4,[ecx+12*16]
+	pxor xmm0, xmm4
+	aesdec1_u [ecx+11*16]
+	aesdec1_u  [ecx+10*16]
+	aesdec1_u  [ecx+9*16]
+	aesdec1_u  [ecx+8*16]
+	aesdec1_u  [ecx+7*16]
+	aesdec1_u  [ecx+6*16]
+	aesdec1_u  [ecx+5*16]
+	aesdec1_u  [ecx+4*16]
+	aesdec1_u  [ecx+3*16]
+	aesdec1_u  [ecx+2*16]
+	aesdec1_u  [ecx+1*16]
+	aesdeclast1_u  [ecx+0*16]
+
+	add esi, 16
+	movdqu  [edi+esi - 16], xmm0
+	dec eax
+	jnz lp192decsingle
+
+end_dec192:
+
+
+	mov esp,ebp
+	pop ebp
+	pop edi
+	pop esi
+	
+	ret
+
+
+align 16
+global _iDec192_CBC
+_iDec192_CBC:
+	mov ecx,[esp-4+8]
+	
+	push esi
+	push edi
+	push ebp
+	mov ebp,esp
+	
+	sub esp,16*16
+	and esp,0xfffffff0
+
+	mov eax,[ecx+12]
+	movdqu xmm5,[eax]	;iv
+	
+	mov eax,[ecx+16] ; numblocks
+	mov esi,[ecx]
+	mov edi,[ecx+4]
+	mov ecx,[ecx+8]
+	
+	sub edi,esi
+
+	test eax,eax
+	jz end_dec192_CBC
+
+	cmp eax,4
+	jl	lp192decsingle_CBC
+
+	test	ecx,0xf
+	jz		lp192decfour_CBC
+	
+	copy_round_keys esp,ecx,0
+	copy_round_keys esp,ecx,1
+	copy_round_keys esp,ecx,2
+	copy_round_keys esp,ecx,3
+	copy_round_keys esp,ecx,4
+	copy_round_keys esp,ecx,5
+	copy_round_keys esp,ecx,6
+	copy_round_keys esp,ecx,7
+	copy_round_keys esp,ecx,8
+	copy_round_keys esp,ecx,9
+	copy_round_keys esp,ecx,10
+	copy_round_keys esp,ecx,11
+	copy_round_keys esp,ecx,12
+	mov ecx,esp	
+
+align 16
+lp192decfour_CBC:
+	
+	test eax,eax
+	jz end_dec192_CBC
+
+	cmp eax,4
+	jl	lp192decsingle_CBC
+
+	load_and_xor4 esi, [ecx+12*16]
+	add esi,16*4
+	aesdec4 [ecx+11*16]
+	aesdec4 [ecx+10*16]
+	aesdec4 [ecx+9*16]
+	aesdec4 [ecx+8*16]
+	aesdec4 [ecx+7*16]
+	aesdec4 [ecx+6*16]
+	aesdec4 [ecx+5*16]
+	aesdec4 [ecx+4*16]
+	aesdec4 [ecx+3*16]
+	aesdec4 [ecx+2*16]
+	aesdec4 [ecx+1*16]
+	aesdeclast4 [ecx+0*16]
+	
+	pxor	xmm0,xmm5
+	movdqu	xmm4,[esi- 16*4 + 0*16]
+	pxor	xmm1,xmm4
+	movdqu	xmm4,[esi- 16*4 + 1*16]
+	pxor	xmm2,xmm4
+	movdqu	xmm4,[esi- 16*4 + 2*16]
+	pxor	xmm3,xmm4
+	movdqu	xmm5,[esi- 16*4 + 3*16]
+	
+	sub eax,4
+	store4 esi+edi-(16*4)
+	jmp lp192decfour_CBC
+
+
+	align 16
+lp192decsingle_CBC:
+
+	movdqu xmm0, [esi]
+	movdqu xmm4,[ecx+12*16]
+	movdqa xmm1,xmm0
+	pxor xmm0, xmm4
+	aesdec1_u [ecx+11*16]
+	aesdec1_u [ecx+10*16]
+	aesdec1_u [ecx+9*16]
+	aesdec1_u [ecx+8*16]
+	aesdec1_u [ecx+7*16]
+	aesdec1_u [ecx+6*16]
+	aesdec1_u [ecx+5*16]
+	aesdec1_u [ecx+4*16]
+	aesdec1_u [ecx+3*16]
+	aesdec1_u [ecx+2*16]
+	aesdec1_u [ecx+1*16]
+	aesdeclast1_u [ecx+0*16]
+	
+	pxor	xmm0,xmm5
+	movdqa	xmm5,xmm1
+	
+	add esi, 16
+	movdqu  [edi+esi - 16], xmm0
+	dec eax
+	jnz lp192decsingle_CBC
+
+end_dec192_CBC:
+
+
+	mov esp,ebp
+	pop ebp
+	pop edi
+	pop esi
+
+	mov ecx,[esp-4+8]
+	mov ecx,[ecx+12]
+	movdqu	[ecx],xmm5 ; store last iv for chaining
+	
+	ret
+
+
+
+
+
+align 16
+global _iDec256
+_iDec256:
+	mov ecx, [esp-4+8]
+	
+	push esi
+	push edi
+	push ebp
+	mov ebp,esp
+	
+	sub esp,16*16
+	and esp,0xfffffff0
+
+	mov eax,[ecx+16] ; numblocks
+	mov esi,[ecx]
+	mov edi,[ecx+4]
+	mov ecx,[ecx+8]
+	
+	sub edi,esi
+
+
+	test eax,eax
+	jz end_dec256
+	
+	cmp eax,4
+	jl lp256dec
+
+	test	ecx,0xf
+	jz	lp256dec4
+	
+	copy_round_keys esp,ecx,0
+	copy_round_keys esp,ecx,1
+	copy_round_keys esp,ecx,2
+	copy_round_keys esp,ecx,3
+	copy_round_keys esp,ecx,4
+	copy_round_keys esp,ecx,5
+	copy_round_keys esp,ecx,6
+	copy_round_keys esp,ecx,7
+	copy_round_keys esp,ecx,8
+	copy_round_keys esp,ecx,9
+	copy_round_keys esp,ecx,10
+	copy_round_keys esp,ecx,11
+	copy_round_keys esp,ecx,12
+	copy_round_keys esp,ecx,13
+	copy_round_keys esp,ecx,14
+	mov ecx,esp	
+	
+	align 16
+lp256dec4:
+	test eax,eax
+	jz end_dec256
+	
+	cmp eax,4
+	jl lp256dec
+	
+	load_and_xor4 esi,[ecx+14*16]
+	add esi, 4*16
+	aesdec4 [ecx+13*16]
+	aesdec4 [ecx+12*16]
+	aesdec4 [ecx+11*16]
+	aesdec4 [ecx+10*16]
+	aesdec4 [ecx+9*16]
+	aesdec4 [ecx+8*16]
+	aesdec4 [ecx+7*16]
+	aesdec4 [ecx+6*16]
+	aesdec4 [ecx+5*16]
+	aesdec4 [ecx+4*16]
+	aesdec4 [ecx+3*16]
+	aesdec4 [ecx+2*16]
+	aesdec4 [ecx+1*16]
+	aesdeclast4 [ecx+0*16]
+
+	store4 esi+edi-16*4
+	sub eax,4
+	jmp lp256dec4	
+	
+	align 16
+lp256dec:
+
+	movdqu xmm0, [esi]
+	movdqu xmm4,[ecx+14*16]
+	add esi, 16
+	pxor xmm0, xmm4                     ; Round 0 (only xor)
+	aesdec1_u  [ecx+13*16]
+	aesdec1_u  [ecx+12*16]
+	aesdec1_u  [ecx+11*16]
+	aesdec1_u  [ecx+10*16]
+	aesdec1_u  [ecx+9*16]
+	aesdec1_u  [ecx+8*16]
+	aesdec1_u  [ecx+7*16]
+	aesdec1_u  [ecx+6*16]
+	aesdec1_u  [ecx+5*16]
+	aesdec1_u  [ecx+4*16]
+	aesdec1_u  [ecx+3*16]
+	aesdec1_u  [ecx+2*16]
+	aesdec1_u  [ecx+1*16]
+	aesdeclast1_u  [ecx+0*16]
+
+		; Store output encrypted data into CIPHERTEXT array
+	movdqu  [esi+edi-16], xmm0
+	dec eax
+	jnz lp256dec
+
+end_dec256:
+
+
+	mov esp,ebp
+	pop ebp
+	pop edi
+	pop esi
+	
+	ret
+
+
+
+
+align 16
+global _iDec256_CBC
+_iDec256_CBC:
+	mov ecx,[esp-4+8]
+	
+	push esi
+	push edi
+	push ebp
+	mov ebp,esp
+	
+	sub esp,16*16
+	and esp,0xfffffff0
+
+	mov eax,[ecx+12]
+	movdqu xmm5,[eax]	;iv
+	
+	mov eax,[ecx+16] ; numblocks
+	mov esi,[ecx]
+	mov edi,[ecx+4]
+	mov ecx,[ecx+8]
+	
+	sub edi,esi
+
+	test eax,eax
+	jz end_dec256_CBC
+
+	cmp eax,4
+	jl	lp256decsingle_CBC
+
+	test	ecx,0xf
+	jz	lp256decfour_CBC
+	
+	copy_round_keys esp,ecx,0
+	copy_round_keys esp,ecx,1
+	copy_round_keys esp,ecx,2
+	copy_round_keys esp,ecx,3
+	copy_round_keys esp,ecx,4
+	copy_round_keys esp,ecx,5
+	copy_round_keys esp,ecx,6
+	copy_round_keys esp,ecx,7
+	copy_round_keys esp,ecx,8
+	copy_round_keys esp,ecx,9
+	copy_round_keys esp,ecx,10
+	copy_round_keys esp,ecx,11
+	copy_round_keys esp,ecx,12
+	copy_round_keys esp,ecx,13
+	copy_round_keys esp,ecx,14
+	mov ecx,esp	
+
+align 16
+lp256decfour_CBC:
+	
+	test eax,eax
+	jz end_dec256_CBC
+
+	cmp eax,4
+	jl	lp256decsingle_CBC
+
+	load_and_xor4 esi, [ecx+14*16]
+	add esi,16*4
+	aesdec4 [ecx+13*16]
+	aesdec4 [ecx+12*16]
+	aesdec4 [ecx+11*16]
+	aesdec4 [ecx+10*16]
+	aesdec4 [ecx+9*16]
+	aesdec4 [ecx+8*16]
+	aesdec4 [ecx+7*16]
+	aesdec4 [ecx+6*16]
+	aesdec4 [ecx+5*16]
+	aesdec4 [ecx+4*16]
+	aesdec4 [ecx+3*16]
+	aesdec4 [ecx+2*16]
+	aesdec4 [ecx+1*16]
+	aesdeclast4 [ecx+0*16]
+	
+	pxor	xmm0,xmm5
+	movdqu	xmm4,[esi- 16*4 + 0*16]
+	pxor	xmm1,xmm4
+	movdqu	xmm4,[esi- 16*4 + 1*16]
+	pxor	xmm2,xmm4
+	movdqu	xmm4,[esi- 16*4 + 2*16]
+	pxor	xmm3,xmm4
+	movdqu	xmm5,[esi- 16*4 + 3*16]
+	
+	sub eax,4
+	store4 esi+edi-(16*4)
+	jmp lp256decfour_CBC
+
+
+	align 16
+lp256decsingle_CBC:
+
+	movdqu xmm0, [esi]
+	movdqa xmm1,xmm0
+	movdqu xmm4, [ecx+14*16]
+	pxor xmm0, xmm4
+	aesdec1_u  [ecx+13*16]
+	aesdec1_u  [ecx+12*16]
+	aesdec1_u  [ecx+11*16]
+	aesdec1_u  [ecx+10*16]
+	aesdec1_u  [ecx+9*16]
+	aesdec1_u  [ecx+8*16]
+	aesdec1_u  [ecx+7*16]
+	aesdec1_u  [ecx+6*16]
+	aesdec1_u  [ecx+5*16]
+	aesdec1_u  [ecx+4*16]
+	aesdec1_u  [ecx+3*16]
+	aesdec1_u  [ecx+2*16]
+	aesdec1_u  [ecx+1*16]
+	aesdeclast1_u  [ecx+0*16]
+	
+	pxor	xmm0,xmm5
+	movdqa	xmm5,xmm1
+	
+	add esi, 16
+	movdqu  [edi+esi - 16], xmm0
+	dec eax
+	jnz lp256decsingle_CBC
+
+end_dec256_CBC:
+
+
+	mov esp,ebp
+	pop ebp
+	pop edi
+	pop esi
+
+	mov ecx,[esp-4+8]  ; first arg
+	mov ecx,[ecx+12]
+	movdqu	[ecx],xmm5 ; store last iv for chaining
+	
+	ret
+
+
+
+
+
+
+
+
+
+align 16
+global _iEnc128
+_iEnc128:
+	mov ecx,[esp-4+8]
+	
+	push esi
+	push edi
+	push ebp
+	mov ebp,esp
+	
+	sub esp,16*16
+	and esp,0xfffffff0
+
+	mov eax,[ecx+16] ; numblocks
+	mov esi,[ecx]
+	mov edi,[ecx+4]
+	mov ecx,[ecx+8]
+	
+	sub edi,esi
+
+	test eax,eax
+	jz end_enc128
+	
+	cmp eax,4
+	jl lp128encsingle
+
+	test	ecx,0xf
+	jz		lpenc128four
+	
+	copy_round_keys esp,ecx,0
+	copy_round_keys esp,ecx,1
+	copy_round_keys esp,ecx,2
+	copy_round_keys esp,ecx,3
+	copy_round_keys esp,ecx,4
+	copy_round_keys esp,ecx,5
+	copy_round_keys esp,ecx,6
+	copy_round_keys esp,ecx,7
+	copy_round_keys esp,ecx,8
+	copy_round_keys esp,ecx,9
+	copy_round_keys esp,ecx,10
+	mov ecx,esp	
+
+
+	align 16	
+	
+lpenc128four:
+	
+	test eax,eax
+	jz end_enc128
+	
+	cmp eax,4
+	jl lp128encsingle
+
+	load_and_xor4 esi,[ecx+0*16]
+	add esi,4*16
+	aesenc4	[ecx+1*16]
+	aesenc4	[ecx+2*16]
+	aesenc4	[ecx+3*16]
+	aesenc4	[ecx+4*16]
+	aesenc4	[ecx+5*16]
+	aesenc4	[ecx+6*16]
+	aesenc4	[ecx+7*16]
+	aesenc4	[ecx+8*16]
+	aesenc4	[ecx+9*16]
+	aesenclast4	[ecx+10*16]
+	
+	store4 esi+edi-16*4
+	sub eax,4
+	jmp lpenc128four
+	
+	align 16
+lp128encsingle:
+
+	movdqu xmm0, [esi]
+	add esi, 16
+	movdqu xmm4,[ecx+0*16]
+	pxor xmm0, xmm4
+	aesenc1_u  [ecx+1*16]
+	aesenc1_u  [ecx+2*16]
+	aesenc1_u  [ecx+3*16]
+	aesenc1_u  [ecx+4*16]     
+	aesenc1_u  [ecx+5*16]
+	aesenc1_u  [ecx+6*16]
+	aesenc1_u  [ecx+7*16]
+	aesenc1_u  [ecx+8*16]
+	aesenc1_u  [ecx+9*16]
+	aesenclast1_u  [ecx+10*16]
+		; Store output encrypted data into CIPHERTEXT array
+	movdqu  [esi+edi-16], xmm0
+	dec eax
+	jnz lp128encsingle
+
+end_enc128:
+
+
+	mov esp,ebp
+	pop ebp
+	pop edi
+	pop esi
+	
+	ret
+
+
+align 16
+global _iEnc128_CTR
+_iEnc128_CTR:
+	mov ecx,[esp-4+8]
+	
+	push esi
+	push edi
+	push ebp
+	mov ebp,esp
+	
+	sub esp,16*16
+	and esp,0xfffffff0
+
+	mov	eax,[ecx+12]
+	movdqu xmm5,[eax]	;initial counter
+
+	mov eax,[ecx+16] ; numblocks
+	mov esi,[ecx]
+	mov edi,[ecx+4]
+	mov ecx,[ecx+8]
+	
+	sub edi,esi
+
+	test eax,eax
+	jz end_encctr128
+	
+	cmp eax,4
+	jl lp128encctrsingle
+
+	test	ecx,0xf
+	jz		lpencctr128four
+	
+	copy_round_keys esp,ecx,0
+	copy_round_keys esp,ecx,1
+	copy_round_keys esp,ecx,2
+	copy_round_keys esp,ecx,3
+	copy_round_keys esp,ecx,4
+	copy_round_keys esp,ecx,5
+	copy_round_keys esp,ecx,6
+	copy_round_keys esp,ecx,7
+	copy_round_keys esp,ecx,8
+	copy_round_keys esp,ecx,9
+	copy_round_keys esp,ecx,10
+	mov ecx,esp	
+
+
+	align 16	
+	
+lpencctr128four:
+	
+	test eax,eax
+	jz end_encctr128
+	
+	cmp eax,4
+	jl lp128encsingle
+
+	load_and_inc4 [ecx+0*16]
+	add esi,4*16
+	aesenc4	[ecx+1*16]
+	aesenc4	[ecx+2*16]
+	aesenc4	[ecx+3*16]
+	aesenc4	[ecx+4*16]
+	aesenc4	[ecx+5*16]
+	aesenc4	[ecx+6*16]
+	aesenc4	[ecx+7*16]
+	aesenc4	[ecx+8*16]
+	aesenc4	[ecx+9*16]
+	aesenclast4	[ecx+10*16]
+	xor_with_input4 esi-(4*16)
+	
+	store4 esi+edi-16*4
+	sub eax,4
+	jmp lpencctr128four
+	
+	align 16
+lp128encctrsingle:
+
+	movdqa	xmm0,xmm5
+	paddq	xmm5,[counter_add_one]
+	add esi, 16
+	movdqu xmm4,[ecx+0*16]
+	pxor xmm0, xmm4
+	aesenc1_u [ecx+1*16]
+	aesenc1_u [ecx+2*16]
+	aesenc1_u [ecx+3*16]
+	aesenc1_u [ecx+4*16]     
+	aesenc1_u [ecx+5*16]
+	aesenc1_u [ecx+6*16]
+	aesenc1_u [ecx+7*16]
+	aesenc1_u [ecx+8*16]
+	aesenc1_u [ecx+9*16]
+	aesenclast1_u [ecx+10*16]
+	movdqu xmm4, [esi-16]
+	pxor	xmm0,xmm4
+		; Store output encrypted data into CIPHERTEXT array
+	movdqu  [esi+edi-16], xmm0
+	dec eax
+	jnz lp128encctrsingle
+
+end_encctr128:
+
+	mov esp,ebp
+	pop ebp
+	pop edi
+	pop esi
+
+	mov ecx,[esp-4+8]  ; first arg
+	mov ecx,[ecx+12]
+	movdqu	[ecx],xmm5 ; store last counter for chaining
+	
+	ret
+
+
+align 16
+global _iEnc192_CTR
+_iEnc192_CTR:
+	mov ecx,[esp-4+8]
+	
+	push esi
+	push edi
+	push ebp
+	mov ebp,esp
+	
+	sub esp,16*16
+	and esp,0xfffffff0
+
+	mov	eax,[ecx+12]
+	movdqu xmm5,[eax]	;initial counter
+
+	mov eax,[ecx+16] ; numblocks
+	mov esi,[ecx]
+	mov edi,[ecx+4]
+	mov ecx,[ecx+8]
+	
+	sub edi,esi
+
+	test eax,eax
+	jz end_encctr192
+	
+	cmp eax,4
+	jl lp192encctrsingle
+
+	test	ecx,0xf
+	jz		lpencctr128four
+	
+	copy_round_keys esp,ecx,0
+	copy_round_keys esp,ecx,1
+	copy_round_keys esp,ecx,2
+	copy_round_keys esp,ecx,3
+	copy_round_keys esp,ecx,4
+	copy_round_keys esp,ecx,5
+	copy_round_keys esp,ecx,6
+	copy_round_keys esp,ecx,7
+	copy_round_keys esp,ecx,8
+	copy_round_keys esp,ecx,9
+	copy_round_keys esp,ecx,10
+	copy_round_keys esp,ecx,11
+	copy_round_keys esp,ecx,12
+	mov ecx,esp	
+
+
+	align 16	
+	
+lpencctr192four:
+	
+	test eax,eax
+	jz end_encctr192
+	
+	cmp eax,4
+	jl lp192encsingle
+
+	load_and_inc4 [ecx+0*16]
+	add esi,4*16
+	aesenc4	[ecx+1*16]
+	aesenc4	[ecx+2*16]
+	aesenc4	[ecx+3*16]
+	aesenc4	[ecx+4*16]
+	aesenc4	[ecx+5*16]
+	aesenc4	[ecx+6*16]
+	aesenc4	[ecx+7*16]
+	aesenc4	[ecx+8*16]
+	aesenc4	[ecx+9*16]
+	aesenc4	[ecx+10*16]
+	aesenc4	[ecx+11*16]
+	aesenclast4	[ecx+12*16]
+	xor_with_input4 esi-(4*16)
+	
+	store4 esi+edi-16*4
+	sub eax,4
+	jmp lpencctr192four
+	
+	align 16
+lp192encctrsingle:
+
+	movdqa	xmm0,xmm5
+	paddq	xmm5,[counter_add_one]
+	add esi, 16
+	movdqu xmm4,[ecx+0*16]
+	pxor xmm0, xmm4
+	aesenc1_u  [ecx+1*16]
+	aesenc1_u  [ecx+2*16]
+	aesenc1_u  [ecx+3*16]
+	aesenc1_u  [ecx+4*16]     
+	aesenc1_u  [ecx+5*16]
+	aesenc1_u  [ecx+6*16]
+	aesenc1_u  [ecx+7*16]
+	aesenc1_u  [ecx+8*16]
+	aesenc1_u  [ecx+9*16]
+	aesenc1_u  [ecx+10*16]
+	aesenc1_u  [ecx+11*16]
+	aesenclast1_u  [ecx+12*16]
+	movdqu xmm4, [esi-16]
+	pxor	xmm0,xmm4
+		; Store output encrypted data into CIPHERTEXT array
+	movdqu  [esi+edi-16], xmm0
+	dec eax
+	jnz lp192encctrsingle
+
+end_encctr192:
+
+	mov esp,ebp
+	pop ebp
+	pop edi
+	pop esi
+
+	mov ecx,[esp-4+8]  ; first arg
+	mov ecx,[ecx+12]
+	movdqu	[ecx],xmm5 ; store last counter for chaining
+	
+	ret
+
+
+align 16
+global _iEnc256_CTR
+_iEnc256_CTR:
+	mov ecx,[esp-4+8]
+	
+	push esi
+	push edi
+	push ebp
+	mov ebp,esp
+	
+	sub esp,16*16
+	and esp,0xfffffff0
+
+	mov	eax,[ecx+12]
+	movdqu xmm5,[eax]	;initial counter
+
+	mov eax,[ecx+16] ; numblocks
+	mov esi,[ecx]
+	mov edi,[ecx+4]
+	mov ecx,[ecx+8]
+	
+	sub edi,esi
+
+	test eax,eax
+	jz end_encctr256
+	
+	cmp eax,4
+	jl lp256encctrsingle
+
+	test	ecx,0xf
+	jz		lpencctr128four
+	
+	copy_round_keys esp,ecx,0
+	copy_round_keys esp,ecx,1
+	copy_round_keys esp,ecx,2
+	copy_round_keys esp,ecx,3
+	copy_round_keys esp,ecx,4
+	copy_round_keys esp,ecx,5
+	copy_round_keys esp,ecx,6
+	copy_round_keys esp,ecx,7
+	copy_round_keys esp,ecx,8
+	copy_round_keys esp,ecx,9
+	copy_round_keys esp,ecx,10
+	copy_round_keys esp,ecx,11
+	copy_round_keys esp,ecx,12
+	copy_round_keys esp,ecx,13
+	copy_round_keys esp,ecx,14
+	mov ecx,esp	
+
+
+	align 16	
+	
+lpencctr256four:
+	
+	test eax,eax
+	jz end_encctr256
+	
+	cmp eax,4
+	jl lp256encctrsingle
+
+	load_and_inc4 [ecx+0*16]
+	add esi,4*16
+	aesenc4	[ecx+1*16]
+	aesenc4	[ecx+2*16]
+	aesenc4	[ecx+3*16]
+	aesenc4	[ecx+4*16]
+	aesenc4	[ecx+5*16]
+	aesenc4	[ecx+6*16]
+	aesenc4	[ecx+7*16]
+	aesenc4	[ecx+8*16]
+	aesenc4	[ecx+9*16]
+	aesenc4	[ecx+10*16]
+	aesenc4	[ecx+11*16]
+	aesenc4	[ecx+12*16]
+	aesenc4	[ecx+13*16]
+	aesenclast4	[ecx+14*16]
+	xor_with_input4 esi-(4*16)
+	
+	store4 esi+edi-16*4
+	sub eax,4
+	jmp lpencctr256four
+	
+	align 16
+	
+lp256encctrsingle:
+
+	movdqa	xmm0,xmm5
+	paddq	xmm5,[counter_add_one]
+	add esi, 16
+	movdqu xmm4,[ecx+0*16]
+	pxor xmm0, xmm4
+	aesenc1_u  [ecx+1*16]
+	aesenc1_u  [ecx+2*16]
+	aesenc1_u  [ecx+3*16]
+	aesenc1_u  [ecx+4*16]     
+	aesenc1_u  [ecx+5*16]
+	aesenc1_u  [ecx+6*16]
+	aesenc1_u  [ecx+7*16]
+	aesenc1_u  [ecx+8*16]
+	aesenc1_u  [ecx+9*16]
+	aesenc1_u  [ecx+10*16]
+	aesenc1_u  [ecx+11*16]
+	aesenc1_u  [ecx+12*16]
+	aesenc1_u  [ecx+13*16]
+	aesenclast1_u  [ecx+14*16]
+	movdqu xmm4, [esi-16]
+	pxor	xmm0,xmm4
+		; Store output encrypted data into CIPHERTEXT array
+	movdqu  [esi+edi-16], xmm0
+	dec eax
+	jnz lp256encctrsingle
+
+end_encctr256:
+
+	mov esp,ebp
+	pop ebp
+	pop edi
+	pop esi
+
+	mov ecx,[esp-4+8]  ; first arg
+	mov ecx,[ecx+12]
+	movdqu	[ecx],xmm5 ; store last counter for chaining
+	
+	ret
+
+
+
+
+
+
+align 16
+global _iEnc128_CBC
+_iEnc128_CBC:
+	mov ecx,[esp-4+8]
+	
+	push esi
+	push edi
+	push ebp
+	mov ebp,esp
+	
+	sub esp,16*16
+	and esp,0xfffffff0
+
+	mov	eax,[ecx+12]
+	movdqu xmm1,[eax]	;iv	
+	
+	mov eax,[ecx+16] ; numblocks
+	mov esi,[ecx]
+	mov edi,[ecx+4]
+	mov ecx,[ecx+8]
+	sub edi,esi
+
+	test	ecx,0xf
+	jz		lp128encsingle_CBC
+	
+	copy_round_keys esp,ecx,0
+	copy_round_keys esp,ecx,1
+	copy_round_keys esp,ecx,2
+	copy_round_keys esp,ecx,3
+	copy_round_keys esp,ecx,4
+	copy_round_keys esp,ecx,5
+	copy_round_keys esp,ecx,6
+	copy_round_keys esp,ecx,7
+	copy_round_keys esp,ecx,8
+	copy_round_keys esp,ecx,9
+	copy_round_keys esp,ecx,10
+	mov ecx,esp	
+
+	align 16	
+	
+lp128encsingle_CBC:
+
+	movdqu xmm0, [esi]
+	add esi, 16
+	pxor xmm0, xmm1
+	movdqu xmm4,[ecx+0*16]
+	pxor xmm0, xmm4
+	aesenc1  [ecx+1*16]
+	aesenc1  [ecx+2*16]
+	aesenc1  [ecx+3*16]
+	aesenc1  [ecx+4*16]     
+	aesenc1  [ecx+5*16]
+	aesenc1  [ecx+6*16]
+	aesenc1  [ecx+7*16]
+	aesenc1  [ecx+8*16]
+	aesenc1  [ecx+9*16]
+	aesenclast1  [ecx+10*16]
+		; Store output encrypted data into CIPHERTEXT array
+	movdqu  [esi+edi-16], xmm0
+	movdqa xmm1,xmm0
+	dec eax
+	jnz lp128encsingle_CBC
+
+
+	mov esp,ebp
+	pop ebp
+	pop edi
+	pop esi
+	mov ecx,[esp-4+8]  ; first arg
+	mov ecx,[ecx+12]
+	movdqu	[ecx],xmm1 ; store last iv for chaining
+	
+	ret
+
+
+align 16
+global _iEnc192_CBC
+_iEnc192_CBC:
+	mov ecx,[esp-4+8]  ; first arg
+	
+	push esi
+	push edi
+	push ebp
+	mov ebp,esp
+	
+	sub esp,16*16
+	and esp,0xfffffff0
+
+	mov	eax,[ecx+12]
+	movdqu xmm1,[eax]	;iv	
+	
+	mov eax,[ecx+16] ; numblocks
+	mov esi,[ecx]
+	mov edi,[ecx+4]
+	mov ecx,[ecx+8]
+	sub edi,esi
+
+	test	ecx,0xf
+	jz		lp192encsingle_CBC
+	
+	copy_round_keys esp,ecx,0
+	copy_round_keys esp,ecx,1
+	copy_round_keys esp,ecx,2
+	copy_round_keys esp,ecx,3
+	copy_round_keys esp,ecx,4
+	copy_round_keys esp,ecx,5
+	copy_round_keys esp,ecx,6
+	copy_round_keys esp,ecx,7
+	copy_round_keys esp,ecx,8
+	copy_round_keys esp,ecx,9
+	copy_round_keys esp,ecx,10
+	copy_round_keys esp,ecx,11
+	copy_round_keys esp,ecx,12
+	mov ecx,esp	
+
+	align 16	
+	
+lp192encsingle_CBC:
+
+	movdqu xmm0, [esi]
+	add esi, 16
+	pxor xmm0, xmm1
+	movdqu xmm4,[ecx+0*16]
+	pxor xmm0, xmm4
+	aesenc1  [ecx+1*16]
+	aesenc1  [ecx+2*16]
+	aesenc1  [ecx+3*16]
+	aesenc1  [ecx+4*16]     
+	aesenc1  [ecx+5*16]
+	aesenc1  [ecx+6*16]
+	aesenc1  [ecx+7*16]
+	aesenc1  [ecx+8*16]
+	aesenc1  [ecx+9*16]
+	aesenc1  [ecx+10*16]
+	aesenc1  [ecx+11*16]
+	aesenclast1  [ecx+12*16]
+		; Store output encrypted data into CIPHERTEXT array
+	movdqu  [esi+edi-16], xmm0
+	movdqa xmm1,xmm0
+	dec eax
+	jnz lp192encsingle_CBC
+
+
+	mov esp,ebp
+	pop ebp
+	pop edi
+	pop esi
+	mov ecx,[esp-4+8]  ; first arg
+	mov ecx,[ecx+12]
+	movdqu	[ecx],xmm1 ; store last iv for chaining
+	
+	ret
+
+align 16
+global _iEnc256_CBC
+_iEnc256_CBC:
+	mov ecx,[esp-4+8]  ; first arg
+	
+	push esi
+	push edi
+	push ebp
+	mov ebp,esp
+	
+	sub esp,16*16
+	and esp,0xfffffff0
+
+	mov	eax,[ecx+12]
+	movdqu xmm1,[eax]	;iv	
+	
+	mov eax,[ecx+16] ; numblocks
+	mov esi,[ecx]
+	mov edi,[ecx+4]
+	mov ecx,[ecx+8]
+	sub edi,esi
+
+	test	ecx,0xf
+	jz		lp256encsingle_CBC
+	
+	copy_round_keys esp,ecx,0
+	copy_round_keys esp,ecx,1
+	copy_round_keys esp,ecx,2
+	copy_round_keys esp,ecx,3
+	copy_round_keys esp,ecx,4
+	copy_round_keys esp,ecx,5
+	copy_round_keys esp,ecx,6
+	copy_round_keys esp,ecx,7
+	copy_round_keys esp,ecx,8
+	copy_round_keys esp,ecx,9
+	copy_round_keys esp,ecx,10
+	copy_round_keys esp,ecx,11
+	copy_round_keys esp,ecx,12
+	copy_round_keys esp,ecx,13
+	copy_round_keys esp,ecx,14
+	mov ecx,esp	
+
+	align 16	
+	
+lp256encsingle_CBC:
+
+;abab
+	movdqu xmm0, [esi]
+	add esi, 16
+	pxor xmm0, xmm1
+	movdqu xmm4,[ecx+0*16]
+	pxor xmm0, xmm4
+	aesenc1 [ecx+1*16]
+	aesenc1 [ecx+2*16]
+	aesenc1 [ecx+3*16]
+	aesenc1 [ecx+4*16]     
+	aesenc1 [ecx+5*16]
+	aesenc1 [ecx+6*16]
+	aesenc1 [ecx+7*16]
+	aesenc1 [ecx+8*16]
+	aesenc1 [ecx+9*16]
+	aesenc1 [ecx+10*16]
+	aesenc1 [ecx+11*16]
+	aesenc1 [ecx+12*16]
+	aesenc1 [ecx+13*16]
+	aesenclast1 [ecx+14*16]
+		; Store output encrypted data into CIPHERTEXT array
+	movdqu  [esi+edi-16], xmm0
+	movdqa xmm1,xmm0
+	dec eax
+	jnz lp256encsingle_CBC
+
+
+	mov esp,ebp
+	pop ebp
+	pop edi
+	pop esi
+	mov ecx,[esp-4+8]
+	mov ecx,[ecx+12]
+	movdqu	[ecx],xmm1 ; store last iv for chaining
+	
+	ret
+
+
+
+
+
+align 16
+global _iEnc192
+_iEnc192:
+	mov ecx,[esp-4+8]
+	
+	push esi
+	push edi
+	push ebp
+	mov ebp,esp
+	
+	sub esp,16*16
+	and esp,0xfffffff0
+
+	mov eax,[ecx+16] ; numblocks
+	mov esi,[ecx]
+	mov edi,[ecx+4]
+	mov ecx,[ecx+8]
+	
+	sub edi,esi
+
+	test eax,eax
+	jz end_enc192
+	
+	cmp eax,4
+	jl lp192encsingle
+
+	test	ecx,0xf
+	jz		lpenc192four
+	
+	copy_round_keys esp,ecx,0
+	copy_round_keys esp,ecx,1
+	copy_round_keys esp,ecx,2
+	copy_round_keys esp,ecx,3
+	copy_round_keys esp,ecx,4
+	copy_round_keys esp,ecx,5
+	copy_round_keys esp,ecx,6
+	copy_round_keys esp,ecx,7
+	copy_round_keys esp,ecx,8
+	copy_round_keys esp,ecx,9
+	copy_round_keys esp,ecx,10
+	copy_round_keys esp,ecx,11
+	copy_round_keys esp,ecx,12
+	mov ecx,esp	
+
+	align 16	
+	
+lpenc192four:
+	
+	test eax,eax
+	jz end_enc192
+	
+	cmp eax,4
+	jl lp192encsingle
+
+	load_and_xor4 esi,[ecx+0*16]
+	add esi,4*16
+	aesenc4	[ecx+1*16]
+	aesenc4	[ecx+2*16]
+	aesenc4	[ecx+3*16]
+	aesenc4	[ecx+4*16]
+	aesenc4	[ecx+5*16]
+	aesenc4	[ecx+6*16]
+	aesenc4	[ecx+7*16]
+	aesenc4	[ecx+8*16]
+	aesenc4	[ecx+9*16]
+	aesenc4	[ecx+10*16]
+	aesenc4	[ecx+11*16]
+	aesenclast4	[ecx+12*16]
+	
+	store4 esi+edi-16*4
+	sub eax,4
+	jmp lpenc192four
+	
+	align 16
+lp192encsingle:
+
+	movdqu xmm0, [esi]
+	add esi, 16
+	movdqu xmm4,[ecx+0*16]
+	pxor xmm0, xmm4
+	aesenc1_u [ecx+1*16]
+	aesenc1_u [ecx+2*16]
+	aesenc1_u [ecx+3*16]
+	aesenc1_u [ecx+4*16]     
+	aesenc1_u [ecx+5*16]
+	aesenc1_u [ecx+6*16]
+	aesenc1_u [ecx+7*16]
+	aesenc1_u [ecx+8*16]
+	aesenc1_u [ecx+9*16]
+	aesenc1_u [ecx+10*16]
+	aesenc1_u [ecx+11*16]
+	aesenclast1_u [ecx+12*16]
+		; Store output encrypted data into CIPHERTEXT array
+	movdqu  [esi+edi-16], xmm0
+	dec eax
+	jnz lp192encsingle
+
+end_enc192:
+
+
+	mov esp,ebp
+	pop ebp
+	pop edi
+	pop esi
+	
+	ret
+
+
+
+
+align 16
+global _iEnc256
+_iEnc256:
+	mov ecx,[esp-4+8]
+	
+	push esi
+	push edi
+	push ebp
+	mov ebp,esp
+	
+	sub esp,16*16
+	and esp,0xfffffff0
+
+	mov eax,[ecx+16] ; numblocks
+	mov esi,[ecx]
+	mov edi,[ecx+4]
+	mov ecx,[ecx+8]
+	
+	sub edi,esi	
+
+	test eax,eax
+	jz end_enc256
+
+	cmp eax,4
+	jl lp256enc
+
+	test	ecx,0xf
+	jz	lp256enc4
+	
+	copy_round_keys esp,ecx,0
+	copy_round_keys esp,ecx,1
+	copy_round_keys esp,ecx,2
+	copy_round_keys esp,ecx,3
+	copy_round_keys esp,ecx,4
+	copy_round_keys esp,ecx,5
+	copy_round_keys esp,ecx,6
+	copy_round_keys esp,ecx,7
+	copy_round_keys esp,ecx,8
+	copy_round_keys esp,ecx,9
+	copy_round_keys esp,ecx,10
+	copy_round_keys esp,ecx,11
+	copy_round_keys esp,ecx,12
+	copy_round_keys esp,ecx,13
+	copy_round_keys esp,ecx,14
+	mov ecx,esp	
+
+
+
+	align 16
+	
+lp256enc4:
+	test eax,eax
+	jz end_enc256
+
+	cmp eax,4
+	jl lp256enc
+
+
+	load_and_xor4 esi,[ecx+0*16]
+	add esi, 16*4
+	aesenc4 [ecx+1*16]
+	aesenc4 [ecx+2*16]
+	aesenc4 [ecx+3*16]
+	aesenc4 [ecx+4*16]
+	aesenc4 [ecx+5*16]
+	aesenc4 [ecx+6*16]
+	aesenc4 [ecx+7*16]
+	aesenc4 [ecx+8*16]
+	aesenc4 [ecx+9*16]
+	aesenc4 [ecx+10*16]
+	aesenc4 [ecx+11*16]
+	aesenc4 [ecx+12*16]
+	aesenc4 [ecx+13*16]
+	aesenclast4 [ecx+14*16]
+
+	store4  esi+edi-16*4
+	sub eax,4
+	jmp lp256enc4
+	
+	align 16
+lp256enc:
+
+	movdqu xmm0, [esi]
+	add esi, 16
+	movdqu xmm4,[ecx+0*16]
+	pxor xmm0, xmm4
+	aesenc1_u [ecx+1*16]
+	aesenc1_u [ecx+2*16]
+	aesenc1_u [ecx+3*16]
+	aesenc1_u [ecx+4*16]
+	aesenc1_u [ecx+5*16]
+	aesenc1_u [ecx+6*16]
+	aesenc1_u [ecx+7*16]
+	aesenc1_u [ecx+8*16]
+	aesenc1_u [ecx+9*16]
+	aesenc1_u [ecx+10*16]
+	aesenc1_u [ecx+11*16]
+	aesenc1_u [ecx+12*16]
+	aesenc1_u [ecx+13*16]
+	aesenclast1_u [ecx+14*16]
+
+		; Store output encrypted data into CIPHERTEXT array
+	movdqu  [esi+edi-16], xmm0
+	dec eax
+	jnz lp256enc
+
+end_enc256:
+
+
+	mov esp,ebp
+	pop ebp
+	pop edi
+	pop esi
+	
+	ret
diff --git a/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/include/iaes_asm_interface.h b/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/include/iaes_asm_interface.h
new file mode 100644
--- /dev/null
+++ b/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/include/iaes_asm_interface.h
@@ -0,0 +1,126 @@
+/* 
+ * Copyright (c) 2010, Intel Corporation
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *     * Redistributions of source code must retain the above copyright notice, 
+ *       this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Intel Corporation nor the names of its contributors 
+ *       may be used to endorse or promote products derived from this software 
+ *       without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+ * 
+*/
+
+#ifndef _INTEL_AES_ASM_INTERFACE_H__
+#define _INTEL_AES_ASM_INTERFACE_H__
+
+
+#include "iaesni.h"
+
+
+
+//structure to pass aes processing data to asm level functions
+typedef struct _sAesData
+{
+	_AES_IN		UCHAR	*in_block;
+	_AES_OUT	UCHAR	*out_block;
+	_AES_IN		UCHAR	*expanded_key;		
+	_AES_INOUT	UCHAR	*iv;					// for CBC mode
+	_AES_IN		size_t	num_blocks;
+} sAesData;
+
+#if (__cplusplus)
+extern "C"
+{
+#endif
+#if 0
+#define MYSTDCALL __stdcall
+#else
+#define MYSTDCALL 
+#endif
+
+#if defined __linux__ || defined __APPLE__
+#ifndef __LP64__
+#define iEncExpandKey256 _iEncExpandKey256
+#define iEncExpandKey192 _iEncExpandKey192
+#define iEncExpandKey128 _iEncExpandKey128
+#define iDecExpandKey256 _iDecExpandKey256
+#define iDecExpandKey192 _iDecExpandKey192
+#define iDecExpandKey128 _iDecExpandKey128
+#define iEnc128 _iEnc128
+#define iDec128 _iDec128
+#define iEnc256 _iEnc256
+#define iDec256 _iDec256
+#define iEnc192 _iEnc192
+#define iDec192 _iDec192
+#define iEnc128_CBC _iEnc128_CBC
+#define iDec128_CBC _iDec128_CBC
+#define iEnc256_CBC _iEnc256_CBC
+#define iDec256_CBC _iDec256_CBC
+#define iEnc192_CBC _iEnc192_CBC
+#define iDec192_CBC _iDec192_CBC
+#define iEnc128_CTR _iEnc128_CTR
+#define iEnc192_CTR _iEnc192_CTR
+#define iEnc256_CTR _iEnc256_CTR
+#define do_rdtsc    _do_rdtsc
+#endif // lp64
+#endif // linux
+	// prepearing the different key rounds, for enc/dec in asm
+	// expnaded key should be 16-byte aligned
+	// expanded key should have enough space to hold all key rounds (16 bytes per round) - 256 bytes would cover all cases (AES256 has 14 rounds + 1 xor)
+	void MYSTDCALL iEncExpandKey256(_AES_IN UCHAR *key, _AES_OUT UCHAR *expanded_key);
+	void MYSTDCALL iEncExpandKey192(_AES_IN UCHAR *key, _AES_OUT UCHAR *expanded_key);
+	void MYSTDCALL iEncExpandKey128(_AES_IN UCHAR *key, _AES_OUT UCHAR *expanded_key);
+
+	void MYSTDCALL iDecExpandKey256(UCHAR *key, _AES_OUT UCHAR *expanded_key);
+	void MYSTDCALL iDecExpandKey192(UCHAR *key, _AES_OUT UCHAR *expanded_key);
+	void MYSTDCALL iDecExpandKey128(UCHAR *key, _AES_OUT UCHAR *expanded_key);
+
+
+	//enc/dec asm functions
+	void MYSTDCALL iEnc128(sAesData *data);
+	void MYSTDCALL iDec128(sAesData *data);
+	void MYSTDCALL iEnc256(sAesData *data);
+	void MYSTDCALL iDec256(sAesData *data);
+	void MYSTDCALL iEnc192(sAesData *data);
+	void MYSTDCALL iDec192(sAesData *data);
+
+	void MYSTDCALL iEnc128_CBC(sAesData *data);
+	void MYSTDCALL iDec128_CBC(sAesData *data);
+	void MYSTDCALL iEnc256_CBC(sAesData *data);
+	void MYSTDCALL iDec256_CBC(sAesData *data);
+	void MYSTDCALL iEnc192_CBC(sAesData *data);
+	void MYSTDCALL iDec192_CBC(sAesData *data);
+
+
+	void MYSTDCALL iEnc128_CTR(sAesData *data);
+	void MYSTDCALL iEnc256_CTR(sAesData *data);
+	void MYSTDCALL iEnc192_CTR(sAesData *data);
+
+	// rdtsc function
+	unsigned long long do_rdtsc(void);
+
+
+#if (__cplusplus)
+}
+#endif
+
+
+#endif
+
diff --git a/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/include/iaesni.h b/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/include/iaesni.h
new file mode 100644
--- /dev/null
+++ b/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/include/iaesni.h
@@ -0,0 +1,151 @@
+/* 
+ * Copyright (c) 2010, Intel Corporation
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *     * Redistributions of source code must retain the above copyright notice, 
+ *       this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Intel Corporation nor the names of its contributors 
+ *       may be used to endorse or promote products derived from this software 
+ *       without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+ * 
+*/
+
+
+#ifndef _IAESNI_H__
+#define _IAESNI_H__
+
+#include <stdlib.h>
+
+#define AES_INSTRCTIONS_CPUID_BIT (1<<25)
+
+//indicates input param
+#define _AES_IN	
+
+//indicates output param
+#define _AES_OUT
+
+//indicates input/output param - based on context
+#define _AES_INOUT
+
+typedef unsigned char UCHAR;
+
+
+#ifndef bool
+#define bool BOOL
+#endif
+//test if the processor actually supports the above functions
+//executing one the functions below without processor support will cause UD fault
+//bool check_for_aes_instructions(void);
+#if (__cplusplus)
+extern "C" {
+#endif
+int check_for_aes_instructions(void);
+
+#define ROUND_KEYS_UNALIGNED_TESTING
+
+#if defined __linux__ || defined __APPLE__
+
+#warning "Configuring for Linux or Darwin"
+
+#ifdef ROUND_KEYS_UNALIGNED_TESTING
+
+#define DEFINE_ROUND_KEYS \
+	UCHAR __attribute__ ((aligned (16))) _expandedKey[16*16];	\
+	UCHAR *expandedKey = _expandedKey + 4;	\
+
+
+#else
+
+
+
+#define DEFINE_ROUND_KEYS \
+	UCHAR __attribute__ ((aligned (16))) _expandedKey[16*16];	\
+	UCHAR *expandedKey = _expandedKey;	\
+
+#endif
+
+#else // if not __linux__
+
+#warning "Configuring for Windows..."
+
+#ifdef ROUND_KEYS_UNALIGNED_TESTING
+
+#define DEFINE_ROUND_KEYS \
+	__declspec(align(16)) UCHAR _expandedKey[16*16];	\
+	UCHAR *expandedKey = _expandedKey + 4;	\
+
+
+#else
+
+
+
+#define DEFINE_ROUND_KEYS \
+	__declspec(align(16)) UCHAR _expandedKey[16*16];	\
+	UCHAR *expandedKey = _expandedKey;	\
+
+
+#endif
+
+#endif
+
+
+
+// encryption functions
+// plainText is pointer to input stream
+// cipherText is pointer to buffer to be filled with encrypted (cipher text) data
+// key is pointer to enc key (sizes are 16 bytes for AES-128, 24 bytes for AES-192, 32 for AES-256)
+// numBlocks is number of 16 bytes blocks to process - note that encryption is done of full 16 byte blocks
+void intel_AES_enc128(_AES_IN UCHAR *plainText, _AES_OUT UCHAR *cipherText, _AES_IN UCHAR *key, _AES_IN size_t numBlocks);
+void intel_AES_enc192(_AES_IN UCHAR *plainText, _AES_OUT UCHAR *cipherText, _AES_IN UCHAR *key, _AES_IN size_t numBlocks);
+void intel_AES_enc256(_AES_IN UCHAR *plainText, _AES_OUT UCHAR *cipherText, _AES_IN UCHAR *key, _AES_IN size_t numBlocks);
+
+
+void intel_AES_enc128_CBC(_AES_IN UCHAR *plainText, _AES_OUT UCHAR *cipherText, _AES_IN UCHAR *key, _AES_IN size_t numBlocks, _AES_IN UCHAR *iv);
+void intel_AES_enc192_CBC(_AES_IN UCHAR *plainText, _AES_OUT UCHAR *cipherText, _AES_IN UCHAR *key, _AES_IN size_t numBlocks, _AES_IN UCHAR *iv);
+void intel_AES_enc256_CBC(_AES_IN UCHAR *plainText, _AES_OUT UCHAR *cipherText, _AES_IN UCHAR *key, _AES_IN size_t numBlocks, _AES_IN UCHAR *iv);
+
+
+// encryption functions
+// cipherText is pointer to encrypted stream
+// plainText is pointer to buffer to be filled with original (plain text) data
+// key is pointer to enc key (sizes are 16 bytes for AES-128, 24 bytes for AES-192, 32 for AES-256)
+// numBlocks is number of 16 bytes blocks to process - note that decryption is done of full 16 byte blocks
+void intel_AES_dec128(_AES_IN UCHAR *cipherText, _AES_OUT UCHAR *plainText, _AES_IN UCHAR *key, _AES_IN size_t numBlocks);
+void intel_AES_dec192(_AES_IN UCHAR *cipherText, _AES_OUT UCHAR *plainText, _AES_IN UCHAR *key, _AES_IN size_t numBlocks);
+void intel_AES_dec256(_AES_IN UCHAR *cipherText, _AES_OUT UCHAR *plainText, _AES_IN UCHAR *key, _AES_IN size_t numBlocks);
+
+void intel_AES_dec128_CBC(_AES_IN UCHAR *cipherText, _AES_OUT UCHAR *plainText, _AES_IN UCHAR *key, _AES_IN size_t numBlocks, _AES_IN UCHAR *iv);
+void intel_AES_dec192_CBC(_AES_IN UCHAR *cipherText, _AES_OUT UCHAR *plainText, _AES_IN UCHAR *key, _AES_IN size_t numBlocks, _AES_IN UCHAR *iv);
+void intel_AES_dec256_CBC(_AES_IN UCHAR *cipherText, _AES_OUT UCHAR *plainText, _AES_IN UCHAR *key, _AES_IN size_t numBlocks, _AES_IN UCHAR *iv);
+
+void intel_AES_encdec128_CTR(_AES_IN UCHAR *input, _AES_OUT UCHAR *output, _AES_IN UCHAR *key, _AES_IN size_t numBlocks, _AES_IN UCHAR *initial_counter);
+void intel_AES_encdec192_CTR(_AES_IN UCHAR *input, _AES_OUT UCHAR *output, _AES_IN UCHAR *key, _AES_IN size_t numBlocks, _AES_IN UCHAR *initial_counter);
+void intel_AES_encdec256_CTR(_AES_IN UCHAR *input, _AES_OUT UCHAR *output, _AES_IN UCHAR *key, _AES_IN size_t numBlocks, _AES_IN UCHAR *initial_counter);
+
+
+#if (__cplusplus)
+}
+#endif
+
+
+#endif
+
+
+
diff --git a/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/mk_lnx_lib.sh b/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/mk_lnx_lib.sh
new file mode 100644
--- /dev/null
+++ b/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/mk_lnx_lib.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+# arg in required. Must be 86 (for 32bit compiler) or 64 (for 64bit compiler)
+arch=$1
+if [ "x$arch" != "x86" ]; then 
+   if [ "x$arch" != "x64" ]; then 
+      echo "One arg in required. Must be 86 (for 32bit compiler) or 64 (for 64bit compiler)"
+      exit 1
+   fi
+fi
+if [ "$arch" == "86" ]; then 
+sz=32
+fi
+if [ "$arch" == "64" ]; then 
+sz=64
+fi
+#echo got sz= $sz and arch= $arch
+
+mkdir -p obj/x${arch}
+
+#yasm="../yasm/yasm"
+yasm=yasm
+
+pushd .
+asm="iaesx${arch} do_rdtsc"
+for i in $asm; do 
+   # echo do $i.s
+   echo "$yasm -D__linux__ -g dwarf2 -f elf${sz} asm/x${arch}/$i.s -o obj/x${arch}/$i.o"
+   $yasm -D__linux__ -g dwarf2 -f elf${sz} asm/x${arch}/$i.s -o obj/x${arch}/$i.o
+done
+# gcc -O3 -g -m${sz} -Iinclude/ -c src/intel_aes.c -o obj/x${arch}/intel_aes.o
+# RRN: Building a shared library too:
+ echo "Compiling C source"
+ gcc -fPIC -O3 -g -Iinclude/ -c src/intel_aes.c -o obj/x64/intel_aes.o
+
+ echo "Linking static and dynamic libraries"
+ ar -r lib/x${arch}/libintel_aes${arch}.a obj/x${arch}/*.o
+ gcc -shared -dynamic  -o lib/x${arch}/libintel_aes${arch}.so obj/x64/*.o
+popd
+
+echo "Copying to cbits parent directory"
+cp lib/x${arch}/*.so ../../
+cp lib/x${arch}/*.a  ../../
diff --git a/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/mk_win_lib.bat b/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/mk_win_lib.bat
new file mode 100644
--- /dev/null
+++ b/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/mk_win_lib.bat
@@ -0,0 +1,35 @@
+
+@rem arg in required. Must be 86 (for 32bit compiler) or 64 (for 64bit compiler)
+SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
+set arch=%1
+if "%arch%" == "86" goto OK
+if "%arch%" == "64" goto OK
+echo One arg in required. Must be 86 (for 32bit compiler) or 64 (for 64bit compiler)
+goto :ERR
+
+:OK
+if "%arch%" == "86" set sz=32
+if "%arch%" == "64" set sz=64
+
+mkdir obj\x%arch%
+
+set yasm=..\yasm\yasm-0.8.0-win%sz%.exe
+
+%yasm% -f win%sz% asm\x%arch%\do_rdtsc.s -o obj\x%arch%\do_rdtsc.obj
+
+pushd .
+set asm=iaesx%arch%
+for %%i in (%asm%) do (
+	%yasm% -f win%sz% asm/x%arch%/%%i.s -o obj/x%arch%/%%i.obj
+	if ERRORLEVEL 1 goto :ERR
+)
+cl /O2 /Zi -Iinclude\ -c src\intel_aes.c /Foobj\x%arch%\intel_aes.obj
+if ERRORLEVEL 1 goto :ERR
+lib /out:lib\x%arch%\intel_aes%arch%.lib obj\x%arch%\*.obj
+if ERRORLEVEL 1 goto :ERR
+popd
+
+goto :EOF
+
+:ERR
+echo got an error in mk_win_lib.bat
diff --git a/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/src/aessample.c b/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/src/aessample.c
new file mode 100644
--- /dev/null
+++ b/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/src/aessample.c
@@ -0,0 +1,302 @@
+/* 
+ * Copyright (c) 2010, Intel Corporation
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *     * Redistributions of source code must retain the above copyright notice, 
+ *       this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Intel Corporation nor the names of its contributors 
+ *       may be used to endorse or promote products derived from this software 
+ *       without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+ * 
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <memory.h>
+#ifdef __linux__
+#include <alloca.h>
+#ifndef _alloca
+#define _alloca alloca
+#endif
+#endif
+
+#include "iaesni.h"
+
+// test vectors from fips-197 Appendix C http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
+
+unsigned char test_plain_text[16] = {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff};
+unsigned char test_cipher_text_128[16] = {0x69,0xc4,0xe0,0xd8,0x6a,0x7b,0x04,0x30,0xd8,0xcd,0xb7,0x80,0x70,0xb4,0xc5,0x5a};
+unsigned char test_cipher_text_192[16] = {0xdd,0xa9,0x7c,0xa4,0x86,0x4c,0xdf,0xe0,0x6e,0xaf,0x70,0xa0,0xec,0x0d,0x71,0x91};
+unsigned char test_cipher_text_256[16] = {0x8e,0xa2,0xb7,0xca,0x51,0x67,0x45,0xbf,0xea,0xfc,0x49,0x90,0x4b,0x49,0x60,0x89};
+unsigned char test_key_128[16] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
+unsigned char test_key_192[24] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17};
+unsigned char test_key_256[32] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f};
+unsigned char test_iv[16] = {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff};
+
+
+#define TEST_PASS (0)
+#define TEST_FAIL_ENC (1)
+#define TEST_FAIL_DEC (2)
+
+int test128(unsigned long numBlocks)
+{
+	unsigned int buffer_size = numBlocks*16;
+	unsigned int i;
+	UCHAR *testVector = (UCHAR*)_alloca(buffer_size);
+	UCHAR *testResult = (UCHAR*)_alloca(buffer_size);
+	for (i=0;i<buffer_size;i++)
+	{
+		testVector[i] = test_plain_text[i % 16];
+		testResult[i] = 0xee;
+	}
+
+	intel_AES_enc128(testVector,testResult,test_key_128,numBlocks);
+
+	for (i=0;i<buffer_size;i++)
+	{
+		if (testResult[i] != test_cipher_text_128[i % 16])
+			return TEST_FAIL_ENC;
+
+		testVector[i] = 0xdd;
+	}
+
+	intel_AES_dec128(testResult,testVector,test_key_128,numBlocks);
+
+	for (i=0;i<buffer_size;i++)
+	{
+		if (testVector[i] != test_plain_text[i % 16])
+			return TEST_FAIL_DEC;
+	}
+
+	return TEST_PASS;
+
+}
+
+
+int test128_CBC(unsigned long numBlocks)
+{
+	unsigned int buffer_size = numBlocks*16;
+	unsigned int i;
+	UCHAR *testVector = (UCHAR*)_alloca(buffer_size);
+	UCHAR *testResult = (UCHAR*)_alloca(buffer_size);
+	UCHAR local_test_iv[16];
+	unsigned int half_size;
+
+	for (i=0;i<buffer_size;i++)
+	{
+		testVector[i] = test_plain_text[i % 16];
+		testResult[i] = 0xee;
+	}
+
+	memcpy(local_test_iv,test_iv,16);
+	intel_AES_enc128_CBC(testVector,testResult,test_key_128,numBlocks,local_test_iv);
+
+	//test chaining as well
+	memcpy(local_test_iv,test_iv,16);
+	half_size = numBlocks/2;
+	intel_AES_dec128_CBC(testResult,testVector,test_key_128,half_size,local_test_iv);
+	intel_AES_dec128_CBC(testResult+16*(half_size),testVector+16*(half_size),test_key_128,numBlocks - half_size,local_test_iv);
+
+	for (i=0;i<buffer_size;i++)
+	{
+		if (testVector[i] != test_plain_text[i % 16])
+		{
+			printf("%d",i);
+			return TEST_FAIL_DEC;
+		}
+	}
+
+	return TEST_PASS;
+
+}
+
+
+
+
+int test192(unsigned long numBlocks)
+{
+	unsigned int buffer_size = numBlocks*16;
+	unsigned int i;
+	UCHAR *testVector = (UCHAR*)_alloca(buffer_size);
+	UCHAR *testResult = (UCHAR*)_alloca(buffer_size);
+	for (i=0;i<buffer_size;i++)
+	{
+		testVector[i] = test_plain_text[i % 16];
+		testResult[i] = 0xee;
+	}
+
+	intel_AES_enc192(testVector,testResult,test_key_192,numBlocks);
+
+	for (i=0;i<buffer_size;i++)
+	{
+		if (testResult[i] != test_cipher_text_192[i % 16])
+			return TEST_FAIL_ENC;
+
+		testVector[i] = 0xdd;
+	}
+
+	intel_AES_dec192(testResult,testVector,test_key_192,numBlocks);
+
+	for (i=0;i<buffer_size;i++)
+	{
+		if (testVector[i] != test_plain_text[i % 16])
+			return TEST_FAIL_DEC;
+	}
+
+	return 0;
+
+}
+
+
+int test192_CBC(unsigned long numBlocks)
+{
+	unsigned int buffer_size = numBlocks*16;
+	unsigned int i;
+	UCHAR *testVector = (UCHAR*)_alloca(buffer_size);
+	UCHAR *testResult = (UCHAR*)_alloca(buffer_size);
+	UCHAR local_test_iv[16];
+	unsigned int half_size;
+
+	memcpy(local_test_iv,test_iv,16);
+
+	for (i=0;i<buffer_size;i++)
+	{
+		testVector[i] = test_plain_text[i % 16];
+		testResult[i] = 0xee;
+	}
+
+	intel_AES_enc192_CBC(testVector,testResult,test_key_128,numBlocks,local_test_iv);
+
+
+	memcpy(local_test_iv,test_iv,16);
+	half_size = numBlocks/2;
+	intel_AES_dec192_CBC(testResult,testVector,test_key_128,half_size,local_test_iv);
+	intel_AES_dec192_CBC(testResult+16*(half_size),testVector+16*(half_size),test_key_128,numBlocks - half_size,local_test_iv);
+
+	for (i=0;i<buffer_size;i++)
+	{
+		if (testVector[i] != test_plain_text[i % 16])
+			return TEST_FAIL_DEC;
+	}
+
+	return TEST_PASS;
+
+}
+
+
+int test256(unsigned long numBlocks)
+{
+	unsigned int buffer_size = numBlocks*16;
+	unsigned int i;
+	UCHAR *testVector = (UCHAR*)_alloca(buffer_size);
+	UCHAR *testResult = (UCHAR*)_alloca(buffer_size);
+	for (i=0;i<buffer_size;i++)
+	{
+		testVector[i] = test_plain_text[i % 16];
+		testResult[i] = 0xee;
+	}
+
+	intel_AES_enc256(testVector,testResult,test_key_256,numBlocks);
+
+	for (i=0;i<buffer_size;i++)
+	{
+		if (testResult[i] != test_cipher_text_256[i % 16])
+			return TEST_FAIL_ENC;
+
+		testVector[i] = 0xdd;
+	}
+
+	intel_AES_dec256(testResult,testVector,test_key_256,numBlocks);
+
+	for (i=0;i<buffer_size;i++)
+	{
+		if (testVector[i] != test_plain_text[i % 16])
+			return TEST_FAIL_DEC;
+	}
+
+	return 0;
+
+}
+
+
+int test256_CBC(unsigned long numBlocks)
+{
+	unsigned int buffer_size = numBlocks*16;
+	unsigned int i;
+	UCHAR *testVector = (UCHAR*)_alloca(buffer_size);
+	UCHAR *testResult = (UCHAR*)_alloca(buffer_size);
+	UCHAR local_test_iv[16];
+	unsigned int half_size = numBlocks/2;
+
+	memcpy(local_test_iv,test_iv,16);
+
+	for (i=0;i<buffer_size;i++)
+	{
+		testVector[i] = test_plain_text[i % 16];
+		testResult[i] = 0xee;
+	}
+
+	intel_AES_enc256_CBC(testVector,testResult,test_key_256,numBlocks,local_test_iv);
+
+
+	memcpy(local_test_iv,test_iv,16);
+	intel_AES_dec256_CBC(testResult,testVector,test_key_256,half_size,local_test_iv);
+	intel_AES_dec256_CBC(testResult+16*(half_size),testVector+16*(half_size),test_key_256,numBlocks - half_size,local_test_iv);
+
+	for (i=0;i<buffer_size;i++)
+	{
+		if (testVector[i] != test_plain_text[i % 16])
+			return TEST_FAIL_DEC;
+	}
+
+	return TEST_PASS;
+
+}
+
+
+int  main(void)
+{
+	int i;
+
+	if (check_for_aes_instructions() == 0)
+	{
+		printf("no AES instructions detected! - stopping the test app\n");
+		return 1;
+	}
+
+	printf("AES instructions detected\n");
+	for (i=1;i<4096;i+=i*3/2)
+	{
+		printf("testing %d blocks,AES-128: %s",i,(test128(i) != TEST_PASS) ? "FAIL" : "PASS");
+		printf(",AES-192: %s",(test192(i) != TEST_PASS) ? "FAIL" : "PASS");
+		printf(",AES-256: %s",(test256(i) != TEST_PASS) ? "FAIL" : "PASS");
+		printf("\n");
+	}
+
+	for (i=1;i<4096;i+=i*3/2)
+	{
+		printf("testing %d blocks,AES-128-CBC: %s",i,(test128_CBC(i) != TEST_PASS) ? "FAIL" : "PASS");
+		printf(",AES-192-CBC: %s",(test192_CBC(i) != TEST_PASS) ? "FAIL" : "PASS");
+		printf(",AES-256-CBC: %s\n",(test256_CBC(i) != TEST_PASS) ? "FAIL" : "PASS");
+		printf("\n");
+	}
+	return 0;
+}
diff --git a/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/src/aessampletiming.cpp b/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/src/aessampletiming.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/src/aessampletiming.cpp
@@ -0,0 +1,541 @@
+/* 
+ * Copyright (c) 2010, Intel Corporation
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *     * Redistributions of source code must retain the above copyright notice, 
+ *       this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Intel Corporation nor the names of its contributors 
+ *       may be used to endorse or promote products derived from this software 
+ *       without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+ * 
+*/
+
+/* 
+	This program can take a long time to run and it may use the whole system.
+	The program gets timing info for various sizes, methods, and number of threads.
+	It also raises the priority of the timing threads to reduce the variation in performance.
+	It has windows specific code and I haven't ported it to linux.
+	See aes_gladman_subset\src\modetest.c for example implementation in linux and windows
+*/
+#include <stdlib.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <memory.h>
+#include "iaesni.h"
+#include <windows.h>
+
+// test vectors from fips-197 Appendix C http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
+
+unsigned char test_plain_text[16] = {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff};
+unsigned char test_cipher_text_128[16] = {0x69,0xc4,0xe0,0xd8,0x6a,0x7b,0x04,0x30,0xd8,0xcd,0xb7,0x80,0x70,0xb4,0xc5,0x5a};
+unsigned char test_cipher_text_192[16] = {0xdd,0xa9,0x7c,0xa4,0x86,0x4c,0xdf,0xe0,0x6e,0xaf,0x70,0xa0,0xec,0x0d,0x71,0x91};
+unsigned char test_cipher_text_256[16] = {0x8e,0xa2,0xb7,0xca,0x51,0x67,0x45,0xbf,0xea,0xfc,0x49,0x90,0x4b,0x49,0x60,0x89};
+unsigned char test_key_128[16] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
+unsigned char test_key_192[24] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17};
+unsigned char test_key_256[32] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f};
+unsigned char test_iv[16] = {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff};
+
+SYSTEM_INFO si;
+
+
+#define TEST_PASS (0)
+#define TEST_FAIL_ENC (1)
+#define TEST_FAIL_DEC (2)
+
+int test128(unsigned long numBlocks)
+{
+	unsigned int buffer_size = numBlocks*16;
+	unsigned int i;
+	UCHAR *testVector = (UCHAR*)_alloca(buffer_size);
+	UCHAR *testResult = (UCHAR*)_alloca(buffer_size);
+	for (i=0;i<buffer_size;i++)
+	{
+		testVector[i] = test_plain_text[i % 16];
+		testResult[i] = 0xee;
+	}
+
+	intel_AES_enc128(testVector,testResult,test_key_128,numBlocks);
+
+	for (i=0;i<buffer_size;i++)
+	{
+		if (testResult[i] != test_cipher_text_128[i % 16])
+			return TEST_FAIL_ENC;
+
+		testVector[i] = 0xdd;
+	}
+
+	intel_AES_dec128(testResult,testVector,test_key_128,numBlocks);
+
+	for (i=0;i<buffer_size;i++)
+	{
+		if (testVector[i] != test_plain_text[i % 16])
+			return TEST_FAIL_DEC;
+	}
+
+	return TEST_PASS;
+
+}
+
+
+int test128_CBC(unsigned long numBlocks)
+{
+	unsigned int buffer_size = numBlocks*16;
+	unsigned int i;
+	UCHAR *testVector = (UCHAR*)_alloca(buffer_size);
+	UCHAR *testResult = (UCHAR*)_alloca(buffer_size);
+	UCHAR local_test_iv[16];
+
+	for (i=0;i<buffer_size;i++)
+	{
+		testVector[i] = test_plain_text[i % 16];
+		testResult[i] = 0xee;
+	}
+
+	memcpy(local_test_iv,test_iv,16);
+	intel_AES_enc128_CBC(testVector,testResult,test_key_128,numBlocks,local_test_iv);
+
+	//test chaining as well
+	memcpy(local_test_iv,test_iv,16);
+	unsigned int half_size = numBlocks/2;
+	intel_AES_dec128_CBC(testResult,testVector,test_key_128,half_size,local_test_iv);
+	intel_AES_dec128_CBC(testResult+16*(half_size),testVector+16*(half_size),test_key_128,numBlocks - half_size,local_test_iv);
+
+	for (i=0;i<buffer_size;i++)
+	{
+		if (testVector[i] != test_plain_text[i % 16])
+		{
+			printf("%d",i);
+			return TEST_FAIL_DEC;
+		}
+	}
+
+	return TEST_PASS;
+
+}
+
+
+
+
+int test192(unsigned long numBlocks)
+{
+	unsigned int buffer_size = numBlocks*16;
+	unsigned int i;
+	UCHAR *testVector = (UCHAR*)_alloca(buffer_size);
+	UCHAR *testResult = (UCHAR*)_alloca(buffer_size);
+	for (i=0;i<buffer_size;i++)
+	{
+		testVector[i] = test_plain_text[i % 16];
+		testResult[i] = 0xee;
+	}
+
+	intel_AES_enc192(testVector,testResult,test_key_192,numBlocks);
+
+	for (i=0;i<buffer_size;i++)
+	{
+		if (testResult[i] != test_cipher_text_192[i % 16])
+			return TEST_FAIL_ENC;
+
+		testVector[i] = 0xdd;
+	}
+
+	intel_AES_dec192(testResult,testVector,test_key_192,numBlocks);
+
+	for (i=0;i<buffer_size;i++)
+	{
+		if (testVector[i] != test_plain_text[i % 16])
+			return TEST_FAIL_DEC;
+	}
+
+	return 0;
+
+}
+
+
+int test192_CBC(unsigned long numBlocks)
+{
+	unsigned int buffer_size = numBlocks*16;
+	unsigned int i;
+	UCHAR *testVector = (UCHAR*)_alloca(buffer_size);
+	UCHAR *testResult = (UCHAR*)_alloca(buffer_size);
+	UCHAR local_test_iv[16];
+
+	memcpy(local_test_iv,test_iv,16);
+
+	for (i=0;i<buffer_size;i++)
+	{
+		testVector[i] = test_plain_text[i % 16];
+		testResult[i] = 0xee;
+	}
+
+	intel_AES_enc192_CBC(testVector,testResult,test_key_128,numBlocks,local_test_iv);
+
+
+	memcpy(local_test_iv,test_iv,16);
+	unsigned int half_size = numBlocks/2;
+	intel_AES_dec192_CBC(testResult,testVector,test_key_128,half_size,local_test_iv);
+	intel_AES_dec192_CBC(testResult+16*(half_size),testVector+16*(half_size),test_key_128,numBlocks - half_size,local_test_iv);
+
+	for (i=0;i<buffer_size;i++)
+	{
+		if (testVector[i] != test_plain_text[i % 16])
+			return TEST_FAIL_DEC;
+	}
+
+	return TEST_PASS;
+
+}
+
+
+int test256(unsigned long numBlocks)
+{
+	unsigned int buffer_size = numBlocks*16;
+	unsigned int i;
+	UCHAR *testVector = (UCHAR*)_alloca(buffer_size);
+	UCHAR *testResult = (UCHAR*)_alloca(buffer_size);
+	for (i=0;i<buffer_size;i++)
+	{
+		testVector[i] = test_plain_text[i % 16];
+		testResult[i] = 0xee;
+	}
+
+	intel_AES_enc256(testVector,testResult,test_key_256,numBlocks);
+
+	for (i=0;i<buffer_size;i++)
+	{
+		if (testResult[i] != test_cipher_text_256[i % 16])
+			return TEST_FAIL_ENC;
+
+		testVector[i] = 0xdd;
+	}
+
+	intel_AES_dec256(testResult,testVector,test_key_256,numBlocks);
+
+	for (i=0;i<buffer_size;i++)
+	{
+		if (testVector[i] != test_plain_text[i % 16])
+			return TEST_FAIL_DEC;
+	}
+
+	return 0;
+
+}
+
+
+int test256_CBC(unsigned long numBlocks)
+{
+	unsigned int buffer_size = numBlocks*16;
+	unsigned int i;
+	UCHAR *testVector = (UCHAR*)_alloca(buffer_size);
+	UCHAR *testResult = (UCHAR*)_alloca(buffer_size);
+	UCHAR local_test_iv[16];
+
+	memcpy(local_test_iv,test_iv,16);
+
+	for (i=0;i<buffer_size;i++)
+	{
+		testVector[i] = test_plain_text[i % 16];
+		testResult[i] = 0xee;
+	}
+
+	intel_AES_enc256_CBC(testVector,testResult,test_key_128,numBlocks,local_test_iv);
+
+
+	memcpy(local_test_iv,test_iv,16);
+	unsigned int half_size = numBlocks/2;
+	intel_AES_dec256_CBC(testResult,testVector,test_key_128,half_size,local_test_iv);
+	intel_AES_dec256_CBC(testResult+16*(half_size),testVector+16*(half_size),test_key_128,numBlocks - half_size,local_test_iv);
+
+	for (i=0;i<buffer_size;i++)
+	{
+		if (testVector[i] != test_plain_text[i % 16])
+			return TEST_FAIL_DEC;
+	}
+
+	return TEST_PASS;
+
+}
+
+#define MAX_NUM_THREADS (16)
+#define ITER 30000
+
+#include "iaes_asm_interface.h"
+
+typedef 	void (__cdecl *AESPROC)(sAesData *);
+typedef 	void (__cdecl *KEYGENPROC)(UCHAR *key,UCHAR *round_keys);
+
+struct ThreadCommad;
+DWORD __stdcall ThreadFunction(ThreadCommad *cmd);
+
+
+
+struct ThreadCommad
+{
+	volatile LONG *start_mutex;
+	volatile LONG *end_mutex;
+	UINT num_threads;
+	UINT thread_num;
+	UINT num_iterations;
+	void (__cdecl *proc)(sAesData *);
+	KEYGENPROC key_gen_proc;
+	sAesData data;
+	UCHAR *key;
+	double avg_clocks;
+	char padd[256];
+};
+
+struct TestCfg
+{
+	UINT num_threads;
+	UINT buffer_size;
+	UINT alignment;
+	KEYGENPROC key_gen_proc;
+	AESPROC proc;
+	bool in_place;
+	bool aligned_round_keys;
+	char *name;
+};
+
+TestCfg cfg[] = {
+//	{1,2048,4096,iEncExpandKey256,iEnc256,false,true,"Enc-ECB-256"},
+//	{1,2048,4096,iEncExpandKey192,iEnc192,false,true,"Enc-ECB-192"},
+//	{1,2048,4096,iEncExpandKey128,iEnc128,false,true,"Enc-ECB-128"},
+	
+	{1,2048,4096,iEncExpandKey256,iEnc256_CBC,false,true,"Enc-CBC-256"},
+	{1,2048,4096,iEncExpandKey192,iEnc192_CBC,false,true,"Enc-CBC-192"},
+	{1,2048,4096,iEncExpandKey128,iEnc128_CBC,false,true,"Enc-CBC-128"},
+
+//	{1,2048,4096,iDecExpandKey256,iDec256,false,true,"Dec-ECB-256"},
+//	{1,2048,4096,iDecExpandKey192,iDec192,false,true,"Dec-ECB-192"},
+//	{1,2048,4096,iDecExpandKey128,iDec128,false,true,"Dec-ECB-128"},
+	
+	{1,2048,4096,iDecExpandKey256,iDec256_CBC,false,true,"Dec-CBC-256"},
+	{1,2048,4096,iDecExpandKey192,iDec192_CBC,false,true,"Dec-CBC-192"},
+	{1,2048,4096,iDecExpandKey128,iDec128_CBC,false,true,"Dec-CBC-128"},
+
+};
+
+struct TestCommand
+{
+	LONG start_mutex;
+	char pad1[256];
+	LONG end_mutex;
+	char pad2[256];
+
+	UCHAR iv[16];
+
+	UCHAR round_keys_buf[17*16];
+	bool in_place;
+	UINT num_threads;
+
+	ThreadCommad cmds[MAX_NUM_THREADS];
+
+	void BuildTest(TestCfg *cfg)
+	{
+		UCHAR key[16];
+		UINT i;
+		UINT block_size = ((cfg->buffer_size + 15)/16)*16;
+		num_threads = cfg->num_threads;
+		start_mutex = end_mutex = 0;
+		UCHAR *round_keys = round_keys_buf;
+		in_place = cfg->in_place;
+
+		if (cfg->aligned_round_keys && ((DWORD_PTR)round_keys & 0xf) != 0)
+		{
+			*(DWORD_PTR *)&round_keys += 15;
+			*(DWORD_PTR *)&round_keys /= 16;
+			*(DWORD_PTR *)&round_keys *= 16;
+		}
+		else if (!cfg->aligned_round_keys && ((DWORD_PTR)round_keys & 0xf) == 0)
+		{
+			*(DWORD_PTR *)&round_keys += 15;
+			*(DWORD_PTR *)&round_keys /= 16;
+			*(DWORD_PTR *)&round_keys *= 16;
+			*(DWORD_PTR *)&round_keys += 4;
+		}
+
+		cfg->key_gen_proc(key,round_keys);
+		
+		for (i=0;i<num_threads;i++)
+		{
+			cmds[i].data.in_block = (UCHAR *)_aligned_malloc(block_size,cfg->alignment);
+			if (!in_place) cmds[i].data.out_block = (UCHAR *)_aligned_malloc(block_size,cfg->alignment);
+			cmds[i].num_iterations = ITER;
+			cmds[i].num_threads = num_threads;
+			cmds[i].thread_num = i;
+			cmds[i].proc = cfg->proc;
+			cmds[i].start_mutex = &start_mutex;
+			cmds[i].end_mutex = &end_mutex;
+			cmds[i].data.iv = iv;
+			cmds[i].data.expanded_key = round_keys;
+			cmds[i].data.num_blocks = block_size/16;
+			cmds[i].key_gen_proc = cfg->key_gen_proc;
+			cmds[i].key = (UCHAR *)key;
+		}
+	}
+
+	void ExecuteTest(double *min,double *max,double *avg)
+	{
+		HANDLE *h = new HANDLE[num_threads];
+		UINT i;
+
+		for (i=0;i<num_threads;i++)
+		{
+			h[i] = CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)ThreadFunction,&cmds[i],0,NULL);
+		}
+		WaitForMultipleObjects(num_threads,h,TRUE,INFINITE);
+
+		double amin = 1e38,amax = 0,sum = 0;
+		for (i=0;i<num_threads;i++)
+		{
+			if (cmds[i].avg_clocks < amin) amin = cmds[i].avg_clocks;
+			if (cmds[i].avg_clocks > amax) amax = cmds[i].avg_clocks;
+			sum += cmds[i].avg_clocks;
+		}
+
+		sum /= num_threads;
+
+		*min = amin;
+		*max = amax;
+		*avg = sum;
+
+		delete[] h;
+
+	}
+
+	void FreeTest()
+	{
+		UINT i;
+		for (i=0;i<num_threads;i++)
+		{
+			_aligned_free(cmds[i].data.in_block);
+			if (!in_place) _aligned_free(cmds[i].data.out_block);
+		}
+		
+	}
+
+
+};
+
+
+DWORD __stdcall ThreadFunction(ThreadCommad *cmd)
+{
+	UINT i;
+	if (cmd->num_threads != si.dwNumberOfProcessors)
+		SetThreadAffinityMask(GetCurrentThread(),1<<(cmd->thread_num*2));
+	else
+		SetThreadAffinityMask(GetCurrentThread(),1<<(cmd->thread_num));
+
+
+	SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_TIME_CRITICAL );
+	Sleep(10);
+	InterlockedIncrement(cmd->start_mutex);
+	while(*cmd->start_mutex < cmd->num_threads);
+	cmd->key_gen_proc(cmd->key,cmd->data.expanded_key);
+	cmd->proc(&cmd->data);
+	unsigned __int64 start = do_rdtsc();
+	for (i=0;i<cmd->num_iterations;i++)
+	{
+		cmd->key_gen_proc(cmd->key,cmd->data.expanded_key);
+		cmd->proc(&cmd->data);
+	}
+	unsigned __int64 stop = do_rdtsc() - start;
+	InterlockedIncrement(cmd->end_mutex);
+	while(*cmd->end_mutex < cmd->num_threads);
+	cmd->avg_clocks = (double)stop/(double)cmd->num_iterations;
+	return 0;
+}
+
+
+
+
+UINT test_threads[] = {1,2,4,6,12};
+
+
+void main()
+{
+	int i;
+
+	fprintf(stderr, "This program can take a long time to run and it may use the whole system.\n");
+	fprintf(stderr, "The program gets timing info for various sizes, methods, and number of threads.\n");
+	fprintf(stderr, "It also raises the priority of the timing threads to reduce the variation in performance.\n");
+	if (!check_for_aes_instructions())
+	{
+		printf("no AES instructions detected! - stopping the test app\n");
+		return;
+	}
+
+	printf("AES instructions detected\n");
+
+#if 0
+	for (i=1;i<4096;i+=i*3/2)
+	{
+		printf("testing %d blocks,AES-128: %s",i,(test128(i) != TEST_PASS) ? "FAIL" : "PASS");
+		printf(",AES-192: %s",(test192(i) != TEST_PASS) ? "FAIL" : "PASS");
+		printf(",AES-256: %s",(test256(i) != TEST_PASS) ? "FAIL" : "PASS");
+		printf("\n");
+	}
+
+	for (i=1;i<4096;i+=i*3/2)
+	{
+		printf("testing %d blocks,AES-128-CBC: %s",i,(test128_CBC(i) != TEST_PASS) ? "FAIL" : "PASS");
+		printf(",AES-192-CBC: %s",(test192_CBC(i) != TEST_PASS) ? "FAIL" : "PASS");
+		printf(",AES-256-CBC: %s\n",(test256_CBC(i) != TEST_PASS) ? "FAIL" : "PASS");
+		printf("\n");
+	}
+#endif
+
+	TestCommand cmd;
+	UINT nthr;
+	UINT buffsize;
+
+	GetSystemInfo(&si);
+
+	printf("#threads,#bytes,");
+	for (i=0;i<sizeof(cfg)/sizeof(TestCfg);i++)
+		printf("%s,,,",cfg[i].name);
+	printf("\n");
+	printf(",,");
+	for (i=0;i<sizeof(cfg)/sizeof(TestCfg);i++)
+		printf("min,max,avg,",cfg[i].name);
+	printf("\n");
+
+	for (nthr = 0;nthr < sizeof(test_threads)/sizeof(UINT);nthr++)
+	{
+		if (test_threads[nthr] > si.dwNumberOfProcessors) continue;
+
+		for (buffsize = 16;buffsize < 32*1024;buffsize +=(buffsize/2048 + 1)*16)
+		{
+
+			for (i=0;i<sizeof(cfg)/sizeof(TestCfg);i++)
+			{
+				double min,max,avg;
+				cfg[i].buffer_size = buffsize;
+				cfg[i].num_threads = test_threads[nthr];
+				if (i == 0) 			printf("%d,%d,",cfg[i].num_threads,cfg[i].buffer_size);
+				cmd.BuildTest(&cfg[i]);
+				cmd.ExecuteTest(&min,&max,&avg);
+				printf("%lf,%lf,%lf,",min/buffsize,max/buffsize,avg/buffsize);
+				cmd.FreeTest();
+			}
+			printf("\n");
+		}
+	}
+
+}
diff --git a/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/src/intel_aes.c b/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/src/intel_aes.c
new file mode 100644
--- /dev/null
+++ b/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/src/intel_aes.c
@@ -0,0 +1,308 @@
+/* 
+ * Copyright (c) 2010, Intel Corporation
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *     * Redistributions of source code must retain the above copyright notice, 
+ *       this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Intel Corporation nor the names of its contributors 
+ *       may be used to endorse or promote products derived from this software 
+ *       without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+ * 
+*/
+
+#if (__cplusplus)
+extern "C" {
+#endif
+
+#include "iaesni.h"
+#include "iaes_asm_interface.h"
+
+#if (__cplusplus)
+}
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+
+
+void intel_AES_enc128(UCHAR *plainText,UCHAR *cipherText,UCHAR *key,size_t numBlocks)
+{
+	DEFINE_ROUND_KEYS
+	sAesData aesData;
+	aesData.in_block = plainText;
+	aesData.out_block = cipherText;
+	aesData.expanded_key = expandedKey;
+	aesData.num_blocks = numBlocks;
+
+	iEncExpandKey128(key,expandedKey);
+	iEnc128(&aesData);
+}
+
+
+void intel_AES_enc128_CBC(UCHAR *plainText,UCHAR *cipherText,UCHAR *key,size_t numBlocks,UCHAR *iv)
+{
+	DEFINE_ROUND_KEYS
+	sAesData aesData;
+	aesData.in_block = plainText;
+	aesData.out_block = cipherText;
+	aesData.expanded_key = expandedKey;
+	aesData.num_blocks = numBlocks;
+	aesData.iv = iv;
+
+	iEncExpandKey128(key,expandedKey);
+	iEnc128_CBC(&aesData);
+}
+
+
+void intel_AES_enc192(UCHAR *plainText,UCHAR *cipherText,UCHAR *key,size_t numBlocks)
+{
+	DEFINE_ROUND_KEYS
+	sAesData aesData;
+	aesData.in_block = plainText;
+	aesData.out_block = cipherText;
+	aesData.expanded_key = expandedKey;
+	aesData.num_blocks = numBlocks;
+
+	iEncExpandKey192(key,expandedKey);
+	iEnc192(&aesData);
+}
+
+
+void intel_AES_enc192_CBC(UCHAR *plainText,UCHAR *cipherText,UCHAR *key,size_t numBlocks,UCHAR *iv)
+{
+	DEFINE_ROUND_KEYS
+	sAesData aesData;
+	aesData.in_block = plainText;
+	aesData.out_block = cipherText;
+	aesData.expanded_key = expandedKey;
+	aesData.num_blocks = numBlocks;
+	aesData.iv = iv;
+
+	iEncExpandKey192(key,expandedKey);
+	iEnc192_CBC(&aesData);
+}
+
+
+void intel_AES_enc256(UCHAR *plainText,UCHAR *cipherText,UCHAR *key,size_t numBlocks)
+{
+	DEFINE_ROUND_KEYS
+	sAesData aesData;
+	aesData.in_block = plainText;
+	aesData.out_block = cipherText;
+	aesData.expanded_key = expandedKey;
+	aesData.num_blocks = numBlocks;
+
+	iEncExpandKey256(key,expandedKey);
+	iEnc256(&aesData);
+}
+
+
+void intel_AES_enc256_CBC(UCHAR *plainText,UCHAR *cipherText,UCHAR *key,size_t numBlocks,UCHAR *iv)
+{
+	DEFINE_ROUND_KEYS
+	sAesData aesData;
+	aesData.in_block = plainText;
+	aesData.out_block = cipherText;
+	aesData.expanded_key = expandedKey;
+	aesData.num_blocks = numBlocks;
+	aesData.iv = iv;
+
+	iEncExpandKey256(key,expandedKey);
+	iEnc256_CBC(&aesData);
+}
+
+
+void intel_AES_dec128(UCHAR *cipherText,UCHAR *plainText,UCHAR *key,size_t numBlocks)
+{
+	DEFINE_ROUND_KEYS
+	sAesData aesData;
+	aesData.in_block = cipherText;
+	aesData.out_block = plainText;
+	aesData.expanded_key = expandedKey;
+	aesData.num_blocks = numBlocks;
+
+	iDecExpandKey128(key,expandedKey);
+	iDec128(&aesData);
+}
+
+void intel_AES_dec128_CBC(UCHAR *cipherText,UCHAR *plainText,UCHAR *key,size_t numBlocks,UCHAR *iv)
+{
+	DEFINE_ROUND_KEYS
+	sAesData aesData;
+	aesData.in_block = cipherText;
+	aesData.out_block = plainText;
+	aesData.expanded_key = expandedKey;
+	aesData.num_blocks = numBlocks;
+	aesData.iv = iv;
+
+	iDecExpandKey128(key,expandedKey);
+	iDec128_CBC(&aesData);
+}
+
+
+void intel_AES_dec192(UCHAR *cipherText,UCHAR *plainText,UCHAR *key,size_t numBlocks)
+{
+	DEFINE_ROUND_KEYS
+	sAesData aesData;
+	aesData.in_block = cipherText;
+	aesData.out_block = plainText;
+	aesData.expanded_key = expandedKey;
+	aesData.num_blocks = numBlocks;
+
+	iDecExpandKey192(key,expandedKey);
+	iDec192(&aesData);
+}
+
+
+void intel_AES_dec192_CBC(UCHAR *cipherText,UCHAR *plainText,UCHAR *key,size_t numBlocks,UCHAR *iv)
+{
+	DEFINE_ROUND_KEYS
+	sAesData aesData;
+	aesData.in_block = cipherText;
+	aesData.out_block = plainText;
+	aesData.expanded_key = expandedKey;
+	aesData.num_blocks = numBlocks;
+	aesData.iv = iv;
+
+	iDecExpandKey192(key,expandedKey);
+	iDec192_CBC(&aesData);
+}
+
+
+void intel_AES_dec256(UCHAR *cipherText,UCHAR *plainText,UCHAR *key,size_t numBlocks)
+{
+	DEFINE_ROUND_KEYS
+	sAesData aesData;
+	aesData.in_block = cipherText;
+	aesData.out_block = plainText;
+	aesData.expanded_key = expandedKey;
+	aesData.num_blocks = numBlocks;
+
+	iDecExpandKey256(key,expandedKey);
+	iDec256(&aesData);
+}
+
+
+void intel_AES_dec256_CBC(UCHAR *cipherText,UCHAR *plainText,UCHAR *key,size_t numBlocks,UCHAR *iv)
+{
+	DEFINE_ROUND_KEYS
+	sAesData aesData;
+	aesData.in_block = cipherText;
+	aesData.out_block = plainText;
+	aesData.expanded_key = expandedKey;
+	aesData.num_blocks = numBlocks;
+	aesData.iv = iv;
+
+	iDecExpandKey256(key,expandedKey);
+	iDec256_CBC(&aesData);
+}
+
+
+
+void intel_AES_encdec256_CTR(UCHAR *in,UCHAR *out,UCHAR *key,size_t numBlocks,UCHAR *ic)
+{
+	DEFINE_ROUND_KEYS
+	sAesData aesData;
+	aesData.in_block = in;
+	aesData.out_block = out;
+	aesData.expanded_key = expandedKey;
+	aesData.num_blocks = numBlocks;
+	aesData.iv = ic;
+
+	iEncExpandKey256(key,expandedKey);
+	iEnc256_CTR(&aesData);
+}
+
+void intel_AES_encdec192_CTR(UCHAR *in,UCHAR *out,UCHAR *key,size_t numBlocks,UCHAR *ic)
+{
+	DEFINE_ROUND_KEYS
+	sAesData aesData;
+	aesData.in_block = in;
+	aesData.out_block = out;
+	aesData.expanded_key = expandedKey;
+	aesData.num_blocks = numBlocks;
+	aesData.iv = ic;
+
+	iEncExpandKey192(key,expandedKey);
+	iEnc192_CTR(&aesData);
+}
+
+void intel_AES_encdec128_CTR(UCHAR *in,UCHAR *out,UCHAR *key,size_t numBlocks,UCHAR *ic)
+{
+	DEFINE_ROUND_KEYS
+	sAesData aesData;
+	aesData.in_block = in;
+	aesData.out_block = out;
+	aesData.expanded_key = expandedKey;
+	aesData.num_blocks = numBlocks;
+	aesData.iv = ic;
+
+	iEncExpandKey128(key,expandedKey);
+	iEnc128_CTR(&aesData);
+}
+
+
+
+#if defined __linux__ || defined __APPLE__ 
+static void __cpuid(unsigned int where[4], unsigned int leaf) {
+  asm volatile("cpuid":"=a"(*where),"=b"(*(where+1)), "=c"(*(where+2)),"=d"(*(where+3)):"a"(leaf));
+  return;
+}
+#else // windows
+#include <intrin.h>
+#endif
+
+/* 
+ * check_for_aes_instructions()
+ *   return 1 if support AES-NI and 0 if don't support AES-NI
+ */
+
+int check_for_aes_instructions()
+{
+	unsigned int cpuid_results[4];
+	int yes=1, no=0;
+
+	__cpuid(cpuid_results,0);
+
+	if (cpuid_results[0] < 1)
+		return no;
+/*
+ *      MSB         LSB
+ * EBX = 'u' 'n' 'e' 'G'
+ * EDX = 'I' 'e' 'n' 'i'
+ * ECX = 'l' 'e' 't' 'n'
+ */
+	
+	if (memcmp((unsigned char *)&cpuid_results[1], "Genu", 4) != 0 ||
+		memcmp((unsigned char *)&cpuid_results[3], "ineI", 4) != 0 ||
+		memcmp((unsigned char *)&cpuid_results[2], "ntel", 4) != 0)
+		return no;
+
+	__cpuid(cpuid_results,1);
+
+	if (cpuid_results[2] & AES_INSTRCTIONS_CPUID_BIT)
+		return yes;
+
+	return no;
+}
+
+
+
diff --git a/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/where_files_come_from_and_license.txt b/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/where_files_come_from_and_license.txt
new file mode 100644
--- /dev/null
+++ b/cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/where_files_come_from_and_license.txt
@@ -0,0 +1,34 @@
+/* intel_aes_lib source files come from Intel.
+ * Modified by Patrick Fay
+ *
+Copyright (c) 2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without 
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+      this list of conditions and the following disclaimer.
+    * 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.
+    * Neither the name of Intel Corporation nor the names of its contributors 
+      may be used to endorse or promote products derived from this software 
+      without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+
+ ---------------------------------------------------------------------------
+ Issue Date: Aug 6, 2010
+ */
+
+Other source code files use the license shown in the source code file.
diff --git a/cbits/Makefile b/cbits/Makefile
new file mode 100644
--- /dev/null
+++ b/cbits/Makefile
@@ -0,0 +1,9 @@
+
+
+
+all:
+	cd Intel_AESNI_Sample_Library_v1.0/intel_aes_lib; $(MAKE)
+
+clean:
+	cd Intel_AESNI_Sample_Library_v1.0/intel_aes_lib; $(MAKE) clean
+	rm -f libintel_aes.a libintel_aes.so
diff --git a/cbits/c_test.c b/cbits/c_test.c
new file mode 100644
--- /dev/null
+++ b/cbits/c_test.c
@@ -0,0 +1,55 @@
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+// Haskell can call this with a memory location.
+// void blast_rands(int* ptr1, int* ptr2)
+void blast_rands(int count, int* ptr)
+{
+  int i;
+  for(i=0; i<count; i++)
+  {
+    *ptr = rand();
+  }
+}
+
+void store_loop(int count, volatile int* ptr)
+{
+  int i;
+  for(i=0; i<count; i++)
+  {
+    *ptr += 1;
+  }
+}
+
+
+#if 0
+// On a 3.33ghz desktop nehalem this produces 100M rands in 0.826 seconds.
+int main() {
+
+  int i, sum = 0; 
+  for(i=0; i<100000000; i++) 
+  {
+    sum += rand();
+  }
+
+  printf("Sum of 100M randoms: %d\n", sum);
+
+  return 0;
+}
+#endif
+
+
+
+// [2011.01.30] TEMP, testing AES bindings
+#if 0
+#include "iaesni.h"
+
+void temp_test128()
+{
+   printf("  Inside C test...\n");
+   
+}
+#endif
diff --git a/cbits/gladman/aes.h b/cbits/gladman/aes.h
new file mode 100644
--- /dev/null
+++ b/cbits/gladman/aes.h
@@ -0,0 +1,205 @@
+/*
+ ---------------------------------------------------------------------------
+ Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
+
+ LICENSE TERMS
+
+ The redistribution and use of this software (with or without changes)
+ is allowed without the payment of fees or royalties provided that:
+
+  1. source code distributions include the above copyright notice, this
+     list of conditions and the following disclaimer;
+
+  2. binary distributions include the above copyright notice, this list
+     of conditions and the following disclaimer in their documentation;
+
+  3. the name of the copyright holder is not used to endorse products
+     built using this software without specific written permission.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ ---------------------------------------------------------------------------
+ Issue Date: 20/12/2007
+
+ This file contains the definitions required to use AES in C. See aesopt.h
+ for optimisation details.
+*/
+
+#ifndef _AES_H
+#define _AES_H
+
+#include <stdlib.h>
+
+/*  This include is used to find 8 & 32 bit unsigned integer types  */
+#include "brg_types.h"
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+#define AES_128     /* if a fast 128 bit key scheduler is needed    */
+#define AES_192     /* if a fast 192 bit key scheduler is needed    */
+#define AES_256     /* if a fast 256 bit key scheduler is needed    */
+#define AES_VAR     /* if variable key size scheduler is needed     */
+#define AES_MODES   /* if support is needed for modes               */
+
+/* The following must also be set in assembler files if being used  */
+
+#define AES_ENCRYPT /* if support for encryption is needed          */
+#define AES_DECRYPT /* if support for decryption is needed          */
+#define AES_REV_DKS /* define to reverse decryption key schedule    */
+
+#define AES_BLOCK_SIZE  16  /* the AES block size in bytes          */
+#define N_COLS           4  /* the number of columns in the state   */
+
+/* The key schedule length is 11, 13 or 15 16-byte blocks for 128,  */
+/* 192 or 256-bit keys respectively. That is 176, 208 or 240 bytes  */
+/* or 44, 52 or 60 32-bit words.                                    */
+
+#if defined( AES_VAR ) || defined( AES_256 )
+#define KS_LENGTH       60
+#elif defined( AES_192 )
+#define KS_LENGTH       52
+#else
+#define KS_LENGTH       44
+#endif
+
+#define AES_RETURN INT_RETURN
+
+/* the character array 'inf' in the following structures is used    */
+/* to hold AES context information. This AES code uses cx->inf.b[0] */
+/* to hold the number of rounds multiplied by 16. The other three   */
+/* elements can be used by code that implements additional modes    */
+
+typedef union
+{   uint_32t l;
+    uint_8t b[4];
+} aes_inf;
+
+typedef struct
+{   uint_32t ks[KS_LENGTH];
+    aes_inf inf;
+} aes_encrypt_ctx;
+
+typedef struct
+{   uint_32t ks[KS_LENGTH];
+    aes_inf inf;
+} aes_decrypt_ctx;
+
+/* This routine must be called before first use if non-static       */
+/* tables are being used                                            */
+
+AES_RETURN aes_init(void);
+
+/* Key lengths in the range 16 <= key_len <= 32 are given in bytes, */
+/* those in the range 128 <= key_len <= 256 are given in bits       */
+
+#if defined( AES_ENCRYPT )
+
+#if defined( AES_128 ) || defined( AES_VAR)
+AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]);
+#endif
+
+#if defined( AES_192 ) || defined( AES_VAR)
+AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]);
+#endif
+
+#if defined( AES_256 ) || defined( AES_VAR)
+AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]);
+#endif
+
+#if defined( AES_VAR )
+AES_RETURN aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1]);
+#endif
+
+AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]);
+
+#endif
+
+#if defined( AES_DECRYPT )
+
+#if defined( AES_128 ) || defined( AES_VAR)
+AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]);
+#endif
+
+#if defined( AES_192 ) || defined( AES_VAR)
+AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]);
+#endif
+
+#if defined( AES_256 ) || defined( AES_VAR)
+AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]);
+#endif
+
+#if defined( AES_VAR )
+AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1]);
+#endif
+
+AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]);
+
+#endif
+
+#if defined( AES_MODES )
+
+/* Multiple calls to the following subroutines for multiple block   */
+/* ECB, CBC, CFB, OFB and CTR mode encryption can be used to handle */
+/* long messages incremantally provided that the context AND the iv */
+/* are preserved between all such calls.  For the ECB and CBC modes */
+/* each individual call within a series of incremental calls must   */
+/* process only full blocks (i.e. len must be a multiple of 16) but */
+/* the CFB, OFB and CTR mode calls can handle multiple incremental  */
+/* calls of any length. Each mode is reset when a new AES key is    */
+/* set but ECB and CBC operations can be reset without setting a    */
+/* new key by setting a new IV value.  To reset CFB, OFB and CTR    */
+/* without setting the key, aes_mode_reset() must be called and the */
+/* IV must be set.  NOTE: All these calls update the IV on exit so  */
+/* this has to be reset if a new operation with the same IV as the  */
+/* previous one is required (or decryption follows encryption with  */
+/* the same IV array).                                              */
+
+AES_RETURN aes_test_alignment_detection(unsigned int n);
+
+AES_RETURN aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, const aes_encrypt_ctx cx[1]);
+
+AES_RETURN aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, const aes_decrypt_ctx cx[1]);
+
+AES_RETURN aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, unsigned char *iv, const aes_encrypt_ctx cx[1]);
+
+AES_RETURN aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, unsigned char *iv, const aes_decrypt_ctx cx[1]);
+
+AES_RETURN aes_mode_reset(aes_encrypt_ctx cx[1]);
+
+AES_RETURN aes_cfb_encrypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, unsigned char *iv, aes_encrypt_ctx cx[1]);
+
+AES_RETURN aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, unsigned char *iv, aes_encrypt_ctx cx[1]);
+
+#define aes_ofb_encrypt aes_ofb_crypt
+#define aes_ofb_decrypt aes_ofb_crypt
+
+AES_RETURN aes_ofb_crypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, unsigned char *iv, aes_encrypt_ctx cx[1]);
+
+typedef void cbuf_inc(unsigned char *cbuf);
+
+#define aes_ctr_encrypt aes_ctr_crypt
+#define aes_ctr_decrypt aes_ctr_crypt
+
+AES_RETURN aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf,
+            int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx cx[1]);
+
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/cbits/gladman/aes.txt b/cbits/gladman/aes.txt
new file mode 100644
--- /dev/null
+++ b/cbits/gladman/aes.txt
@@ -0,0 +1,556 @@
+
+An AES (Rijndael) Implementation in C/C++ (as specified in FIPS-197)
+====================================================================
+
+Changes in this Version (16/04/2007)
+====================================
+
+These changes remove errors in the VC++ build files and add some 
+improvements in file naming consitency and portability. There are
+no changes to overcome reported bugs in the code.
+
+1. gen_tabs() has been renamed to aes_init() to better decribe its
+   function to those not familiar with AES internals.
+
+2. via_ace.h has been renamed to aes_via_ace.h.
+
+3. Minor changes have been made to aestab.h and aestab.c to enable
+   all the code to be compiled in either C or C++.
+   
+4. The code for detecting memory alignment in aesmdoes.c has been
+   simplified and a new routine has been added:
+   
+       aes_test_alignment_detection()
+   
+   to check that the aligment test is likely to be correct.
+
+5. The addition of support for Structured Exception Handling (SEH) 
+   to YASM (well done Peter and Michael!) has allowed the AMD64 
+   x64 assembler code to be changed to comply with SEH requriements.
+       
+6. Corrections to build files (for win32 debug build).
+
+Overview
+========
+
+This code implements AES for both 32 and 64 bit systems with optional
+assembler support for x86 and AMD64/EM64T (but optimised for AMD64).
+
+The basic AES source code files are as follows:
+
+aes.h           the header file needed to use AES in C
+aescpp.h        the header file required with to use AES in C++
+aesopt.h        the header file for setting options (and some common code)
+aestab.h        the header file for the AES table declaration
+aescrypt.c      the main C source code file for encryption and decryption
+aeskey.c        the main C source code file for the key schedule
+aestab.c        the main file for the AES tables
+brg_types.h     a header defining some standard types and DLL defines
+brg_endian.h    a header containing code to detect or define endianness
+aes_x86_v1.asm  x86 assembler (YASM) alternative to aescrypt.c using
+                large tables
+aes_x86_v2.asm  x86 assembler (YASM) alternative to aescrypt.c using
+                compressed tables
+aes_amd64.asm   AMD64 assembler (YASM) alternative to aescrypt.c using
+                compressed tables
+
+In addition AES modes are implemented in the files:
+
+aes_modes.c     AES modes with optional support for VIA ACE detection and use
+aes_via_ace.h   the header file for VIA ACE support
+
+Other associated files for testing and support are:
+
+aesaux.h        header for auxilliary routines for testsing
+aesaux.c        auxilliary routines for testsingt
+aestst.h        header file for setting the testing environment
+rdtsc.h         a header file that provides access to the Time Stamp Counter
+aestst.c        a simple test program for quick tests of the AES code
+aesgav.c        a program to generate and verify the test vector files
+aesrav.c        a program to verify output against the test vector files
+aestmr.c        a program to time the code on x86 systems
+modetest.c      a program to test the AES modes support
+vbxam.doc       a demonstration of AES DLL use from Visual Basic in Microsoft Word
+vb.txt          Visual Basic code from the above example (win32 only)
+aesxam.c        an example of AES use
+tablegen.c      a program to generate a simplified 'aestab.c' file for
+                use with compilers that find aestab.c too complex
+yasm.rules      the YASM build rules file for Microsoft Visual Studio 2005
+via_ace.txt     describes support for the VIA ACE cryptography engine
+aes.txt         this file
+
+Building The AES Libraries
+--------------------------
+
+A. Versions
+-----------
+
+The code can be used to build static and dynamic libraries, each in five
+versions:
+
+    C           uses C source code only
+    ASM_X86_V1C large table x86 assembler code for encrypt/decrypt
+    ASM_X86_V2  compressed table x86 assembler for encrypt/decrypt and keying
+    ASM_X86_V2C compressed table x86 assembler code for encrypt/decrypt
+    ASM_AMD64   compressed table x86 assembler code for encrypt/decrypt
+
+The C version can be compiled for Win32 or x64, the x86 assembler versions
+are for Win32 only and the AMD64 version for x64 only.
+
+B. Types
+--------
+
+The code makes use of types defined as uint_<nn>t where <nn> is the length
+of the type, for example, the unsigned 32-bit type is 'uint_32t'.  These are
+NOT the same as the fixed width integer types in C99, inttypes.h and stdint.h
+since several attempts to use these types have shown that support for them is
+still highly variable.  But a regular expression search and replace in VC++
+with search on 'uint_{:z}t' and a replace with 'uint\1_t' will convert these
+types to C99 types (there should be similar search/replace facilities on other
+systems).
+
+C. YASM
+-------
+
+If you wish to use the x86 assembler files you will also need the YASM open
+source x86 assembler (r1331 or later) for Windows which can be obtained from:
+
+  http://www.tortall.net/projects/yasm/
+
+This assembler should be placed in the bin directory used by VC++, which, for
+Visual Stduio 2005, is typically:
+
+ C:\Program Files (x86)\Microsoft Visual Studio 8\VC\bin
+
+You will also need to move the yasm.rules file from this distribution into
+the directory where Visual Studio 2005 expects to find it, which is typically:
+
+ C:\Program Files (x86)\Microsoft Visual Studio 8\VC\VCProjectDefaults
+
+Alternatively you can configure the path for rules files within Visual Studio.
+
+D. Configuration
+----------------
+
+The following configurations are available as projects for Visual Studio 2005
+but the following descriptions should allow them to be built in other x86
+environments:
+
+    lib_generic_c       Win32 and x64
+        headers:        aes.h, aesopt.h, aestab.h, brg_endian.h, tdefs,h
+        C source:       aescrypt.c, aeskey.c, aestab.c, aes_modes.c
+        defines
+    dll_generic_c       Win32 and x64
+        headers:        aes.h, aesopt.h, aestab.h, brg_endian.h, tdefs,h
+        C source:       aescrypt.c, aeskey.c, aestab.c, aes_modes.c
+        defines         DLL_EXPORT
+
+    lib_asm_x86_v1c     Win32
+        headers:        aes.h, aesopt.h, aestab.h, brg_endian.h, tdefs,h
+        C source:       aeskey.c, aestab.c, aes_modes.c
+        x86 assembler:  aes_x86_v1.asm
+        defines         ASM_X86_V1C (set for C and assembler files)
+    dll_asm_x86_v1c     Win32
+        headers:        aes.h, aesopt.h, aestab.h, brg_endian.h, tdefs,h
+        C source:       aeskey.c, aestab.c, aes_modes.c
+        x86 assembler:  aes_x86_v1.asm
+        defines         DLL_EXPORT, ASM_X86_V1C (set for C and assembler files)
+
+    lib_asm_x86_v2c     Win32
+        headers:        aes.h, aesopt.h, aestab.h, brg_endian.h, tdefs,h
+        C source:       aeskey.c, aestab.c, aes_modes.c
+        x86 assembler:  aes_x86_v2.asm
+        defines         ASM_X86_V2C (set for C and assembler files)
+    dll_asm_x86_v2c     Win32
+        headers:        aes.h, aesopt.h, aestab.h, brg_endian.h, tdefs,h
+        C source:       aeskey.c, aestab.c, aes_modes.c
+        x86 assembler:  aes_x86_v1.asm
+        defines         DLL_EXPORT, ASM_X86_V2C (set for C and assembler files)
+
+    lib_asm_x86_v2      Win32
+        headers:        aes.h, aesopt.h, aestab.h, brg_endian.h, tdefs,h
+        C source:       aes_modes.c
+        x86 assembler:  aes_x86_v1.asm
+        defines         ASM_X86_V2 (set for C and assembler files)
+    dll_asm_x86_v2      Win32
+        headers:        aes.h, aesopt.h, aestab.h, brg_endian.h, tdefs,h
+        C source:       aes_modes.c
+        x86 assembler:  aes_x86_v1.asm
+        defines         DLL_EXPORT, ASM_AMD64_C (set for C and assembler files)
+
+    lib_asm_amd64_c     x64
+        headers:        aes.h, aesopt.h, aestab.h, brg_endian.h, tdefs,h
+        C source:       aes_modes.c
+        x86 assembler:  aes_amd64.asm
+        defines         ASM_X86_V2 (set for C and assembler files)
+    dll_asm_amd64_c     x64
+        headers:        aes.h, aesopt.h, aestab.h, brg_endian.h, tdefs,h
+        C source:       aes_modes.c
+        x86 assembler:  aes_amd64.asm
+        defines         DLL_EXPORT, ASM_AMD64_C (set for C and assembler files)
+
+Notes:
+
+ASM_X86_V1C is defined if using the version 1 assembler code (aescrypt1.asm).
+            The defines in the assember file must match those in aes.h and
+            aesopt.h).  Also remember to include/exclude the right assembler
+            and C files in the build to avoid undefined or multiply defined
+            symbols - include aescrypt1.asm and exclude aescrypt.c and
+            aescrypt2.asm.
+
+ASM_X86_V2  is defined if using the version 2 assembler code (aescrypt2.asm).
+            This version provides a full, self contained assembler version
+            and does not use any C source code files except for the mutiple
+            block encryption modes that are provided by aes_modes.c. The define
+            ASM_X86_V2 must be set on the YASM command line (or in aescrypt2.asm)
+            to use this version and all C files except aec_modes.c and. for the
+            DLL build, aestab.c must be excluded from the build.
+
+ASM_X86_V2C is defined when using the version 2 assembler code (aescrypt2.asm)
+            with faster key scheduling provided by the in C code (the options in
+            the assember file must match those in aes.h and aesopt.h).  In this
+            case aeskey.c and aestab.c are needed with aescrypt2.asm and the
+            define ASM_X86_V2C must be set for both the C files and for
+            asecrypt2.asm command lines (or in aesopt.h and aescrypt2.asm).
+            Include aescrypt2.asm aeskey.c and aestab.c, exclude aescrypt.c for
+            this option.
+
+ASM_AMD64_C is defined when using the AMD64 assembly code because the C key
+            scheduling is sued in this case.
+
+DLL_EXPORT  must be defined to generate the DLL version of the code and
+            to run tests on it
+
+DLL_IMPORT  must be defined to use the DLL version of the code in an
+            application program
+
+Directories the paths for the various directories for test vector input and
+            output have to be set in aestst.h
+
+VIA ACE     see the via_ace.txt for this item
+
+Static      The static libraries are named:
+Libraries
+                aes_lib_generic_c.lib
+                aes_lib_asm_x86_v1c.lib
+                aes_lib_asm_x86_v2.lib
+                aes_lib_asm_x86_v2c.lib
+                aes_lib_asm_amd64_c.lib
+
+            and placed in one of the the directories:
+
+                lib\win32\release\
+                lib\win32\debug\
+                lib\x64\release\
+                lib\x64\debug\
+
+            in the aes root directory depending on the platform(win32 or
+            x64) and the build (release or debug). After any of these is
+            built it is then copied into aes.lib, which is the library
+            that is subsequently used for testing. Hence testing is for
+            the last static library built.
+
+Dynamic     The static libraries are named:
+Libraries
+                aes_lib_generic_c.dll
+                aes_lib_asm_x86_v1c.dll
+                aes_lib_asm_x86_v2.dll
+                aes_lib_asm_x86_v2c.dll
+                aes_lib_asm_amd64_c.dll
+
+            and placed in one of the the directories:
+
+                dll\win32\release\
+                dll\win32\debug\
+                dll\x64\release\
+                dll\x64\debug\
+
+            in the aes root directory depending on the platform(win32 or
+            x64) and the build (release or debug).  Each DLL library:
+
+                aes_<ext>.dll
+
+            has three associated files:
+
+                aes_dll_<ext>.lib   the library file for implicit linking
+                aes_dll_<ext>.exp   the exports file
+                aes_dll_<ext>.pdb   the symbol file
+
+            After any DLL is built it and its three related files are then
+            copied into aes.lib, aes.lib, aes,exp and aes.pdb, which are
+            the libraries used for testing.  Hence testing is for the last
+            static library or DLL built.
+
+E. Testing
+----------
+
+These tests require that the test vector files are placed in the 'testvals' 
+subdirectory. If the AES Algorithm Validation Suite tests will be use3d then
+the *.fax files need to be put in the 'testvals\fax' subdirectory.  This is
+covered in more detail below.
+
+The projects test_dll and time_dll are used to test and time the last DLL
+built.  These use the files:
+
+    test_dll:       Win32 (x64 for the C and AMD64 versions)
+        headers:    aes.h, aescpp.h, brg_types.h, aesaux.h and aestst.h
+        C source:   aesaux.c, aesrav.c
+        defines:    DLL_IMPORT
+
+    time_dll:       Win32 (x64 for the C and AMD64 versions)
+        headers:    aes.h, aescpp.h, brg_types.h, aesaux.h aestst.h and rdtsc.h
+        C source:   aesaux.c, aestmr.c
+        defines:    DLL_IMPORT
+
+and link to the DLL using explicit linking. However, if the lib file associated
+with the DLL is linked into this project and the symbol DYNAMIC_LINK in aestst.h
+is left undefined, then implicit linking will be used
+
+The projects test_lib and time_lib are used to test and time the last static LIB
+built. They use the files:
+
+    test_lib:       Win32 (x64 for the C and AMD64 versions)
+        headers:    aes.h, aescpp.h, brg_types.h, aesaux.h and aestst.h
+        C source:   aesaux.c, aesrav.c
+        defines:
+
+    time_lib:       Win32 (x64 for the C and AMD64 versions)
+        headers:    aes.h, aescpp.h, brg_types.h, aesaux.h, aestst.h and rdtsc.h
+        C source:   aesaux.c, aestmr.c
+        defines:
+
+and link to the last static library built.
+
+The above test take command line arguments that determine which test are run
+as follows:
+
+    test_lib /t:[knec] /k:[468]
+    test_dll /t:[knec] /k:[468]
+
+where the symbols in square brackets can be used in any combination (without
+the brackets) and have the following meanings:
+
+        /t:[knec]   selects which tests are used
+        /k:[468]    selects the key lengths used
+        /c          compares output with reference (see later)
+
+        k: generate ECB Known Answer Test files
+        n: generate ECB Known Answer Test files (new)
+        e: generate ECB Monte Carlo Test files
+        c: generate CBC Monte Carlo Test files
+
+and the characters giving the lengths are digits representing the lengths in
+32-bit units.\n\n");
+
+The project test_modes tests the AES modes.  It uses the files:
+
+    test_modes:     Win32 or x64
+        headers:    aes.h, aescpp.h, brg_types.h, aesaux,h and aestst.h
+        C source:   aesaux.c, modetest.c
+        defines:    none for static library test, DLL_IMPORT for DLL test
+
+which again links to the last library built.
+
+F. Other Applications
+---------------------
+
+These are:
+
+    gen_tests       builds the test_vector files. The commad line is
+                        gen_tests /t:knec /k:468 /c
+                    as described earlier
+                    
+    test_aes_avs    run the AES Algorithm Validation Suite tests for
+                    ECB, CBC, CFB and OFB modes
+
+    gen_tables      builds a simple version of aes_tab.c (in aestab2.c)
+                    for compilers that cannot handle the normal version
+    aes_example     provides an example of AES use
+
+These applications are linked to the last static library built or, if
+DLL_IMPORT is defined during compilation, to the last DLL built.
+
+G. Use of the VIA ACE Cryptography Engine
+-----------------------------------------
+
+The use of the code with the VIA ACE cryptography engine in described in the
+file via_ace.txt. In outline aes_modes.c is used and USE_VIA_ACE_IF_PRESENT
+is defined either in section 2 of aesopt.h or as a compilation option in Visual
+Studio. If in addition ASSUME_VIA_ACE_PRESENT is also defined then all normal
+AES code will be removed if not needed to support VIA ACE use.  If VIA ACE
+support is needed and AES assembler is being used only the ASM_X86_V1C and
+ASM_X86_V2C versions should be used since ASM_X86_V2 and ASM_AMD64 do not
+support the VIA ACE engine.
+
+H. The AES Test Vector Files
+----------------------------
+
+These files fall in the following groups (where <nn> is a two digit
+number):
+
+1. ecbvk<nn>.txt  ECB vectors with variable key
+2. ecbvt<nn>.txt  ECB vectors with variable text
+3. ecbnk<nn>.txt  new ECB vectors with variable key
+4. ecbnt<nn>.txt  new ECB vectors with variable text
+5. ecbme<nn>.txt  ECB monte carlo encryption test vectors
+6. ecbmd<nn>.txt  ECB monte carlo decryption test vectors
+7. cbcme<nn>.txt  CBC monte carlo encryption test vectors
+8. cbcmd<nn>.txt  CBC monte carlo decryption test vectors
+
+The first digit of the numeric suffix on the filename gives the block size
+in 32 bit units and the second numeric digit gives the key size. For example,
+the file ecbvk44.txt provides the test vectors for ECB encryption with a 128
+bit block size and a 128 bit key size. The test routines expect to find these
+files in the 'testvals' subdirectory within the aes root directory. The
+'outvals' subdirectory is used for outputs that are compared with the files
+in 'testvals'. Note that the monte carlo test vectors are the result of
+applying AES iteratively 10000 times, not just once.
+
+The AES Algorithm Validation Suite tests can be run for ECB, CBC, CFB and 
+OFB modes (CFB1 and CFB8 are not implemented).  The test routine uses the 
+*.fax test files, which should be placed in the 'testvals\fax' subdirectory.
+
+I. The Basic AES Calling Interface
+----------------------------------
+
+The basic AES code keeps its state in a context, there being different 
+contexts for encryption and decryption:
+
+    aes_encrypt_ctx
+    aes_decrypt_ctx
+    
+The AES code is initialised with the call
+
+	aes_init(void)
+	
+although this is only essential if the option to generate the AES tables at 
+run-time has been set in the options (i.e.fixed tables are not being used).
+    
+The AES encryption key is set by one of the calls:
+ 
+    aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1])
+    aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1])
+    aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1])
+
+or by:
+
+    aes_encrypt_key(const unsigned char *key, int key_len, 
+                                                aes_encrypt_ctx cx[1])
+
+where the key length is set by 'key_len', which can be the length in bits 
+or bytes.  
+
+Similarly, the AES decryption key is set by one of:
+
+    aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1])
+    aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1])
+    aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1])
+
+or by:
+
+    aes_decrypt_key(const unsigned char *key, int key_len, 
+                                                aes_decrypt_ctx cx[1])
+ 
+Encryption and decryption for a single 16 byte block is then achieved using:
+
+    aes_encrypt(const unsigned char *in, unsigned char *out, 
+                                            const aes_encrypt_ctx cx[1])
+    aes_decrypt(const unsigned char *in, unsigned char *out, 
+                                            const aes_decrypt_ctx cx[1])
+                                            
+The above subroutines return a value of EXIT_SUCCESS or EXIT_FAILURE 
+depending on whether the operation succeeded or failed.
+ 
+J. The Calling Interface for the AES Modes
+------------------------------------------
+
+The subroutines for the AES modes, ECB, CBC, CFB, OFB and CTR, each process
+blocks of variable length and can also be called several times to complete 
+single mode operations incrementally on long messages (or those messages,
+not all of which are available at the same time).  The calls:
+
+    aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, const aes_encrypt_ctx cx[1])
+
+    aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, const aes_decrypt_ctx cx[1])
+
+for ECB operations and those for CBC:
+
+    aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, unsigned char *iv, const aes_encrypt_ctx cx[1])
+
+    aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, unsigned char *iv, const aes_decrypt_ctx cx[1])
+ 
+can only process blocks whose lengths are multiples of 16 bytes but the calls 
+for CFB, OFB and CTR mode operations:
+
+    aes_cfb_encrypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, unsigned char *iv, aes_encrypt_ctx cx[1])
+
+    aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, unsigned char *iv, aes_encrypt_ctx cx[1])
+
+    aes_ofb_encrypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, unsigned char *iv, aes_encrypt_ctx cx[1])
+
+    aes_ofb_decrypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, unsigned char *iv, aes_encrypt_ctx cx[1])
+
+    aes_ctr_encrypt(const unsigned char *ibuf, unsigned char *obuf,
+            int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx cx[1])
+
+    aes_ctr_decrypt(const unsigned char *ibuf, unsigned char *obuf,
+            int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx cx[1])
+
+can process blocks of any length.  Note also that CFB, OFB and CTR mode calls only
+use AES encryption contexts even during decryption operations.
+
+The calls CTR mode operations use a buffer (cbuf) which holds the counter value
+together with a function parameter:
+
+    void cbuf_inc(unsigned char *cbuf);
+
+that is ued to update the counter value after each 16 byte AES operation. The 
+counter buffer is updated appropriately to allow for incremental operations.
+
+Please note the following IMPORTANT points about the AES mode subroutines:
+
+    1. All modes are reset when a new AES key is set.
+    
+    2. Incremental calls to the different modes cannot 
+       be mixed. If a change of mode is needed a new 
+       key must be set or a reset must be issued (see 
+       below).
+       
+    3. For modes with IVs, the IV value is an inpu AND
+       an ouput since it is updated after each call to 
+       the value needed for any subsequent incremental
+       call(s). If the mode is reset, the IV hence has
+       to be set (or reset) as well.
+       
+    4. ECB operations must be multiples of 16 bytes
+       but do not need to be reset for new operations.
+       
+    5. CBC operations must also be multiples of 16 
+       bytes and are reset for a new operation by 
+       setting the IV.
+       
+    6. CFB, OFB and CTR mode must be reset by setting 
+       a new IV value AND by calling:
+       
+           aes_mode_reset(aes_encrypt_ctx cx[1])
+           
+       For CTR mode the cbuf value also has to be reset.
+       
+    7. CFB, OFB and CTR modes only use AES encryption 
+       operations and contexts and do not need AES
+       decrytpion operations.
+       
+    8. AES keys remain valid across resets and changes
+       of mode (but encryption and decryption keys must 
+       both be set if they are needed).  
+       
+   Brian Gladman  22/07/2008
+   
diff --git a/cbits/gladman/aes_modes.c b/cbits/gladman/aes_modes.c
new file mode 100644
--- /dev/null
+++ b/cbits/gladman/aes_modes.c
@@ -0,0 +1,945 @@
+/*
+ ---------------------------------------------------------------------------
+ Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
+
+ LICENSE TERMS
+
+ The redistribution and use of this software (with or without changes)
+ is allowed without the payment of fees or royalties provided that:
+
+  1. source code distributions include the above copyright notice, this
+     list of conditions and the following disclaimer;
+
+  2. binary distributions include the above copyright notice, this list
+     of conditions and the following disclaimer in their documentation;
+
+  3. the name of the copyright holder is not used to endorse products
+     built using this software without specific written permission.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ ---------------------------------------------------------------------------
+ Issue Date: 20/12/2007
+
+ These subroutines implement multiple block AES modes for ECB, CBC, CFB,
+ OFB and CTR encryption,  The code provides support for the VIA Advanced
+ Cryptography Engine (ACE).
+
+ NOTE: In the following subroutines, the AES contexts (ctx) must be
+ 16 byte aligned if VIA ACE is being used
+*/
+
+#include <string.h>
+#include <assert.h>
+
+#include "aesopt.h"
+
+#if defined( AES_MODES )
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+#if defined( _MSC_VER ) && ( _MSC_VER > 800 )
+#pragma intrinsic(memcpy)
+#endif
+
+#define BFR_BLOCKS      8
+
+/* These values are used to detect long word alignment in order to */
+/* speed up some buffer operations. This facility may not work on  */
+/* some machines so this define can be commented out if necessary  */
+
+#define FAST_BUFFER_OPERATIONS
+
+#define lp32(x)         ((uint_32t*)(x))
+
+#if defined( USE_VIA_ACE_IF_PRESENT )
+
+#include "aes_via_ace.h"
+
+#pragma pack(16)
+
+aligned_array(unsigned long,    enc_gen_table, 12, 16) =    NEH_ENC_GEN_DATA;
+aligned_array(unsigned long,   enc_load_table, 12, 16) =   NEH_ENC_LOAD_DATA;
+aligned_array(unsigned long, enc_hybrid_table, 12, 16) = NEH_ENC_HYBRID_DATA;
+aligned_array(unsigned long,    dec_gen_table, 12, 16) =    NEH_DEC_GEN_DATA;
+aligned_array(unsigned long,   dec_load_table, 12, 16) =   NEH_DEC_LOAD_DATA;
+aligned_array(unsigned long, dec_hybrid_table, 12, 16) = NEH_DEC_HYBRID_DATA;
+
+/* NOTE: These control word macros must only be used after  */
+/* a key has been set up because they depend on key size    */
+
+#if NEH_KEY_TYPE == NEH_LOAD
+#define kd_adr(c)   ((uint_8t*)(c)->ks)
+#elif NEH_KEY_TYPE == NEH_GENERATE
+#define kd_adr(c)   ((uint_8t*)(c)->ks + (c)->inf.b[0])
+#else
+#define kd_adr(c)   ((uint_8t*)(c)->ks + ((c)->inf.b[0] == 160 ? 160 : 0))
+#endif
+
+#else
+
+#define aligned_array(type, name, no, stride) type name[no]
+#define aligned_auto(type, name, no, stride)  type name[no]
+
+#endif
+
+#if defined( _MSC_VER ) && _MSC_VER > 1200
+
+#define via_cwd(cwd, ty, dir, len) \
+    unsigned long* cwd = (dir##_##ty##_table + ((len - 128) >> 4))
+
+#else
+
+#define via_cwd(cwd, ty, dir, len)              \
+    aligned_auto(unsigned long, cwd, 4, 16);    \
+    cwd[1] = cwd[2] = cwd[3] = 0;               \
+    cwd[0] = neh_##dir##_##ty##_key(len)
+
+#endif
+
+/* test the code for detecting and setting pointer alignment */
+
+AES_RETURN aes_test_alignment_detection(unsigned int n)	/* 4 <= n <= 16 */
+{	uint_8t	p[16];
+	uint_32t i, count_eq = 0, count_neq = 0;
+
+	if(n < 4 || n > 16)
+		return EXIT_FAILURE;
+
+	for(i = 0; i < n; ++i)
+	{
+		uint_8t *qf = ALIGN_FLOOR(p + i, n),
+				*qh =  ALIGN_CEIL(p + i, n);
+		
+		if(qh == qf)
+			++count_eq;
+		else if(qh == qf + n)
+			++count_neq;
+		else
+			return EXIT_FAILURE;
+	}
+	return (count_eq != 1 || count_neq != n - 1 ? EXIT_FAILURE : EXIT_SUCCESS);
+}
+
+AES_RETURN aes_mode_reset(aes_encrypt_ctx ctx[1])
+{
+    ctx->inf.b[2] = 0;
+    return EXIT_SUCCESS;
+}
+
+AES_RETURN aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, const aes_encrypt_ctx ctx[1])
+{   int nb = len >> 4;
+
+    if(len & (AES_BLOCK_SIZE - 1))
+        return EXIT_FAILURE;
+
+#if defined( USE_VIA_ACE_IF_PRESENT )
+
+    if(ctx->inf.b[1] == 0xff)
+    {   uint_8t *ksp = (uint_8t*)(ctx->ks);
+        via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);
+
+        if(ALIGN_OFFSET( ctx, 16 ))
+            return EXIT_FAILURE;
+
+        if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ))
+        {
+            via_ecb_op5(ksp, cwd, ibuf, obuf, nb);
+        }
+        else
+        {   aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
+            uint_8t *ip, *op;
+
+            while(nb)
+            {
+                int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb);
+
+                ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);
+                op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);
+
+                if(ip != ibuf)
+                    memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
+
+                via_ecb_op5(ksp, cwd, ip, op, m);
+
+                if(op != obuf)
+                    memcpy(obuf, buf, m * AES_BLOCK_SIZE);
+
+                ibuf += m * AES_BLOCK_SIZE;
+                obuf += m * AES_BLOCK_SIZE;
+                nb -= m;
+            }
+        }
+
+        return EXIT_SUCCESS;
+    }
+
+#endif
+
+#if !defined( ASSUME_VIA_ACE_PRESENT )
+    while(nb--)
+    {
+        if(aes_encrypt(ibuf, obuf, ctx) != EXIT_SUCCESS)
+			return EXIT_FAILURE;
+        ibuf += AES_BLOCK_SIZE;
+        obuf += AES_BLOCK_SIZE;
+    }
+#endif
+    return EXIT_SUCCESS;
+}
+
+AES_RETURN aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, const aes_decrypt_ctx ctx[1])
+{   int nb = len >> 4;
+
+    if(len & (AES_BLOCK_SIZE - 1))
+        return EXIT_FAILURE;
+
+#if defined( USE_VIA_ACE_IF_PRESENT )
+
+    if(ctx->inf.b[1] == 0xff)
+    {   uint_8t *ksp = kd_adr(ctx);
+        via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192);
+
+        if(ALIGN_OFFSET( ctx, 16 ))
+            return EXIT_FAILURE;
+
+        if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ))
+        {
+            via_ecb_op5(ksp, cwd, ibuf, obuf, nb);
+        }
+        else
+        {   aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
+            uint_8t *ip, *op;
+
+            while(nb)
+            {
+                int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb);
+
+                ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);
+                op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);
+
+                if(ip != ibuf)
+                    memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
+
+                via_ecb_op5(ksp, cwd, ip, op, m);
+
+                if(op != obuf)
+                    memcpy(obuf, buf, m * AES_BLOCK_SIZE);
+
+                ibuf += m * AES_BLOCK_SIZE;
+                obuf += m * AES_BLOCK_SIZE;
+                nb -= m;
+            }
+        }
+
+        return EXIT_SUCCESS;
+    }
+
+#endif
+
+#if !defined( ASSUME_VIA_ACE_PRESENT )
+    while(nb--)
+    {
+        if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS)
+			return EXIT_FAILURE;
+        ibuf += AES_BLOCK_SIZE;
+        obuf += AES_BLOCK_SIZE;
+    }
+#endif
+    return EXIT_SUCCESS;
+}
+
+AES_RETURN aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, unsigned char *iv, const aes_encrypt_ctx ctx[1])
+{   int nb = len >> 4;
+
+    if(len & (AES_BLOCK_SIZE - 1))
+        return EXIT_FAILURE;
+
+#if defined( USE_VIA_ACE_IF_PRESENT )
+
+    if(ctx->inf.b[1] == 0xff)
+    {   uint_8t *ksp = (uint_8t*)(ctx->ks), *ivp = iv;
+        aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16);
+        via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);
+
+        if(ALIGN_OFFSET( ctx, 16 ))
+            return EXIT_FAILURE;
+
+        if(ALIGN_OFFSET( iv, 16 ))   /* ensure an aligned iv */
+        {
+            ivp = liv;
+            memcpy(liv, iv, AES_BLOCK_SIZE);
+        }
+
+        if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ) && !ALIGN_OFFSET( iv, 16 ))
+        {
+            via_cbc_op7(ksp, cwd, ibuf, obuf, nb, ivp, ivp);
+        }
+        else
+        {   aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
+            uint_8t *ip, *op;
+
+            while(nb)
+            {
+                int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb);
+
+                ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);
+                op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);
+
+                if(ip != ibuf)
+                    memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
+
+                via_cbc_op7(ksp, cwd, ip, op, m, ivp, ivp);
+
+                if(op != obuf)
+                    memcpy(obuf, buf, m * AES_BLOCK_SIZE);
+
+                ibuf += m * AES_BLOCK_SIZE;
+                obuf += m * AES_BLOCK_SIZE;
+                nb -= m;
+            }
+        }
+
+        if(iv != ivp)
+            memcpy(iv, ivp, AES_BLOCK_SIZE);
+
+        return EXIT_SUCCESS;
+    }
+
+#endif
+
+#if !defined( ASSUME_VIA_ACE_PRESENT )
+# ifdef FAST_BUFFER_OPERATIONS
+    if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( iv, 4 ))
+        while(nb--)
+        {
+            lp32(iv)[0] ^= lp32(ibuf)[0];
+            lp32(iv)[1] ^= lp32(ibuf)[1];
+            lp32(iv)[2] ^= lp32(ibuf)[2];
+            lp32(iv)[3] ^= lp32(ibuf)[3];
+            if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
+				return EXIT_FAILURE;
+            memcpy(obuf, iv, AES_BLOCK_SIZE);
+            ibuf += AES_BLOCK_SIZE;
+            obuf += AES_BLOCK_SIZE;
+        }
+    else
+# endif
+        while(nb--)
+        {
+            iv[ 0] ^= ibuf[ 0]; iv[ 1] ^= ibuf[ 1];
+            iv[ 2] ^= ibuf[ 2]; iv[ 3] ^= ibuf[ 3];
+            iv[ 4] ^= ibuf[ 4]; iv[ 5] ^= ibuf[ 5];
+            iv[ 6] ^= ibuf[ 6]; iv[ 7] ^= ibuf[ 7];
+            iv[ 8] ^= ibuf[ 8]; iv[ 9] ^= ibuf[ 9];
+            iv[10] ^= ibuf[10]; iv[11] ^= ibuf[11];
+            iv[12] ^= ibuf[12]; iv[13] ^= ibuf[13];
+            iv[14] ^= ibuf[14]; iv[15] ^= ibuf[15];
+            if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
+				return EXIT_FAILURE;
+            memcpy(obuf, iv, AES_BLOCK_SIZE);
+            ibuf += AES_BLOCK_SIZE;
+            obuf += AES_BLOCK_SIZE;
+        }
+#endif
+    return EXIT_SUCCESS;
+}
+
+AES_RETURN aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, unsigned char *iv, const aes_decrypt_ctx ctx[1])
+{   unsigned char tmp[AES_BLOCK_SIZE];
+    int nb = len >> 4;
+
+    if(len & (AES_BLOCK_SIZE - 1))
+        return EXIT_FAILURE;
+
+#if defined( USE_VIA_ACE_IF_PRESENT )
+
+    if(ctx->inf.b[1] == 0xff)
+    {   uint_8t *ksp = kd_adr(ctx), *ivp = iv;
+        aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16);
+        via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192);
+
+        if(ALIGN_OFFSET( ctx, 16 ))
+            return EXIT_FAILURE;
+
+        if(ALIGN_OFFSET( iv, 16 ))   /* ensure an aligned iv */
+        {
+            ivp = liv;
+            memcpy(liv, iv, AES_BLOCK_SIZE);
+        }
+
+        if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ) && !ALIGN_OFFSET( iv, 16 ))
+        {
+            via_cbc_op6(ksp, cwd, ibuf, obuf, nb, ivp);
+        }
+        else
+        {   aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
+            uint_8t *ip, *op;
+
+            while(nb)
+            {
+                int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb);
+
+                ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);
+                op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);
+
+                if(ip != ibuf)
+                    memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
+
+                via_cbc_op6(ksp, cwd, ip, op, m, ivp);
+
+                if(op != obuf)
+                    memcpy(obuf, buf, m * AES_BLOCK_SIZE);
+
+                ibuf += m * AES_BLOCK_SIZE;
+                obuf += m * AES_BLOCK_SIZE;
+                nb -= m;
+            }
+        }
+
+        if(iv != ivp)
+            memcpy(iv, ivp, AES_BLOCK_SIZE);
+
+        return EXIT_SUCCESS;
+    }
+#endif
+
+#if !defined( ASSUME_VIA_ACE_PRESENT )
+# ifdef FAST_BUFFER_OPERATIONS
+    if(!ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 ))
+        while(nb--)
+        {
+            memcpy(tmp, ibuf, AES_BLOCK_SIZE);
+            if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS)
+				return EXIT_FAILURE;
+            lp32(obuf)[0] ^= lp32(iv)[0];
+            lp32(obuf)[1] ^= lp32(iv)[1];
+            lp32(obuf)[2] ^= lp32(iv)[2];
+            lp32(obuf)[3] ^= lp32(iv)[3];
+            memcpy(iv, tmp, AES_BLOCK_SIZE);
+            ibuf += AES_BLOCK_SIZE;
+            obuf += AES_BLOCK_SIZE;
+        }
+    else
+# endif
+        while(nb--)
+        {
+            memcpy(tmp, ibuf, AES_BLOCK_SIZE);
+            if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS)
+				return EXIT_FAILURE;
+            obuf[ 0] ^= iv[ 0]; obuf[ 1] ^= iv[ 1];
+            obuf[ 2] ^= iv[ 2]; obuf[ 3] ^= iv[ 3];
+            obuf[ 4] ^= iv[ 4]; obuf[ 5] ^= iv[ 5];
+            obuf[ 6] ^= iv[ 6]; obuf[ 7] ^= iv[ 7];
+            obuf[ 8] ^= iv[ 8]; obuf[ 9] ^= iv[ 9];
+            obuf[10] ^= iv[10]; obuf[11] ^= iv[11];
+            obuf[12] ^= iv[12]; obuf[13] ^= iv[13];
+            obuf[14] ^= iv[14]; obuf[15] ^= iv[15];
+            memcpy(iv, tmp, AES_BLOCK_SIZE);
+            ibuf += AES_BLOCK_SIZE;
+            obuf += AES_BLOCK_SIZE;
+        }
+#endif
+    return EXIT_SUCCESS;
+}
+
+AES_RETURN aes_cfb_encrypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, unsigned char *iv, aes_encrypt_ctx ctx[1])
+{   int cnt = 0, b_pos = (int)ctx->inf.b[2], nb;
+
+    if(b_pos)           /* complete any partial block   */
+    {
+        while(b_pos < AES_BLOCK_SIZE && cnt < len)
+        {
+            *obuf++ = (iv[b_pos++] ^= *ibuf++);
+            cnt++;
+        }
+
+        b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
+    }
+
+    if((nb = (len - cnt) >> 4) != 0)    /* process whole blocks */
+    {
+#if defined( USE_VIA_ACE_IF_PRESENT )
+
+        if(ctx->inf.b[1] == 0xff)
+        {   int m;
+            uint_8t *ksp = (uint_8t*)(ctx->ks), *ivp = iv;
+            aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16);
+            via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);
+
+            if(ALIGN_OFFSET( ctx, 16 ))
+                return EXIT_FAILURE;
+
+            if(ALIGN_OFFSET( iv, 16 ))   /* ensure an aligned iv */
+            {
+                ivp = liv;
+                memcpy(liv, iv, AES_BLOCK_SIZE);
+            }
+
+            if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ))
+            {
+                via_cfb_op7(ksp, cwd, ibuf, obuf, nb, ivp, ivp);
+                ibuf += nb * AES_BLOCK_SIZE;
+                obuf += nb * AES_BLOCK_SIZE;
+                cnt  += nb * AES_BLOCK_SIZE;
+            }
+            else    /* input, output or both are unaligned  */
+            {   aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
+                uint_8t *ip, *op;
+
+                while(nb)
+                {
+                    m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m;
+
+                    ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);
+                    op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);
+
+                    if(ip != ibuf)
+                        memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
+
+                    via_cfb_op7(ksp, cwd, ip, op, m, ivp, ivp);
+
+                    if(op != obuf)
+                        memcpy(obuf, buf, m * AES_BLOCK_SIZE);
+
+                    ibuf += m * AES_BLOCK_SIZE;
+                    obuf += m * AES_BLOCK_SIZE;
+                    cnt  += m * AES_BLOCK_SIZE;
+                }
+            }
+
+            if(ivp != iv)
+                memcpy(iv, ivp, AES_BLOCK_SIZE);
+        }
+#else
+# ifdef FAST_BUFFER_OPERATIONS
+        if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 ))
+            while(cnt + AES_BLOCK_SIZE <= len)
+            {
+                assert(b_pos == 0);
+                if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
+					return EXIT_FAILURE;
+                lp32(obuf)[0] = lp32(iv)[0] ^= lp32(ibuf)[0];
+                lp32(obuf)[1] = lp32(iv)[1] ^= lp32(ibuf)[1];
+                lp32(obuf)[2] = lp32(iv)[2] ^= lp32(ibuf)[2];
+                lp32(obuf)[3] = lp32(iv)[3] ^= lp32(ibuf)[3];
+                ibuf += AES_BLOCK_SIZE;
+                obuf += AES_BLOCK_SIZE;
+                cnt  += AES_BLOCK_SIZE;
+            }
+        else
+# endif
+            while(cnt + AES_BLOCK_SIZE <= len)
+            {
+                assert(b_pos == 0);
+                if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
+					return EXIT_FAILURE;
+                obuf[ 0] = iv[ 0] ^= ibuf[ 0]; obuf[ 1] = iv[ 1] ^= ibuf[ 1];
+                obuf[ 2] = iv[ 2] ^= ibuf[ 2]; obuf[ 3] = iv[ 3] ^= ibuf[ 3];
+                obuf[ 4] = iv[ 4] ^= ibuf[ 4]; obuf[ 5] = iv[ 5] ^= ibuf[ 5];
+                obuf[ 6] = iv[ 6] ^= ibuf[ 6]; obuf[ 7] = iv[ 7] ^= ibuf[ 7];
+                obuf[ 8] = iv[ 8] ^= ibuf[ 8]; obuf[ 9] = iv[ 9] ^= ibuf[ 9];
+                obuf[10] = iv[10] ^= ibuf[10]; obuf[11] = iv[11] ^= ibuf[11];
+                obuf[12] = iv[12] ^= ibuf[12]; obuf[13] = iv[13] ^= ibuf[13];
+                obuf[14] = iv[14] ^= ibuf[14]; obuf[15] = iv[15] ^= ibuf[15];
+                ibuf += AES_BLOCK_SIZE;
+                obuf += AES_BLOCK_SIZE;
+                cnt  += AES_BLOCK_SIZE;
+            }
+#endif
+    }
+
+    while(cnt < len)
+    {
+        if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
+			return EXIT_FAILURE;
+
+        while(cnt < len && b_pos < AES_BLOCK_SIZE)
+        {
+            *obuf++ = (iv[b_pos++] ^= *ibuf++);
+            cnt++;
+        }
+
+        b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
+    }
+
+    ctx->inf.b[2] = (uint_8t)b_pos;
+    return EXIT_SUCCESS;
+}
+
+AES_RETURN aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, unsigned char *iv, aes_encrypt_ctx ctx[1])
+{   int cnt = 0, b_pos = (int)ctx->inf.b[2], nb;
+
+    if(b_pos)           /* complete any partial block   */
+    {   uint_8t t;
+
+        while(b_pos < AES_BLOCK_SIZE && cnt < len)
+        {
+            t = *ibuf++;
+            *obuf++ = t ^ iv[b_pos];
+            iv[b_pos++] = t;
+            cnt++;
+        }
+
+        b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
+    }
+
+    if((nb = (len - cnt) >> 4) != 0)    /* process whole blocks */
+    {
+#if defined( USE_VIA_ACE_IF_PRESENT )
+
+        if(ctx->inf.b[1] == 0xff)
+        {   int m;
+            uint_8t *ksp = (uint_8t*)(ctx->ks), *ivp = iv;
+            aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16);
+            via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192);
+
+            if(ALIGN_OFFSET( ctx, 16 ))
+                return EXIT_FAILURE;
+
+            if(ALIGN_OFFSET( iv, 16 ))   /* ensure an aligned iv */
+            {
+                ivp = liv;
+                memcpy(liv, iv, AES_BLOCK_SIZE);
+            }
+
+            if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ))
+            {
+                via_cfb_op6(ksp, cwd, ibuf, obuf, nb, ivp);
+                ibuf += nb * AES_BLOCK_SIZE;
+                obuf += nb * AES_BLOCK_SIZE;
+                cnt  += nb * AES_BLOCK_SIZE;
+            }
+            else    /* input, output or both are unaligned  */
+            {   aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
+                uint_8t *ip, *op;
+
+                while(nb)
+                {
+                    m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m;
+
+                    ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);
+                    op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);
+
+                    if(ip != ibuf)  /* input buffer is not aligned */
+                        memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
+
+                    via_cfb_op6(ksp, cwd, ip, op, m, ivp);
+
+                    if(op != obuf)  /* output buffer is not aligned */
+                        memcpy(obuf, buf, m * AES_BLOCK_SIZE);
+
+                    ibuf += m * AES_BLOCK_SIZE;
+                    obuf += m * AES_BLOCK_SIZE;
+                    cnt  += m * AES_BLOCK_SIZE;
+                }
+            }
+
+            if(ivp != iv)
+                memcpy(iv, ivp, AES_BLOCK_SIZE);
+        }
+#else
+# ifdef FAST_BUFFER_OPERATIONS
+        if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) &&!ALIGN_OFFSET( iv, 4 ))
+            while(cnt + AES_BLOCK_SIZE <= len)
+            {   uint_32t t;
+
+                assert(b_pos == 0);
+                if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
+					return EXIT_FAILURE;
+                t = lp32(ibuf)[0], lp32(obuf)[0] = t ^ lp32(iv)[0], lp32(iv)[0] = t;
+                t = lp32(ibuf)[1], lp32(obuf)[1] = t ^ lp32(iv)[1], lp32(iv)[1] = t;
+                t = lp32(ibuf)[2], lp32(obuf)[2] = t ^ lp32(iv)[2], lp32(iv)[2] = t;
+                t = lp32(ibuf)[3], lp32(obuf)[3] = t ^ lp32(iv)[3], lp32(iv)[3] = t;
+                ibuf += AES_BLOCK_SIZE;
+                obuf += AES_BLOCK_SIZE;
+                cnt  += AES_BLOCK_SIZE;
+            }
+        else
+# endif
+            while(cnt + AES_BLOCK_SIZE <= len)
+            {   uint_8t t;
+
+                assert(b_pos == 0);
+                if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
+					return EXIT_FAILURE;
+                t = ibuf[ 0], obuf[ 0] = t ^ iv[ 0], iv[ 0] = t;
+                t = ibuf[ 1], obuf[ 1] = t ^ iv[ 1], iv[ 1] = t;
+                t = ibuf[ 2], obuf[ 2] = t ^ iv[ 2], iv[ 2] = t;
+                t = ibuf[ 3], obuf[ 3] = t ^ iv[ 3], iv[ 3] = t;
+                t = ibuf[ 4], obuf[ 4] = t ^ iv[ 4], iv[ 4] = t;
+                t = ibuf[ 5], obuf[ 5] = t ^ iv[ 5], iv[ 5] = t;
+                t = ibuf[ 6], obuf[ 6] = t ^ iv[ 6], iv[ 6] = t;
+                t = ibuf[ 7], obuf[ 7] = t ^ iv[ 7], iv[ 7] = t;
+                t = ibuf[ 8], obuf[ 8] = t ^ iv[ 8], iv[ 8] = t;
+                t = ibuf[ 9], obuf[ 9] = t ^ iv[ 9], iv[ 9] = t;
+                t = ibuf[10], obuf[10] = t ^ iv[10], iv[10] = t;
+                t = ibuf[11], obuf[11] = t ^ iv[11], iv[11] = t;
+                t = ibuf[12], obuf[12] = t ^ iv[12], iv[12] = t;
+                t = ibuf[13], obuf[13] = t ^ iv[13], iv[13] = t;
+                t = ibuf[14], obuf[14] = t ^ iv[14], iv[14] = t;
+                t = ibuf[15], obuf[15] = t ^ iv[15], iv[15] = t;
+                ibuf += AES_BLOCK_SIZE;
+                obuf += AES_BLOCK_SIZE;
+                cnt  += AES_BLOCK_SIZE;
+            }
+#endif
+    }
+
+    while(cnt < len)
+    {   uint_8t t;
+
+        if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
+			return EXIT_FAILURE;
+
+        while(cnt < len && b_pos < AES_BLOCK_SIZE)
+        {
+            t = *ibuf++;
+            *obuf++ = t ^ iv[b_pos];
+            iv[b_pos++] = t;
+            cnt++;
+        }
+
+        b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
+    }
+
+    ctx->inf.b[2] = (uint_8t)b_pos;
+    return EXIT_SUCCESS;
+}
+
+AES_RETURN aes_ofb_crypt(const unsigned char *ibuf, unsigned char *obuf,
+                    int len, unsigned char *iv, aes_encrypt_ctx ctx[1])
+{   int cnt = 0, b_pos = (int)ctx->inf.b[2], nb;
+
+    if(b_pos)           /* complete any partial block   */
+    {
+        while(b_pos < AES_BLOCK_SIZE && cnt < len)
+        {
+            *obuf++ = iv[b_pos++] ^ *ibuf++;
+            cnt++;
+        }
+
+        b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
+    }
+
+    if((nb = (len - cnt) >> 4) != 0)   /* process whole blocks */
+    {
+#if defined( USE_VIA_ACE_IF_PRESENT )
+
+        if(ctx->inf.b[1] == 0xff)
+        {   int m;
+            uint_8t *ksp = (uint_8t*)(ctx->ks), *ivp = iv;
+            aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16);
+            via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);
+
+            if(ALIGN_OFFSET( ctx, 16 ))
+                return EXIT_FAILURE;
+
+            if(ALIGN_OFFSET( iv, 16 ))   /* ensure an aligned iv */
+            {
+                ivp = liv;
+                memcpy(liv, iv, AES_BLOCK_SIZE);
+            }
+
+            if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ))
+            {
+                via_ofb_op6(ksp, cwd, ibuf, obuf, nb, ivp);
+                ibuf += nb * AES_BLOCK_SIZE;
+                obuf += nb * AES_BLOCK_SIZE;
+                cnt  += nb * AES_BLOCK_SIZE;
+            }
+            else    /* input, output or both are unaligned  */
+        {   aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
+            uint_8t *ip, *op;
+
+                while(nb)
+                {
+                    m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m;
+
+                    ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);
+                    op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);
+
+                    if(ip != ibuf)
+                        memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
+
+                    via_ofb_op6(ksp, cwd, ip, op, m, ivp);
+
+                    if(op != obuf)
+                        memcpy(obuf, buf, m * AES_BLOCK_SIZE);
+
+                    ibuf += m * AES_BLOCK_SIZE;
+                    obuf += m * AES_BLOCK_SIZE;
+                    cnt  += m * AES_BLOCK_SIZE;
+                }
+            }
+
+            if(ivp != iv)
+                memcpy(iv, ivp, AES_BLOCK_SIZE);
+        }
+#else
+# ifdef FAST_BUFFER_OPERATIONS
+        if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 ))
+            while(cnt + AES_BLOCK_SIZE <= len)
+            {
+                assert(b_pos == 0);
+                if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
+					return EXIT_FAILURE;
+                lp32(obuf)[0] = lp32(iv)[0] ^ lp32(ibuf)[0];
+                lp32(obuf)[1] = lp32(iv)[1] ^ lp32(ibuf)[1];
+                lp32(obuf)[2] = lp32(iv)[2] ^ lp32(ibuf)[2];
+                lp32(obuf)[3] = lp32(iv)[3] ^ lp32(ibuf)[3];
+                ibuf += AES_BLOCK_SIZE;
+                obuf += AES_BLOCK_SIZE;
+                cnt  += AES_BLOCK_SIZE;
+            }
+        else
+# endif
+            while(cnt + AES_BLOCK_SIZE <= len)
+            {
+                assert(b_pos == 0);
+                if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
+					return EXIT_FAILURE;
+                obuf[ 0] = iv[ 0] ^ ibuf[ 0]; obuf[ 1] = iv[ 1] ^ ibuf[ 1];
+                obuf[ 2] = iv[ 2] ^ ibuf[ 2]; obuf[ 3] = iv[ 3] ^ ibuf[ 3];
+                obuf[ 4] = iv[ 4] ^ ibuf[ 4]; obuf[ 5] = iv[ 5] ^ ibuf[ 5];
+                obuf[ 6] = iv[ 6] ^ ibuf[ 6]; obuf[ 7] = iv[ 7] ^ ibuf[ 7];
+                obuf[ 8] = iv[ 8] ^ ibuf[ 8]; obuf[ 9] = iv[ 9] ^ ibuf[ 9];
+                obuf[10] = iv[10] ^ ibuf[10]; obuf[11] = iv[11] ^ ibuf[11];
+                obuf[12] = iv[12] ^ ibuf[12]; obuf[13] = iv[13] ^ ibuf[13];
+                obuf[14] = iv[14] ^ ibuf[14]; obuf[15] = iv[15] ^ ibuf[15];
+                ibuf += AES_BLOCK_SIZE;
+                obuf += AES_BLOCK_SIZE;
+                cnt  += AES_BLOCK_SIZE;
+            }
+#endif
+    }
+
+    while(cnt < len)
+    {
+        if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
+			return EXIT_FAILURE;
+
+        while(cnt < len && b_pos < AES_BLOCK_SIZE)
+        {
+            *obuf++ = iv[b_pos++] ^ *ibuf++;
+            cnt++;
+        }
+
+        b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
+    }
+
+    ctx->inf.b[2] = (uint_8t)b_pos;
+    return EXIT_SUCCESS;
+}
+
+#define BFR_LENGTH  (BFR_BLOCKS * AES_BLOCK_SIZE)
+
+AES_RETURN aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf,
+            int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx ctx[1])
+{   unsigned char   *ip;
+    int             i, blen, b_pos = (int)(ctx->inf.b[2]);
+
+#if defined( USE_VIA_ACE_IF_PRESENT )
+    aligned_auto(uint_8t, buf, BFR_LENGTH, 16);
+    if(ctx->inf.b[1] == 0xff && ALIGN_OFFSET( ctx, 16 ))
+        return EXIT_FAILURE;
+#else
+    uint_8t buf[BFR_LENGTH];
+#endif
+
+    if(b_pos)
+    {
+        memcpy(buf, cbuf, AES_BLOCK_SIZE);
+        if(aes_ecb_encrypt(buf, buf, AES_BLOCK_SIZE, ctx) != EXIT_SUCCESS)
+			return EXIT_FAILURE;
+
+        while(b_pos < AES_BLOCK_SIZE && len)
+        {
+            *obuf++ = *ibuf++ ^ buf[b_pos++];
+            --len;
+        }
+
+        if(len)
+            ctr_inc(cbuf), b_pos = 0;
+    }
+
+    while(len)
+    {
+        blen = (len > BFR_LENGTH ? BFR_LENGTH : len), len -= blen;
+
+        for(i = 0, ip = buf; i < (blen >> 4); ++i)
+        {
+            memcpy(ip, cbuf, AES_BLOCK_SIZE);
+            ctr_inc(cbuf);
+            ip += AES_BLOCK_SIZE;
+        }
+
+        if(blen & (AES_BLOCK_SIZE - 1))
+            memcpy(ip, cbuf, AES_BLOCK_SIZE), i++;
+
+#if defined( USE_VIA_ACE_IF_PRESENT )
+        if(ctx->inf.b[1] == 0xff)
+        {
+            via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);
+            via_ecb_op5((ctx->ks), cwd, buf, buf, i);
+        }
+        else
+#endif
+        if(aes_ecb_encrypt(buf, buf, i * AES_BLOCK_SIZE, ctx) != EXIT_SUCCESS)
+			return EXIT_FAILURE;
+
+        i = 0; ip = buf;
+# ifdef FAST_BUFFER_OPERATIONS
+        if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( ip, 4 ))
+            while(i + AES_BLOCK_SIZE <= blen)
+            {
+                lp32(obuf)[0] = lp32(ibuf)[0] ^ lp32(ip)[0];
+                lp32(obuf)[1] = lp32(ibuf)[1] ^ lp32(ip)[1];
+                lp32(obuf)[2] = lp32(ibuf)[2] ^ lp32(ip)[2];
+                lp32(obuf)[3] = lp32(ibuf)[3] ^ lp32(ip)[3];
+                i += AES_BLOCK_SIZE;
+                ip += AES_BLOCK_SIZE;
+                ibuf += AES_BLOCK_SIZE;
+                obuf += AES_BLOCK_SIZE;
+            }
+        else
+#endif
+            while(i + AES_BLOCK_SIZE <= blen)
+            {
+                obuf[ 0] = ibuf[ 0] ^ ip[ 0]; obuf[ 1] = ibuf[ 1] ^ ip[ 1];
+                obuf[ 2] = ibuf[ 2] ^ ip[ 2]; obuf[ 3] = ibuf[ 3] ^ ip[ 3];
+                obuf[ 4] = ibuf[ 4] ^ ip[ 4]; obuf[ 5] = ibuf[ 5] ^ ip[ 5];
+                obuf[ 6] = ibuf[ 6] ^ ip[ 6]; obuf[ 7] = ibuf[ 7] ^ ip[ 7];
+                obuf[ 8] = ibuf[ 8] ^ ip[ 8]; obuf[ 9] = ibuf[ 9] ^ ip[ 9];
+                obuf[10] = ibuf[10] ^ ip[10]; obuf[11] = ibuf[11] ^ ip[11];
+                obuf[12] = ibuf[12] ^ ip[12]; obuf[13] = ibuf[13] ^ ip[13];
+                obuf[14] = ibuf[14] ^ ip[14]; obuf[15] = ibuf[15] ^ ip[15];
+                i += AES_BLOCK_SIZE;
+                ip += AES_BLOCK_SIZE;
+                ibuf += AES_BLOCK_SIZE;
+                obuf += AES_BLOCK_SIZE;
+            }
+
+        while(i++ < blen)
+            *obuf++ = *ibuf++ ^ ip[b_pos++];
+    }
+
+    ctx->inf.b[2] = (uint_8t)b_pos;
+    return EXIT_SUCCESS;
+}
+
+#if defined(__cplusplus)
+}
+#endif
+#endif
diff --git a/cbits/gladman/aes_via_ace.h b/cbits/gladman/aes_via_ace.h
new file mode 100644
--- /dev/null
+++ b/cbits/gladman/aes_via_ace.h
@@ -0,0 +1,529 @@
+/*
+ ---------------------------------------------------------------------------
+ Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
+
+ LICENSE TERMS
+
+ The redistribution and use of this software (with or without changes)
+ is allowed without the payment of fees or royalties provided that:
+
+  1. source code distributions include the above copyright notice, this
+     list of conditions and the following disclaimer;
+
+  2. binary distributions include the above copyright notice, this list
+     of conditions and the following disclaimer in their documentation;
+
+  3. the name of the copyright holder is not used to endorse products
+     built using this software without specific written permission.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ ---------------------------------------------------------------------------
+ Issue Date: 20/12/20077
+*/
+
+#ifndef AES_VIA_ACE_H
+#define AES_VIA_ACE_H
+
+#if defined( _MSC_VER )
+#  define INLINE  __inline
+#elif defined( __GNUC__ )
+#  define INLINE  static inline
+#else
+#  error VIA ACE requires Microsoft or GNU C
+#endif
+
+#define NEH_GENERATE    1
+#define NEH_LOAD        2
+#define NEH_HYBRID      3
+
+#define MAX_READ_ATTEMPTS   1000
+
+/* VIA Nehemiah RNG and ACE Feature Mask Values */
+
+#define NEH_CPU_IS_VIA      0x00000001
+#define NEH_CPU_READ        0x00000010
+#define NEH_CPU_MASK        0x00000011
+
+#define NEH_RNG_PRESENT     0x00000004
+#define NEH_RNG_ENABLED     0x00000008
+#define NEH_ACE_PRESENT     0x00000040
+#define NEH_ACE_ENABLED     0x00000080
+#define NEH_RNG_FLAGS       (NEH_RNG_PRESENT | NEH_RNG_ENABLED)
+#define NEH_ACE_FLAGS       (NEH_ACE_PRESENT | NEH_ACE_ENABLED)
+#define NEH_FLAGS_MASK      (NEH_RNG_FLAGS | NEH_ACE_FLAGS)
+
+/* VIA Nehemiah Advanced Cryptography Engine (ACE) Control Word Values  */
+
+#define NEH_GEN_KEY     0x00000000      /* generate key schedule        */
+#define NEH_LOAD_KEY    0x00000080      /* load schedule from memory    */
+#define NEH_ENCRYPT     0x00000000      /* encryption                   */
+#define NEH_DECRYPT     0x00000200      /* decryption                   */
+#define NEH_KEY128      0x00000000+0x0a /* 128 bit key                  */
+#define NEH_KEY192      0x00000400+0x0c /* 192 bit key                  */
+#define NEH_KEY256      0x00000800+0x0e /* 256 bit key                  */
+
+#define NEH_ENC_GEN     (NEH_ENCRYPT | NEH_GEN_KEY)
+#define NEH_DEC_GEN     (NEH_DECRYPT | NEH_GEN_KEY)
+#define NEH_ENC_LOAD    (NEH_ENCRYPT | NEH_LOAD_KEY)
+#define NEH_DEC_LOAD    (NEH_DECRYPT | NEH_LOAD_KEY)
+
+#define NEH_ENC_GEN_DATA {\
+    NEH_ENC_GEN | NEH_KEY128, 0, 0, 0,\
+    NEH_ENC_GEN | NEH_KEY192, 0, 0, 0,\
+    NEH_ENC_GEN | NEH_KEY256, 0, 0, 0 }
+
+#define NEH_ENC_LOAD_DATA {\
+    NEH_ENC_LOAD | NEH_KEY128, 0, 0, 0,\
+    NEH_ENC_LOAD | NEH_KEY192, 0, 0, 0,\
+    NEH_ENC_LOAD | NEH_KEY256, 0, 0, 0 }
+
+#define NEH_ENC_HYBRID_DATA {\
+    NEH_ENC_GEN  | NEH_KEY128, 0, 0, 0,\
+    NEH_ENC_LOAD | NEH_KEY192, 0, 0, 0,\
+    NEH_ENC_LOAD | NEH_KEY256, 0, 0, 0 }
+
+#define NEH_DEC_GEN_DATA {\
+    NEH_DEC_GEN | NEH_KEY128, 0, 0, 0,\
+    NEH_DEC_GEN | NEH_KEY192, 0, 0, 0,\
+    NEH_DEC_GEN | NEH_KEY256, 0, 0, 0 }
+
+#define NEH_DEC_LOAD_DATA {\
+    NEH_DEC_LOAD | NEH_KEY128, 0, 0, 0,\
+    NEH_DEC_LOAD | NEH_KEY192, 0, 0, 0,\
+    NEH_DEC_LOAD | NEH_KEY256, 0, 0, 0 }
+
+#define NEH_DEC_HYBRID_DATA {\
+    NEH_DEC_GEN  | NEH_KEY128, 0, 0, 0,\
+    NEH_DEC_LOAD | NEH_KEY192, 0, 0, 0,\
+    NEH_DEC_LOAD | NEH_KEY256, 0, 0, 0 }
+
+#define neh_enc_gen_key(x)  ((x) == 128 ? (NEH_ENC_GEN | NEH_KEY128) :      \
+     (x) == 192 ? (NEH_ENC_GEN | NEH_KEY192) : (NEH_ENC_GEN | NEH_KEY256))
+
+#define neh_enc_load_key(x) ((x) == 128 ? (NEH_ENC_LOAD | NEH_KEY128) :     \
+     (x) == 192 ? (NEH_ENC_LOAD | NEH_KEY192) : (NEH_ENC_LOAD | NEH_KEY256))
+
+#define neh_enc_hybrid_key(x)   ((x) == 128 ? (NEH_ENC_GEN | NEH_KEY128) :  \
+     (x) == 192 ? (NEH_ENC_LOAD | NEH_KEY192) : (NEH_ENC_LOAD | NEH_KEY256))
+
+#define neh_dec_gen_key(x)  ((x) == 128 ? (NEH_DEC_GEN | NEH_KEY128) :      \
+     (x) == 192 ? (NEH_DEC_GEN | NEH_KEY192) : (NEH_DEC_GEN | NEH_KEY256))
+
+#define neh_dec_load_key(x) ((x) == 128 ? (NEH_DEC_LOAD | NEH_KEY128) :     \
+     (x) == 192 ? (NEH_DEC_LOAD | NEH_KEY192) : (NEH_DEC_LOAD | NEH_KEY256))
+
+#define neh_dec_hybrid_key(x)   ((x) == 128 ? (NEH_DEC_GEN | NEH_KEY128) :  \
+     (x) == 192 ? (NEH_DEC_LOAD | NEH_KEY192) : (NEH_DEC_LOAD | NEH_KEY256))
+
+#if defined( _MSC_VER ) && ( _MSC_VER > 1200 )
+#define aligned_auto(type, name, no, stride)  __declspec(align(stride)) type name[no]
+#else
+#define aligned_auto(type, name, no, stride)                \
+    unsigned char _##name[no * sizeof(type) + stride];      \
+    type *name = (type*)(16 * ((((unsigned long)(_##name)) + stride - 1) / stride))
+#endif
+
+#if defined( _MSC_VER ) && ( _MSC_VER > 1200 )
+#define aligned_array(type, name, no, stride) __declspec(align(stride)) type name[no]
+#elif defined( __GNUC__ )
+#define aligned_array(type, name, no, stride) type name[no] __attribute__ ((aligned(stride)))
+#else
+#define aligned_array(type, name, no, stride) type name[no]
+#endif
+
+/* VIA ACE codeword     */
+
+static unsigned char via_flags = 0;
+
+#if defined ( _MSC_VER ) && ( _MSC_VER > 800 )
+
+#define NEH_REKEY   __asm pushfd __asm popfd
+#define NEH_AES     __asm _emit 0xf3 __asm _emit 0x0f __asm _emit 0xa7
+#define NEH_ECB     NEH_AES __asm _emit 0xc8
+#define NEH_CBC     NEH_AES __asm _emit 0xd0
+#define NEH_CFB     NEH_AES __asm _emit 0xe0
+#define NEH_OFB     NEH_AES __asm _emit 0xe8
+#define NEH_RNG     __asm _emit 0x0f __asm _emit 0xa7 __asm _emit 0xc0
+
+INLINE int has_cpuid(void)
+{   char ret_value;
+    __asm
+    {   pushfd                  /* save EFLAGS register     */
+        mov     eax,[esp]       /* copy it to eax           */
+        mov     edx,0x00200000  /* CPUID bit position       */
+        xor     eax,edx         /* toggle the CPUID bit     */
+        push    eax             /* attempt to set EFLAGS to */
+        popfd                   /*     the new value        */
+        pushfd                  /* get the new EFLAGS value */
+        pop     eax             /*     into eax             */
+        xor     eax,[esp]       /* xor with original value  */
+        and     eax,edx         /* has CPUID bit changed?   */
+        setne   al              /* set to 1 if we have been */
+        mov     ret_value,al    /*     able to change it    */
+        popfd                   /* restore original EFLAGS  */
+    }
+    return (int)ret_value;
+}
+
+INLINE int is_via_cpu(void)
+{   char ret_value;
+    __asm
+    {   xor     eax,eax         /* use CPUID to get vendor  */
+        cpuid                   /* identity string          */
+        xor     eax,eax         /* is it "CentaurHauls" ?   */
+        sub     ebx,0x746e6543  /* 'Cent'                   */
+        or      eax,ebx
+        sub     edx,0x48727561  /* 'aurH'                   */
+        or      eax,edx
+        sub     ecx,0x736c7561  /* 'auls'                   */
+        or      eax,ecx
+        sete    al              /* set to 1 if it is VIA ID */
+        mov     dl,NEH_CPU_READ /* mark CPU type as read    */
+        or      dl,al           /* & store result in flags  */
+        mov     [via_flags],dl  /* set VIA detected flag    */
+        mov     ret_value,al    /*     able to change it    */
+    }
+    return (int)ret_value;
+}
+
+INLINE int read_via_flags(void)
+{   char ret_value = 0;
+    __asm
+    {
+        mov     eax,0xC0000000  /* Centaur extended CPUID   */
+        cpuid
+        mov     edx,0xc0000001  /* >= 0xc0000001 if support */
+        cmp     eax,edx         /* for VIA extended feature */
+        jnae    no_rng          /*     flags is available   */
+        mov     eax,edx         /* read Centaur extended    */
+        cpuid                   /*     feature flags        */
+        mov     eax,NEH_FLAGS_MASK  /* mask out and save    */
+        and     eax,edx         /*  the RNG and ACE flags   */
+        or      [via_flags],al  /* present & enabled flags  */
+        mov     ret_value,al    /*     able to change it    */
+no_rng:
+    }
+    return (int)ret_value;
+}
+
+INLINE unsigned int via_rng_in(void *buf)
+{   char ret_value = 0x1f;
+    __asm
+    {
+        push    edi
+        mov     edi,buf         /* input buffer address     */
+        xor     edx,edx         /* try to fetch 8 bytes     */
+        NEH_RNG                 /* do RNG read operation    */
+        and     ret_value,al    /* count of bytes returned  */
+        pop     edi
+    }
+    return (int)ret_value;
+}
+
+INLINE void via_ecb_op5(
+            const void *k, const void *c, const void *s, void *d, int l)
+{   __asm
+    {
+        NEH_REKEY
+        mov     ebx, (k)
+        mov     edx, (c)
+        mov     esi, (s)
+        mov     edi, (d)
+        mov     ecx, (l)
+        NEH_ECB
+    }
+}
+
+INLINE void via_cbc_op6(
+            const void *k, const void *c, const void *s, void *d, int l, void *v)
+{   __asm
+    {
+        NEH_REKEY
+        mov     ebx, (k)
+        mov     edx, (c)
+        mov     esi, (s)
+        mov     edi, (d)
+        mov     ecx, (l)
+        mov     eax, (v)
+        NEH_CBC
+    }
+}
+
+INLINE void via_cbc_op7(
+        const void *k, const void *c, const void *s, void *d, int l, void *v, void *w)
+{   __asm
+    {
+        NEH_REKEY
+        mov     ebx, (k)
+        mov     edx, (c)
+        mov     esi, (s)
+        mov     edi, (d)
+        mov     ecx, (l)
+        mov     eax, (v)
+        NEH_CBC
+        mov     esi, eax
+        mov     edi, (w)
+        movsd
+        movsd
+        movsd
+        movsd
+    }
+}
+
+INLINE void via_cfb_op6(
+            const void *k, const void *c, const void *s, void *d, int l, void *v)
+{   __asm
+    {
+        NEH_REKEY
+        mov     ebx, (k)
+        mov     edx, (c)
+        mov     esi, (s)
+        mov     edi, (d)
+        mov     ecx, (l)
+        mov     eax, (v)
+        NEH_CFB
+    }
+}
+
+INLINE void via_cfb_op7(
+        const void *k, const void *c, const void *s, void *d, int l, void *v, void *w)
+{   __asm
+    {
+        NEH_REKEY
+        mov     ebx, (k)
+        mov     edx, (c)
+        mov     esi, (s)
+        mov     edi, (d)
+        mov     ecx, (l)
+        mov     eax, (v)
+        NEH_CFB
+        mov     esi, eax
+        mov     edi, (w)
+        movsd
+        movsd
+        movsd
+        movsd
+    }
+}
+
+INLINE void via_ofb_op6(
+            const void *k, const void *c, const void *s, void *d, int l, void *v)
+{   __asm
+    {
+        NEH_REKEY
+        mov     ebx, (k)
+        mov     edx, (c)
+        mov     esi, (s)
+        mov     edi, (d)
+        mov     ecx, (l)
+        mov     eax, (v)
+        NEH_OFB
+    }
+}
+
+#elif defined( __GNUC__ )
+
+#define NEH_REKEY   asm("pushfl\n popfl\n\t")
+#define NEH_ECB     asm(".byte 0xf3, 0x0f, 0xa7, 0xc8\n\t")
+#define NEH_CBC     asm(".byte 0xf3, 0x0f, 0xa7, 0xd0\n\t")
+#define NEH_CFB     asm(".byte 0xf3, 0x0f, 0xa7, 0xe0\n\t")
+#define NEH_OFB     asm(".byte 0xf3, 0x0f, 0xa7, 0xe8\n\t")
+#define NEH_RNG     asm(".byte 0x0f, 0xa7, 0xc0\n\t");
+
+INLINE int has_cpuid(void)
+{   int val;
+    asm("pushfl\n\t");
+    asm("movl  0(%esp),%eax\n\t");
+    asm("xor   $0x00200000,%eax\n\t");
+    asm("pushl %eax\n\t");
+    asm("popfl\n\t");
+    asm("pushfl\n\t");
+    asm("popl  %eax\n\t");
+    asm("xorl  0(%esp),%edx\n\t");
+    asm("andl  $0x00200000,%eax\n\t");
+    asm("movl  %%eax,%0\n\t" : "=m" (val));
+    asm("popfl\n\t");
+    return val ? 1 : 0;
+}
+
+INLINE int is_via_cpu(void)
+{   int val;
+    asm("xorl %eax,%eax\n\t");
+    asm("cpuid\n\t");
+    asm("xorl %eax,%eax\n\t");
+    asm("subl $0x746e6543,%ebx\n\t");
+    asm("orl  %ebx,%eax\n\t");
+    asm("subl $0x48727561,%edx\n\t");
+    asm("orl  %edx,%eax\n\t");
+    asm("subl $0x736c7561,%ecx\n\t");
+    asm("orl  %ecx,%eax\n\t");
+    asm("movl %%eax,%0\n\t" : "=m" (val));
+    val = (val ? 0 : 1);
+    via_flags = (val | NEH_CPU_READ);
+    return val;
+}
+
+INLINE int read_via_flags(void)
+{   unsigned char   val;
+    asm("movl $0xc0000000,%eax\n\t");
+    asm("cpuid\n\t");
+    asm("movl $0xc0000001,%edx\n\t");
+    asm("cmpl %edx,%eax\n\t");
+    asm("setae %al\n\t");
+    asm("movb %%al,%0\n\t" : "=m" (val));
+    if(!val) return 0;
+    asm("movl $0xc0000001,%eax\n\t");
+    asm("cpuid\n\t");
+    asm("movb %%dl,%0\n\t" : "=m" (val));
+    val &= NEH_FLAGS_MASK;
+    via_flags |= val;
+    return (int) val;
+}
+
+INLINE int via_rng_in(void *buf)
+{   int val;
+    asm("pushl %edi\n\t");
+    asm("movl %0,%%edi\n\t" : : "m" (buf));
+    asm("xorl %edx,%edx\n\t");
+    NEH_RNG
+    asm("andl $0x0000001f,%eax\n\t");
+    asm("movl %%eax,%0\n\t" : "=m" (val));
+    asm("popl %edi\n\t");
+    return val;
+}
+
+INLINE volatile  void via_ecb_op5(
+            const void *k, const void *c, const void *s, void *d, int l)
+{
+    NEH_REKEY;
+    asm("movl %0, %%ebx\n\t" : : "m" (k));
+    asm("movl %0, %%edx\n\t" : : "m" (c));
+    asm("movl %0, %%esi\n\t" : : "m" (s));
+    asm("movl %0, %%edi\n\t" : : "m" (d));
+    asm("movl %0, %%ecx\n\t" : : "m" (l));
+    NEH_ECB;
+}
+
+INLINE volatile  void via_cbc_op6(
+            const void *k, const void *c, const void *s, void *d, int l, void *v)
+{
+    NEH_REKEY;
+    asm("movl %0, %%ebx\n\t" : : "m" (k));
+    asm("movl %0, %%edx\n\t" : : "m" (c));
+    asm("movl %0, %%esi\n\t" : : "m" (s));
+    asm("movl %0, %%edi\n\t" : : "m" (d));
+    asm("movl %0, %%ecx\n\t" : : "m" (l));
+    asm("movl %0, %%eax\n\t" : : "m" (v));
+    NEH_CBC;
+}
+
+INLINE volatile  void via_cbc_op7(
+        const void *k, const void *c, const void *s, void *d, int l, void *v, void *w)
+{
+    NEH_REKEY;
+    asm("movl %0, %%ebx\n\t" : : "m" (k));
+    asm("movl %0, %%edx\n\t" : : "m" (c));
+    asm("movl %0, %%esi\n\t" : : "m" (s));
+    asm("movl %0, %%edi\n\t" : : "m" (d));
+    asm("movl %0, %%ecx\n\t" : : "m" (l));
+    asm("movl %0, %%eax\n\t" : : "m" (v));
+    NEH_CBC;
+    asm("movl %eax,%esi\n\t");
+    asm("movl %0, %%edi\n\t" : : "m" (w));
+    asm("movsl; movsl; movsl; movsl\n\t");
+}
+
+INLINE volatile  void via_cfb_op6(
+            const void *k, const void *c, const void *s, void *d, int l, void *v)
+{
+    NEH_REKEY;
+    asm("movl %0, %%ebx\n\t" : : "m" (k));
+    asm("movl %0, %%edx\n\t" : : "m" (c));
+    asm("movl %0, %%esi\n\t" : : "m" (s));
+    asm("movl %0, %%edi\n\t" : : "m" (d));
+    asm("movl %0, %%ecx\n\t" : : "m" (l));
+    asm("movl %0, %%eax\n\t" : : "m" (v));
+    NEH_CFB;
+}
+
+INLINE volatile  void via_cfb_op7(
+        const void *k, const void *c, const void *s, void *d, int l, void *v, void *w)
+{
+    NEH_REKEY;
+    asm("movl %0, %%ebx\n\t" : : "m" (k));
+    asm("movl %0, %%edx\n\t" : : "m" (c));
+    asm("movl %0, %%esi\n\t" : : "m" (s));
+    asm("movl %0, %%edi\n\t" : : "m" (d));
+    asm("movl %0, %%ecx\n\t" : : "m" (l));
+    asm("movl %0, %%eax\n\t" : : "m" (v));
+    NEH_CFB;
+    asm("movl %eax,%esi\n\t");
+    asm("movl %0, %%edi\n\t" : : "m" (w));
+    asm("movsl; movsl; movsl; movsl\n\t");
+}
+
+INLINE volatile  void via_ofb_op6(
+            const void *k, const void *c, const void *s, void *d, int l, void *v)
+{
+    NEH_REKEY;
+    asm("movl %0, %%ebx\n\t" : : "m" (k));
+    asm("movl %0, %%edx\n\t" : : "m" (c));
+    asm("movl %0, %%esi\n\t" : : "m" (s));
+    asm("movl %0, %%edi\n\t" : : "m" (d));
+    asm("movl %0, %%ecx\n\t" : : "m" (l));
+    asm("movl %0, %%eax\n\t" : : "m" (v));
+    NEH_OFB;
+}
+
+#else
+#error VIA ACE is not available with this compiler
+#endif
+
+INLINE int via_ace_test(void)
+{
+    return has_cpuid() && is_via_cpu() && ((read_via_flags() & NEH_ACE_FLAGS) == NEH_ACE_FLAGS);
+}
+
+#define VIA_ACE_AVAILABLE   (((via_flags & NEH_ACE_FLAGS) == NEH_ACE_FLAGS)         \
+    || (via_flags & NEH_CPU_READ) && (via_flags & NEH_CPU_IS_VIA) || via_ace_test())
+
+INLINE int via_rng_test(void)
+{
+    return has_cpuid() && is_via_cpu() && ((read_via_flags() & NEH_RNG_FLAGS) == NEH_RNG_FLAGS);
+}
+
+#define VIA_RNG_AVAILABLE   (((via_flags & NEH_RNG_FLAGS) == NEH_RNG_FLAGS)         \
+    || (via_flags & NEH_CPU_READ) && (via_flags & NEH_CPU_IS_VIA) || via_rng_test())
+
+INLINE int read_via_rng(void *buf, int count)
+{   int nbr, max_reads, lcnt = count;
+    unsigned char *p, *q;
+    aligned_auto(unsigned char, bp, 64, 16);
+
+    if(!VIA_RNG_AVAILABLE)
+        return 0;
+
+    do
+    {
+        max_reads = MAX_READ_ATTEMPTS;
+        do
+            nbr = via_rng_in(bp);
+        while
+            (nbr == 0 && --max_reads);
+
+        lcnt -= nbr;
+        p = (unsigned char*)buf; q = bp;
+        while(nbr--)
+            *p++ = *q++;
+    }
+    while
+        (lcnt && max_reads);
+
+    return count - lcnt;
+}
+
+#endif
diff --git a/cbits/gladman/aescrypt.c b/cbits/gladman/aescrypt.c
new file mode 100644
--- /dev/null
+++ b/cbits/gladman/aescrypt.c
@@ -0,0 +1,301 @@
+/*
+ ---------------------------------------------------------------------------
+ Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
+
+ LICENSE TERMS
+
+ The redistribution and use of this software (with or without changes)
+ is allowed without the payment of fees or royalties provided that:
+
+  1. source code distributions include the above copyright notice, this
+     list of conditions and the following disclaimer;
+
+  2. binary distributions include the above copyright notice, this list
+     of conditions and the following disclaimer in their documentation;
+
+  3. the name of the copyright holder is not used to endorse products
+     built using this software without specific written permission.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ ---------------------------------------------------------------------------
+ Issue Date: 20/12/2007
+*/
+
+#include "aesopt.h"
+#include "aestab.h"
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+#define si(y,x,k,c) (s(y,c) = word_in(x, c) ^ (k)[c])
+#define so(y,x,c)   word_out(y, c, s(x,c))
+
+#if defined(ARRAYS)
+#define locals(y,x)     x[4],y[4]
+#else
+#define locals(y,x)     x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3
+#endif
+
+#define l_copy(y, x)    s(y,0) = s(x,0); s(y,1) = s(x,1); \
+                        s(y,2) = s(x,2); s(y,3) = s(x,3);
+#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3)
+#define state_out(y,x)  so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3)
+#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3)
+
+#if ( FUNCS_IN_C & ENCRYPTION_IN_C )
+
+/* Visual C++ .Net v7.1 provides the fastest encryption code when using
+   Pentium optimiation with small code but this is poor for decryption
+   so we need to control this with the following VC++ pragmas
+*/
+
+#if defined( _MSC_VER ) && !defined( _WIN64 )
+#pragma optimize( "s", on )
+#endif
+
+/* Given the column (c) of the output state variable, the following
+   macros give the input state variables which are needed in its
+   computation for each row (r) of the state. All the alternative
+   macros give the same end values but expand into different ways
+   of calculating these values.  In particular the complex macro
+   used for dynamically variable block sizes is designed to expand
+   to a compile time constant whenever possible but will expand to
+   conditional clauses on some branches (I am grateful to Frank
+   Yellin for this construction)
+*/
+
+#define fwd_var(x,r,c)\
+ ( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\
+ : r == 1 ? ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))\
+ : r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\
+ :          ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2)))
+
+#if defined(FT4_SET)
+#undef  dec_fmvars
+#define fwd_rnd(y,x,k,c)    (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,n),fwd_var,rf1,c))
+#elif defined(FT1_SET)
+#undef  dec_fmvars
+#define fwd_rnd(y,x,k,c)    (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(f,n),fwd_var,rf1,c))
+#else
+#define fwd_rnd(y,x,k,c)    (s(y,c) = (k)[c] ^ fwd_mcol(no_table(x,t_use(s,box),fwd_var,rf1,c)))
+#endif
+
+#if defined(FL4_SET)
+#define fwd_lrnd(y,x,k,c)   (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,l),fwd_var,rf1,c))
+#elif defined(FL1_SET)
+#define fwd_lrnd(y,x,k,c)   (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(f,l),fwd_var,rf1,c))
+#else
+#define fwd_lrnd(y,x,k,c)   (s(y,c) = (k)[c] ^ no_table(x,t_use(s,box),fwd_var,rf1,c))
+#endif
+
+AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1])
+{   uint_32t         locals(b0, b1);
+    const uint_32t   *kp;
+#if defined( dec_fmvars )
+    dec_fmvars; /* declare variables for fwd_mcol() if needed */
+#endif
+
+    if( cx->inf.b[0] != 10 * 16 && cx->inf.b[0] != 12 * 16 && cx->inf.b[0] != 14 * 16 )
+        return EXIT_FAILURE;
+
+    kp = cx->ks;
+    state_in(b0, in, kp);
+
+#if (ENC_UNROLL == FULL)
+
+    switch(cx->inf.b[0])
+    {
+    case 14 * 16:
+        round(fwd_rnd,  b1, b0, kp + 1 * N_COLS);
+        round(fwd_rnd,  b0, b1, kp + 2 * N_COLS);
+        kp += 2 * N_COLS;
+    case 12 * 16:
+        round(fwd_rnd,  b1, b0, kp + 1 * N_COLS);
+        round(fwd_rnd,  b0, b1, kp + 2 * N_COLS);
+        kp += 2 * N_COLS;
+    case 10 * 16:
+        round(fwd_rnd,  b1, b0, kp + 1 * N_COLS);
+        round(fwd_rnd,  b0, b1, kp + 2 * N_COLS);
+        round(fwd_rnd,  b1, b0, kp + 3 * N_COLS);
+        round(fwd_rnd,  b0, b1, kp + 4 * N_COLS);
+        round(fwd_rnd,  b1, b0, kp + 5 * N_COLS);
+        round(fwd_rnd,  b0, b1, kp + 6 * N_COLS);
+        round(fwd_rnd,  b1, b0, kp + 7 * N_COLS);
+        round(fwd_rnd,  b0, b1, kp + 8 * N_COLS);
+        round(fwd_rnd,  b1, b0, kp + 9 * N_COLS);
+        round(fwd_lrnd, b0, b1, kp +10 * N_COLS);
+    }
+
+#else
+
+#if (ENC_UNROLL == PARTIAL)
+    {   uint_32t    rnd;
+        for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd)
+        {
+            kp += N_COLS;
+            round(fwd_rnd, b1, b0, kp);
+            kp += N_COLS;
+            round(fwd_rnd, b0, b1, kp);
+        }
+        kp += N_COLS;
+        round(fwd_rnd,  b1, b0, kp);
+#else
+    {   uint_32t    rnd;
+        for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd)
+        {
+            kp += N_COLS;
+            round(fwd_rnd, b1, b0, kp);
+            l_copy(b0, b1);
+        }
+#endif
+        kp += N_COLS;
+        round(fwd_lrnd, b0, b1, kp);
+    }
+#endif
+
+    state_out(out, b0);
+    return EXIT_SUCCESS;
+}
+
+#endif
+
+#if ( FUNCS_IN_C & DECRYPTION_IN_C)
+
+/* Visual C++ .Net v7.1 provides the fastest encryption code when using
+   Pentium optimiation with small code but this is poor for decryption
+   so we need to control this with the following VC++ pragmas
+*/
+
+#if defined( _MSC_VER ) && !defined( _WIN64 )
+#pragma optimize( "t", on )
+#endif
+
+/* Given the column (c) of the output state variable, the following
+   macros give the input state variables which are needed in its
+   computation for each row (r) of the state. All the alternative
+   macros give the same end values but expand into different ways
+   of calculating these values.  In particular the complex macro
+   used for dynamically variable block sizes is designed to expand
+   to a compile time constant whenever possible but will expand to
+   conditional clauses on some branches (I am grateful to Frank
+   Yellin for this construction)
+*/
+
+#define inv_var(x,r,c)\
+ ( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\
+ : r == 1 ? ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2))\
+ : r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\
+ :          ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0)))
+
+#if defined(IT4_SET)
+#undef  dec_imvars
+#define inv_rnd(y,x,k,c)    (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,n),inv_var,rf1,c))
+#elif defined(IT1_SET)
+#undef  dec_imvars
+#define inv_rnd(y,x,k,c)    (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(i,n),inv_var,rf1,c))
+#else
+#define inv_rnd(y,x,k,c)    (s(y,c) = inv_mcol((k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c)))
+#endif
+
+#if defined(IL4_SET)
+#define inv_lrnd(y,x,k,c)   (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,l),inv_var,rf1,c))
+#elif defined(IL1_SET)
+#define inv_lrnd(y,x,k,c)   (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(i,l),inv_var,rf1,c))
+#else
+#define inv_lrnd(y,x,k,c)   (s(y,c) = (k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c))
+#endif
+
+/* This code can work with the decryption key schedule in the   */
+/* order that is used for encrytpion (where the 1st decryption  */
+/* round key is at the high end ot the schedule) or with a key  */
+/* schedule that has been reversed to put the 1st decryption    */
+/* round key at the low end of the schedule in memory (when     */
+/* AES_REV_DKS is defined)                                      */
+
+#ifdef AES_REV_DKS
+#define key_ofs     0
+#define rnd_key(n)  (kp + n * N_COLS)
+#else
+#define key_ofs     1
+#define rnd_key(n)  (kp - n * N_COLS)
+#endif
+
+AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1])
+{   uint_32t        locals(b0, b1);
+#if defined( dec_imvars )
+    dec_imvars; /* declare variables for inv_mcol() if needed */
+#endif
+    const uint_32t *kp;
+
+    if( cx->inf.b[0] != 10 * 16 && cx->inf.b[0] != 12 * 16 && cx->inf.b[0] != 14 * 16 )
+        return EXIT_FAILURE;
+
+    kp = cx->ks + (key_ofs ? (cx->inf.b[0] >> 2) : 0);
+    state_in(b0, in, kp);
+
+#if (DEC_UNROLL == FULL)
+
+    kp = cx->ks + (key_ofs ? 0 : (cx->inf.b[0] >> 2));
+    switch(cx->inf.b[0])
+    {
+    case 14 * 16:
+        round(inv_rnd,  b1, b0, rnd_key(-13));
+        round(inv_rnd,  b0, b1, rnd_key(-12));
+    case 12 * 16:
+        round(inv_rnd,  b1, b0, rnd_key(-11));
+        round(inv_rnd,  b0, b1, rnd_key(-10));
+    case 10 * 16:
+        round(inv_rnd,  b1, b0, rnd_key(-9));
+        round(inv_rnd,  b0, b1, rnd_key(-8));
+        round(inv_rnd,  b1, b0, rnd_key(-7));
+        round(inv_rnd,  b0, b1, rnd_key(-6));
+        round(inv_rnd,  b1, b0, rnd_key(-5));
+        round(inv_rnd,  b0, b1, rnd_key(-4));
+        round(inv_rnd,  b1, b0, rnd_key(-3));
+        round(inv_rnd,  b0, b1, rnd_key(-2));
+        round(inv_rnd,  b1, b0, rnd_key(-1));
+        round(inv_lrnd, b0, b1, rnd_key( 0));
+    }
+
+#else
+
+#if (DEC_UNROLL == PARTIAL)
+    {   uint_32t    rnd;
+        for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd)
+        {
+            kp = rnd_key(1);
+            round(inv_rnd, b1, b0, kp);
+            kp = rnd_key(1);
+            round(inv_rnd, b0, b1, kp);
+        }
+        kp = rnd_key(1);
+        round(inv_rnd, b1, b0, kp);
+#else
+    {   uint_32t    rnd;
+        for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd)
+        {
+            kp = rnd_key(1);
+            round(inv_rnd, b1, b0, kp);
+            l_copy(b0, b1);
+        }
+#endif
+        kp = rnd_key(1);
+        round(inv_lrnd, b0, b1, kp);
+        }
+#endif
+
+    state_out(out, b0);
+    return EXIT_SUCCESS;
+}
+
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
diff --git a/cbits/gladman/aeskey.c b/cbits/gladman/aeskey.c
new file mode 100644
--- /dev/null
+++ b/cbits/gladman/aeskey.c
@@ -0,0 +1,555 @@
+/*
+ ---------------------------------------------------------------------------
+ Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
+
+ LICENSE TERMS
+
+ The redistribution and use of this software (with or without changes)
+ is allowed without the payment of fees or royalties provided that:
+
+  1. source code distributions include the above copyright notice, this
+     list of conditions and the following disclaimer;
+
+  2. binary distributions include the above copyright notice, this list
+     of conditions and the following disclaimer in their documentation;
+
+  3. the name of the copyright holder is not used to endorse products
+     built using this software without specific written permission.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ ---------------------------------------------------------------------------
+ Issue Date: 20/12/2007
+*/
+
+#include "aesopt.h"
+#include "aestab.h"
+
+#ifdef USE_VIA_ACE_IF_PRESENT
+#  include "aes_via_ace.h"
+#endif
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+/* Initialise the key schedule from the user supplied key. The key
+   length can be specified in bytes, with legal values of 16, 24
+   and 32, or in bits, with legal values of 128, 192 and 256. These
+   values correspond with Nk values of 4, 6 and 8 respectively.
+
+   The following macros implement a single cycle in the key
+   schedule generation process. The number of cycles needed
+   for each cx->n_col and nk value is:
+
+    nk =             4  5  6  7  8
+    ------------------------------
+    cx->n_col = 4   10  9  8  7  7
+    cx->n_col = 5   14 11 10  9  9
+    cx->n_col = 6   19 15 12 11 11
+    cx->n_col = 7   21 19 16 13 14
+    cx->n_col = 8   29 23 19 17 14
+*/
+
+#if defined( REDUCE_CODE_SIZE )
+#  define ls_box ls_sub
+   uint_32t ls_sub(const uint_32t t, const uint_32t n);
+#  define inv_mcol im_sub
+   uint_32t im_sub(const uint_32t x);
+#  ifdef ENC_KS_UNROLL
+#    undef ENC_KS_UNROLL
+#  endif
+#  ifdef DEC_KS_UNROLL
+#    undef DEC_KS_UNROLL
+#  endif
+#endif
+
+#if (FUNCS_IN_C & ENC_KEYING_IN_C)
+
+#if defined(AES_128) || defined( AES_VAR )
+
+#define ke4(k,i) \
+{   k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \
+    k[4*(i)+5] = ss[1] ^= ss[0]; \
+    k[4*(i)+6] = ss[2] ^= ss[1]; \
+    k[4*(i)+7] = ss[3] ^= ss[2]; \
+}
+
+AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1])
+{   uint_32t    ss[4];
+
+    cx->ks[0] = ss[0] = word_in(key, 0);
+    cx->ks[1] = ss[1] = word_in(key, 1);
+    cx->ks[2] = ss[2] = word_in(key, 2);
+    cx->ks[3] = ss[3] = word_in(key, 3);
+
+#ifdef ENC_KS_UNROLL
+    ke4(cx->ks, 0);  ke4(cx->ks, 1);
+    ke4(cx->ks, 2);  ke4(cx->ks, 3);
+    ke4(cx->ks, 4);  ke4(cx->ks, 5);
+    ke4(cx->ks, 6);  ke4(cx->ks, 7);
+    ke4(cx->ks, 8);
+#else
+    {   uint_32t i;
+        for(i = 0; i < 9; ++i)
+            ke4(cx->ks, i);
+    }
+#endif
+    ke4(cx->ks, 9);
+    cx->inf.l = 0;
+    cx->inf.b[0] = 10 * 16;
+
+#ifdef USE_VIA_ACE_IF_PRESENT
+    if(VIA_ACE_AVAILABLE)
+        cx->inf.b[1] = 0xff;
+#endif
+    return EXIT_SUCCESS;
+}
+
+#endif
+
+#if defined(AES_192) || defined( AES_VAR )
+
+#define kef6(k,i) \
+{   k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \
+    k[6*(i)+ 7] = ss[1] ^= ss[0]; \
+    k[6*(i)+ 8] = ss[2] ^= ss[1]; \
+    k[6*(i)+ 9] = ss[3] ^= ss[2]; \
+}
+
+#define ke6(k,i) \
+{   kef6(k,i); \
+    k[6*(i)+10] = ss[4] ^= ss[3]; \
+    k[6*(i)+11] = ss[5] ^= ss[4]; \
+}
+
+AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1])
+{   uint_32t    ss[6];
+
+    cx->ks[0] = ss[0] = word_in(key, 0);
+    cx->ks[1] = ss[1] = word_in(key, 1);
+    cx->ks[2] = ss[2] = word_in(key, 2);
+    cx->ks[3] = ss[3] = word_in(key, 3);
+    cx->ks[4] = ss[4] = word_in(key, 4);
+    cx->ks[5] = ss[5] = word_in(key, 5);
+
+#ifdef ENC_KS_UNROLL
+    ke6(cx->ks, 0);  ke6(cx->ks, 1);
+    ke6(cx->ks, 2);  ke6(cx->ks, 3);
+    ke6(cx->ks, 4);  ke6(cx->ks, 5);
+    ke6(cx->ks, 6);
+#else
+    {   uint_32t i;
+        for(i = 0; i < 7; ++i)
+            ke6(cx->ks, i);
+    }
+#endif
+    kef6(cx->ks, 7);
+    cx->inf.l = 0;
+    cx->inf.b[0] = 12 * 16;
+
+#ifdef USE_VIA_ACE_IF_PRESENT
+    if(VIA_ACE_AVAILABLE)
+        cx->inf.b[1] = 0xff;
+#endif
+    return EXIT_SUCCESS;
+}
+
+#endif
+
+#if defined(AES_256) || defined( AES_VAR )
+
+#define kef8(k,i) \
+{   k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \
+    k[8*(i)+ 9] = ss[1] ^= ss[0]; \
+    k[8*(i)+10] = ss[2] ^= ss[1]; \
+    k[8*(i)+11] = ss[3] ^= ss[2]; \
+}
+
+#define ke8(k,i) \
+{   kef8(k,i); \
+    k[8*(i)+12] = ss[4] ^= ls_box(ss[3],0); \
+    k[8*(i)+13] = ss[5] ^= ss[4]; \
+    k[8*(i)+14] = ss[6] ^= ss[5]; \
+    k[8*(i)+15] = ss[7] ^= ss[6]; \
+}
+
+AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1])
+{   uint_32t    ss[8];
+
+    cx->ks[0] = ss[0] = word_in(key, 0);
+    cx->ks[1] = ss[1] = word_in(key, 1);
+    cx->ks[2] = ss[2] = word_in(key, 2);
+    cx->ks[3] = ss[3] = word_in(key, 3);
+    cx->ks[4] = ss[4] = word_in(key, 4);
+    cx->ks[5] = ss[5] = word_in(key, 5);
+    cx->ks[6] = ss[6] = word_in(key, 6);
+    cx->ks[7] = ss[7] = word_in(key, 7);
+
+#ifdef ENC_KS_UNROLL
+    ke8(cx->ks, 0); ke8(cx->ks, 1);
+    ke8(cx->ks, 2); ke8(cx->ks, 3);
+    ke8(cx->ks, 4); ke8(cx->ks, 5);
+#else
+    {   uint_32t i;
+        for(i = 0; i < 6; ++i)
+            ke8(cx->ks,  i);
+    }
+#endif
+    kef8(cx->ks, 6);
+    cx->inf.l = 0;
+    cx->inf.b[0] = 14 * 16;
+
+#ifdef USE_VIA_ACE_IF_PRESENT
+    if(VIA_ACE_AVAILABLE)
+        cx->inf.b[1] = 0xff;
+#endif
+    return EXIT_SUCCESS;
+}
+
+#endif
+
+#if defined( AES_VAR )
+
+AES_RETURN aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1])
+{   
+    switch(key_len)
+    {
+    case 16: case 128: return aes_encrypt_key128(key, cx);
+    case 24: case 192: return aes_encrypt_key192(key, cx);
+    case 32: case 256: return aes_encrypt_key256(key, cx);
+    default: return EXIT_FAILURE;
+    }
+}
+
+#endif
+
+#endif
+
+#if (FUNCS_IN_C & DEC_KEYING_IN_C)
+
+/* this is used to store the decryption round keys  */
+/* in forward or reverse order                      */
+
+#ifdef AES_REV_DKS
+#define v(n,i)  ((n) - (i) + 2 * ((i) & 3))
+#else
+#define v(n,i)  (i)
+#endif
+
+#if DEC_ROUND == NO_TABLES
+#define ff(x)   (x)
+#else
+#define ff(x)   inv_mcol(x)
+#if defined( dec_imvars )
+#define d_vars  dec_imvars
+#endif
+#endif
+
+#if defined(AES_128) || defined( AES_VAR )
+
+#define k4e(k,i) \
+{   k[v(40,(4*(i))+4)] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \
+    k[v(40,(4*(i))+5)] = ss[1] ^= ss[0]; \
+    k[v(40,(4*(i))+6)] = ss[2] ^= ss[1]; \
+    k[v(40,(4*(i))+7)] = ss[3] ^= ss[2]; \
+}
+
+#if 1
+
+#define kdf4(k,i) \
+{   ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3]; \
+    ss[1] = ss[1] ^ ss[3]; \
+    ss[2] = ss[2] ^ ss[3]; \
+    ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \
+    ss[i % 4] ^= ss[4]; \
+    ss[4] ^= k[v(40,(4*(i)))];   k[v(40,(4*(i))+4)] = ff(ss[4]); \
+    ss[4] ^= k[v(40,(4*(i))+1)]; k[v(40,(4*(i))+5)] = ff(ss[4]); \
+    ss[4] ^= k[v(40,(4*(i))+2)]; k[v(40,(4*(i))+6)] = ff(ss[4]); \
+    ss[4] ^= k[v(40,(4*(i))+3)]; k[v(40,(4*(i))+7)] = ff(ss[4]); \
+}
+
+#define kd4(k,i) \
+{   ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \
+    ss[i % 4] ^= ss[4]; ss[4] = ff(ss[4]); \
+    k[v(40,(4*(i))+4)] = ss[4] ^= k[v(40,(4*(i)))]; \
+    k[v(40,(4*(i))+5)] = ss[4] ^= k[v(40,(4*(i))+1)]; \
+    k[v(40,(4*(i))+6)] = ss[4] ^= k[v(40,(4*(i))+2)]; \
+    k[v(40,(4*(i))+7)] = ss[4] ^= k[v(40,(4*(i))+3)]; \
+}
+
+#define kdl4(k,i) \
+{   ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; ss[i % 4] ^= ss[4]; \
+    k[v(40,(4*(i))+4)] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3]; \
+    k[v(40,(4*(i))+5)] = ss[1] ^ ss[3]; \
+    k[v(40,(4*(i))+6)] = ss[0]; \
+    k[v(40,(4*(i))+7)] = ss[1]; \
+}
+
+#else
+
+#define kdf4(k,i) \
+{   ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[v(40,(4*(i))+ 4)] = ff(ss[0]); \
+    ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ff(ss[1]); \
+    ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ff(ss[2]); \
+    ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ff(ss[3]); \
+}
+
+#define kd4(k,i) \
+{   ss[4] = ls_box(ss[3],3) ^ t_use(r,c)[i]; \
+    ss[0] ^= ss[4]; ss[4] = ff(ss[4]); k[v(40,(4*(i))+ 4)] = ss[4] ^= k[v(40,(4*(i)))]; \
+    ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ss[4] ^= k[v(40,(4*(i))+ 1)]; \
+    ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ss[4] ^= k[v(40,(4*(i))+ 2)]; \
+    ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ss[4] ^= k[v(40,(4*(i))+ 3)]; \
+}
+
+#define kdl4(k,i) \
+{   ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[v(40,(4*(i))+ 4)] = ss[0]; \
+    ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ss[1]; \
+    ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ss[2]; \
+    ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ss[3]; \
+}
+
+#endif
+
+AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1])
+{   uint_32t    ss[5];
+#if defined( d_vars )
+        d_vars;
+#endif
+    cx->ks[v(40,(0))] = ss[0] = word_in(key, 0);
+    cx->ks[v(40,(1))] = ss[1] = word_in(key, 1);
+    cx->ks[v(40,(2))] = ss[2] = word_in(key, 2);
+    cx->ks[v(40,(3))] = ss[3] = word_in(key, 3);
+
+#ifdef DEC_KS_UNROLL
+     kdf4(cx->ks, 0); kd4(cx->ks, 1);
+     kd4(cx->ks, 2);  kd4(cx->ks, 3);
+     kd4(cx->ks, 4);  kd4(cx->ks, 5);
+     kd4(cx->ks, 6);  kd4(cx->ks, 7);
+     kd4(cx->ks, 8);  kdl4(cx->ks, 9);
+#else
+    {   uint_32t i;
+        for(i = 0; i < 10; ++i)
+            k4e(cx->ks, i);
+#if !(DEC_ROUND == NO_TABLES)
+        for(i = N_COLS; i < 10 * N_COLS; ++i)
+            cx->ks[i] = inv_mcol(cx->ks[i]);
+#endif
+    }
+#endif
+    cx->inf.l = 0;
+    cx->inf.b[0] = 10 * 16;
+
+#ifdef USE_VIA_ACE_IF_PRESENT
+    if(VIA_ACE_AVAILABLE)
+        cx->inf.b[1] = 0xff;
+#endif
+    return EXIT_SUCCESS;
+}
+
+#endif
+
+#if defined(AES_192) || defined( AES_VAR )
+
+#define k6ef(k,i) \
+{   k[v(48,(6*(i))+ 6)] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \
+    k[v(48,(6*(i))+ 7)] = ss[1] ^= ss[0]; \
+    k[v(48,(6*(i))+ 8)] = ss[2] ^= ss[1]; \
+    k[v(48,(6*(i))+ 9)] = ss[3] ^= ss[2]; \
+}
+
+#define k6e(k,i) \
+{   k6ef(k,i); \
+    k[v(48,(6*(i))+10)] = ss[4] ^= ss[3]; \
+    k[v(48,(6*(i))+11)] = ss[5] ^= ss[4]; \
+}
+
+#define kdf6(k,i) \
+{   ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ff(ss[0]); \
+    ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ff(ss[1]); \
+    ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ff(ss[2]); \
+    ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ff(ss[3]); \
+    ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ff(ss[4]); \
+    ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ff(ss[5]); \
+}
+
+#define kd6(k,i) \
+{   ss[6] = ls_box(ss[5],3) ^ t_use(r,c)[i]; \
+    ss[0] ^= ss[6]; ss[6] = ff(ss[6]); k[v(48,(6*(i))+ 6)] = ss[6] ^= k[v(48,(6*(i)))]; \
+    ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[6] ^= k[v(48,(6*(i))+ 1)]; \
+    ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[6] ^= k[v(48,(6*(i))+ 2)]; \
+    ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[6] ^= k[v(48,(6*(i))+ 3)]; \
+    ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ss[6] ^= k[v(48,(6*(i))+ 4)]; \
+    ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ss[6] ^= k[v(48,(6*(i))+ 5)]; \
+}
+
+#define kdl6(k,i) \
+{   ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ss[0]; \
+    ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[1]; \
+    ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[2]; \
+    ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[3]; \
+}
+
+AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1])
+{   uint_32t    ss[7];
+#if defined( d_vars )
+        d_vars;
+#endif
+    cx->ks[v(48,(0))] = ss[0] = word_in(key, 0);
+    cx->ks[v(48,(1))] = ss[1] = word_in(key, 1);
+    cx->ks[v(48,(2))] = ss[2] = word_in(key, 2);
+    cx->ks[v(48,(3))] = ss[3] = word_in(key, 3);
+
+#ifdef DEC_KS_UNROLL
+    cx->ks[v(48,(4))] = ff(ss[4] = word_in(key, 4));
+    cx->ks[v(48,(5))] = ff(ss[5] = word_in(key, 5));
+    kdf6(cx->ks, 0); kd6(cx->ks, 1);
+    kd6(cx->ks, 2);  kd6(cx->ks, 3);
+    kd6(cx->ks, 4);  kd6(cx->ks, 5);
+    kd6(cx->ks, 6);  kdl6(cx->ks, 7);
+#else
+    cx->ks[v(48,(4))] = ss[4] = word_in(key, 4);
+    cx->ks[v(48,(5))] = ss[5] = word_in(key, 5);
+    {   uint_32t i;
+
+        for(i = 0; i < 7; ++i)
+            k6e(cx->ks, i);
+        k6ef(cx->ks, 7);
+#if !(DEC_ROUND == NO_TABLES)
+        for(i = N_COLS; i < 12 * N_COLS; ++i)
+            cx->ks[i] = inv_mcol(cx->ks[i]);
+#endif
+    }
+#endif
+    cx->inf.l = 0;
+    cx->inf.b[0] = 12 * 16;
+
+#ifdef USE_VIA_ACE_IF_PRESENT
+    if(VIA_ACE_AVAILABLE)
+        cx->inf.b[1] = 0xff;
+#endif
+    return EXIT_SUCCESS;
+}
+
+#endif
+
+#if defined(AES_256) || defined( AES_VAR )
+
+#define k8ef(k,i) \
+{   k[v(56,(8*(i))+ 8)] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \
+    k[v(56,(8*(i))+ 9)] = ss[1] ^= ss[0]; \
+    k[v(56,(8*(i))+10)] = ss[2] ^= ss[1]; \
+    k[v(56,(8*(i))+11)] = ss[3] ^= ss[2]; \
+}
+
+#define k8e(k,i) \
+{   k8ef(k,i); \
+    k[v(56,(8*(i))+12)] = ss[4] ^= ls_box(ss[3],0); \
+    k[v(56,(8*(i))+13)] = ss[5] ^= ss[4]; \
+    k[v(56,(8*(i))+14)] = ss[6] ^= ss[5]; \
+    k[v(56,(8*(i))+15)] = ss[7] ^= ss[6]; \
+}
+
+#define kdf8(k,i) \
+{   ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ff(ss[0]); \
+    ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ff(ss[1]); \
+    ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ff(ss[2]); \
+    ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ff(ss[3]); \
+    ss[4] ^= ls_box(ss[3],0); k[v(56,(8*(i))+12)] = ff(ss[4]); \
+    ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ff(ss[5]); \
+    ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ff(ss[6]); \
+    ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ff(ss[7]); \
+}
+
+#define kd8(k,i) \
+{   ss[8] = ls_box(ss[7],3) ^ t_use(r,c)[i]; \
+    ss[0] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+ 8)] = ss[8] ^= k[v(56,(8*(i)))]; \
+    ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[8] ^= k[v(56,(8*(i))+ 1)]; \
+    ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[8] ^= k[v(56,(8*(i))+ 2)]; \
+    ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[8] ^= k[v(56,(8*(i))+ 3)]; \
+    ss[8] = ls_box(ss[3],0); \
+    ss[4] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+12)] = ss[8] ^= k[v(56,(8*(i))+ 4)]; \
+    ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ss[8] ^= k[v(56,(8*(i))+ 5)]; \
+    ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ss[8] ^= k[v(56,(8*(i))+ 6)]; \
+    ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ss[8] ^= k[v(56,(8*(i))+ 7)]; \
+}
+
+#define kdl8(k,i) \
+{   ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ss[0]; \
+    ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[1]; \
+    ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[2]; \
+    ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[3]; \
+}
+
+AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1])
+{   uint_32t    ss[9];
+#if defined( d_vars )
+        d_vars;
+#endif
+    cx->ks[v(56,(0))] = ss[0] = word_in(key, 0);
+    cx->ks[v(56,(1))] = ss[1] = word_in(key, 1);
+    cx->ks[v(56,(2))] = ss[2] = word_in(key, 2);
+    cx->ks[v(56,(3))] = ss[3] = word_in(key, 3);
+
+#ifdef DEC_KS_UNROLL
+    cx->ks[v(56,(4))] = ff(ss[4] = word_in(key, 4));
+    cx->ks[v(56,(5))] = ff(ss[5] = word_in(key, 5));
+    cx->ks[v(56,(6))] = ff(ss[6] = word_in(key, 6));
+    cx->ks[v(56,(7))] = ff(ss[7] = word_in(key, 7));
+    kdf8(cx->ks, 0); kd8(cx->ks, 1);
+    kd8(cx->ks, 2);  kd8(cx->ks, 3);
+    kd8(cx->ks, 4);  kd8(cx->ks, 5);
+    kdl8(cx->ks, 6);
+#else
+    cx->ks[v(56,(4))] = ss[4] = word_in(key, 4);
+    cx->ks[v(56,(5))] = ss[5] = word_in(key, 5);
+    cx->ks[v(56,(6))] = ss[6] = word_in(key, 6);
+    cx->ks[v(56,(7))] = ss[7] = word_in(key, 7);
+    {   uint_32t i;
+
+        for(i = 0; i < 6; ++i)
+            k8e(cx->ks,  i);
+        k8ef(cx->ks,  6);
+#if !(DEC_ROUND == NO_TABLES)
+        for(i = N_COLS; i < 14 * N_COLS; ++i)
+            cx->ks[i] = inv_mcol(cx->ks[i]);
+#endif
+    }
+#endif
+    cx->inf.l = 0;
+    cx->inf.b[0] = 14 * 16;
+
+#ifdef USE_VIA_ACE_IF_PRESENT
+    if(VIA_ACE_AVAILABLE)
+        cx->inf.b[1] = 0xff;
+#endif
+    return EXIT_SUCCESS;
+}
+
+#endif
+
+#if defined( AES_VAR )
+
+AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1])
+{
+    switch(key_len)
+    {
+    case 16: case 128: return aes_decrypt_key128(key, cx);
+    case 24: case 192: return aes_decrypt_key192(key, cx);
+    case 32: case 256: return aes_decrypt_key256(key, cx);
+    default: return EXIT_FAILURE;
+    }
+}
+
+#endif
+
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
diff --git a/cbits/gladman/aesopt.h b/cbits/gladman/aesopt.h
new file mode 100644
--- /dev/null
+++ b/cbits/gladman/aesopt.h
@@ -0,0 +1,746 @@
+/*
+ ---------------------------------------------------------------------------
+ Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
+
+ LICENSE TERMS
+
+ The redistribution and use of this software (with or without changes)
+ is allowed without the payment of fees or royalties provided that:
+
+  1. source code distributions include the above copyright notice, this
+     list of conditions and the following disclaimer;
+
+  2. binary distributions include the above copyright notice, this list
+     of conditions and the following disclaimer in their documentation;
+
+  3. the name of the copyright holder is not used to endorse products
+     built using this software without specific written permission.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ ---------------------------------------------------------------------------
+ Issue Date: 20/12/2007
+
+ This file contains the compilation options for AES (Rijndael) and code
+ that is common across encryption, key scheduling and table generation.
+
+ OPERATION
+
+ These source code files implement the AES algorithm Rijndael designed by
+ Joan Daemen and Vincent Rijmen. This version is designed for the standard
+ block size of 16 bytes and for key sizes of 128, 192 and 256 bits (16, 24
+ and 32 bytes).
+
+ This version is designed for flexibility and speed using operations on
+ 32-bit words rather than operations on bytes.  It can be compiled with
+ either big or little endian internal byte order but is faster when the
+ native byte order for the processor is used.
+
+ THE CIPHER INTERFACE
+
+ The cipher interface is implemented as an array of bytes in which lower
+ AES bit sequence indexes map to higher numeric significance within bytes.
+
+  uint_8t                 (an unsigned  8-bit type)
+  uint_32t                (an unsigned 32-bit type)
+  struct aes_encrypt_ctx  (structure for the cipher encryption context)
+  struct aes_decrypt_ctx  (structure for the cipher decryption context)
+  AES_RETURN                the function return type
+
+  C subroutine calls:
+
+  AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]);
+  AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]);
+  AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]);
+  AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out,
+                                                  const aes_encrypt_ctx cx[1]);
+
+  AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]);
+  AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]);
+  AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]);
+  AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out,
+                                                  const aes_decrypt_ctx cx[1]);
+
+ IMPORTANT NOTE: If you are using this C interface with dynamic tables make sure that
+ you call aes_init() before AES is used so that the tables are initialised.
+
+ C++ aes class subroutines:
+
+     Class AESencrypt  for encryption
+
+      Construtors:
+          AESencrypt(void)
+          AESencrypt(const unsigned char *key) - 128 bit key
+      Members:
+          AES_RETURN key128(const unsigned char *key)
+          AES_RETURN key192(const unsigned char *key)
+          AES_RETURN key256(const unsigned char *key)
+          AES_RETURN encrypt(const unsigned char *in, unsigned char *out) const
+
+      Class AESdecrypt  for encryption
+      Construtors:
+          AESdecrypt(void)
+          AESdecrypt(const unsigned char *key) - 128 bit key
+      Members:
+          AES_RETURN key128(const unsigned char *key)
+          AES_RETURN key192(const unsigned char *key)
+          AES_RETURN key256(const unsigned char *key)
+          AES_RETURN decrypt(const unsigned char *in, unsigned char *out) const
+*/
+
+#if !defined( _AESOPT_H )
+#define _AESOPT_H
+
+#if defined( __cplusplus )
+#include "aescpp.h"
+#else
+#include "aes.h"
+#endif
+
+/*  PLATFORM SPECIFIC INCLUDES */
+
+#include "brg_endian.h"
+
+/*  CONFIGURATION - THE USE OF DEFINES
+
+    Later in this section there are a number of defines that control the
+    operation of the code.  In each section, the purpose of each define is
+    explained so that the relevant form can be included or excluded by
+    setting either 1's or 0's respectively on the branches of the related
+    #if clauses.  The following local defines should not be changed.
+*/
+
+#define ENCRYPTION_IN_C     1
+#define DECRYPTION_IN_C     2
+#define ENC_KEYING_IN_C     4
+#define DEC_KEYING_IN_C     8
+
+#define NO_TABLES           0
+#define ONE_TABLE           1
+#define FOUR_TABLES         4
+#define NONE                0
+#define PARTIAL             1
+#define FULL                2
+
+/*  --- START OF USER CONFIGURED OPTIONS --- */
+
+/*  1. BYTE ORDER WITHIN 32 BIT WORDS
+
+    The fundamental data processing units in Rijndael are 8-bit bytes. The
+    input, output and key input are all enumerated arrays of bytes in which
+    bytes are numbered starting at zero and increasing to one less than the
+    number of bytes in the array in question. This enumeration is only used
+    for naming bytes and does not imply any adjacency or order relationship
+    from one byte to another. When these inputs and outputs are considered
+    as bit sequences, bits 8*n to 8*n+7 of the bit sequence are mapped to
+    byte[n] with bit 8n+i in the sequence mapped to bit 7-i within the byte.
+    In this implementation bits are numbered from 0 to 7 starting at the
+    numerically least significant end of each byte (bit n represents 2^n).
+
+    However, Rijndael can be implemented more efficiently using 32-bit
+    words by packing bytes into words so that bytes 4*n to 4*n+3 are placed
+    into word[n]. While in principle these bytes can be assembled into words
+    in any positions, this implementation only supports the two formats in
+    which bytes in adjacent positions within words also have adjacent byte
+    numbers. This order is called big-endian if the lowest numbered bytes
+    in words have the highest numeric significance and little-endian if the
+    opposite applies.
+
+    This code can work in either order irrespective of the order used by the
+    machine on which it runs. Normally the internal byte order will be set
+    to the order of the processor on which the code is to be run but this
+    define can be used to reverse this in special situations
+
+    WARNING: Assembler code versions rely on PLATFORM_BYTE_ORDER being set.
+    This define will hence be redefined later (in section 4) if necessary
+*/
+
+#if 1
+#  define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER
+#elif 0
+#  define ALGORITHM_BYTE_ORDER IS_LITTLE_ENDIAN
+#elif 0
+#  define ALGORITHM_BYTE_ORDER IS_BIG_ENDIAN
+#else
+#  error The algorithm byte order is not defined
+#endif
+
+/*  2. VIA ACE SUPPORT */
+
+#if defined( __GNUC__ ) && defined( __i386__ ) \
+ || defined( _WIN32   ) && defined( _M_IX86  ) \
+ && !(defined( _WIN64 ) || defined( _WIN32_WCE ) || defined( _MSC_VER ) && ( _MSC_VER <= 800 ))
+#  define VIA_ACE_POSSIBLE
+#endif
+
+/*  Define this option if support for the VIA ACE is required. This uses
+    inline assembler instructions and is only implemented for the Microsoft,
+    Intel and GCC compilers.  If VIA ACE is known to be present, then defining
+    ASSUME_VIA_ACE_PRESENT will remove the ordinary encryption/decryption
+    code.  If USE_VIA_ACE_IF_PRESENT is defined then VIA ACE will be used if
+    it is detected (both present and enabled) but the normal AES code will
+    also be present.
+
+    When VIA ACE is to be used, all AES encryption contexts MUST be 16 byte
+    aligned; other input/output buffers do not need to be 16 byte aligned
+    but there are very large performance gains if this can be arranged.
+    VIA ACE also requires the decryption key schedule to be in reverse
+    order (which later checks below ensure).
+*/
+
+#if 1 && defined( VIA_ACE_POSSIBLE ) && !defined( USE_VIA_ACE_IF_PRESENT )
+#  define USE_VIA_ACE_IF_PRESENT
+#endif
+
+#if 0 && defined( VIA_ACE_POSSIBLE ) && !defined( ASSUME_VIA_ACE_PRESENT )
+#  define ASSUME_VIA_ACE_PRESENT
+#  endif
+
+/*  3. ASSEMBLER SUPPORT
+
+    This define (which can be on the command line) enables the use of the
+    assembler code routines for encryption, decryption and key scheduling
+    as follows:
+
+    ASM_X86_V1C uses the assembler (aes_x86_v1.asm) with large tables for
+                encryption and decryption and but with key scheduling in C
+    ASM_X86_V2  uses assembler (aes_x86_v2.asm) with compressed tables for
+                encryption, decryption and key scheduling
+    ASM_X86_V2C uses assembler (aes_x86_v2.asm) with compressed tables for
+                encryption and decryption and but with key scheduling in C
+    ASM_AMD64_C uses assembler (aes_amd64.asm) with compressed tables for
+                encryption and decryption and but with key scheduling in C
+
+    Change one 'if 0' below to 'if 1' to select the version or define
+    as a compilation option.
+*/
+
+#if 0 && !defined( ASM_X86_V1C )
+#  define ASM_X86_V1C
+#elif 0 && !defined( ASM_X86_V2  )
+#  define ASM_X86_V2
+#elif 0 && !defined( ASM_X86_V2C )
+#  define ASM_X86_V2C
+#elif 0 && !defined( ASM_AMD64_C )
+#  define ASM_AMD64_C
+#endif
+
+#if (defined ( ASM_X86_V1C ) || defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )) \
+      && !defined( _M_IX86 ) || defined( ASM_AMD64_C ) && !defined( _M_X64 )
+#  error Assembler code is only available for x86 and AMD64 systems
+#endif
+
+/*  4. FAST INPUT/OUTPUT OPERATIONS.
+
+    On some machines it is possible to improve speed by transferring the
+    bytes in the input and output arrays to and from the internal 32-bit
+    variables by addressing these arrays as if they are arrays of 32-bit
+    words.  On some machines this will always be possible but there may
+    be a large performance penalty if the byte arrays are not aligned on
+    the normal word boundaries. On other machines this technique will
+    lead to memory access errors when such 32-bit word accesses are not
+    properly aligned. The option SAFE_IO avoids such problems but will
+    often be slower on those machines that support misaligned access
+    (especially so if care is taken to align the input  and output byte
+    arrays on 32-bit word boundaries). If SAFE_IO is not defined it is
+    assumed that access to byte arrays as if they are arrays of 32-bit
+    words will not cause problems when such accesses are misaligned.
+*/
+#if 1 && !defined( _MSC_VER )
+#  define SAFE_IO
+#endif
+
+/*  5. LOOP UNROLLING
+
+    The code for encryption and decrytpion cycles through a number of rounds
+    that can be implemented either in a loop or by expanding the code into a
+    long sequence of instructions, the latter producing a larger program but
+    one that will often be much faster. The latter is called loop unrolling.
+    There are also potential speed advantages in expanding two iterations in
+    a loop with half the number of iterations, which is called partial loop
+    unrolling.  The following options allow partial or full loop unrolling
+    to be set independently for encryption and decryption
+*/
+#if 1
+#  define ENC_UNROLL  FULL
+#elif 0
+#  define ENC_UNROLL  PARTIAL
+#else
+#  define ENC_UNROLL  NONE
+#endif
+
+#if 1
+#  define DEC_UNROLL  FULL
+#elif 0
+#  define DEC_UNROLL  PARTIAL
+#else
+#  define DEC_UNROLL  NONE
+#endif
+
+#if 1
+#  define ENC_KS_UNROLL
+#endif
+
+#if 1
+#  define DEC_KS_UNROLL
+#endif
+
+/*  6. FAST FINITE FIELD OPERATIONS
+
+    If this section is included, tables are used to provide faster finite
+    field arithmetic (this has no effect if FIXED_TABLES is defined).
+*/
+#if 1
+#  define FF_TABLES
+#endif
+
+/*  7. INTERNAL STATE VARIABLE FORMAT
+
+    The internal state of Rijndael is stored in a number of local 32-bit
+    word varaibles which can be defined either as an array or as individual
+    names variables. Include this section if you want to store these local
+    varaibles in arrays. Otherwise individual local variables will be used.
+*/
+#if 1
+#  define ARRAYS
+#endif
+
+/*  8. FIXED OR DYNAMIC TABLES
+
+    When this section is included the tables used by the code are compiled
+    statically into the binary file.  Otherwise the subroutine aes_init()
+    must be called to compute them before the code is first used.
+*/
+#if 1 && !(defined( _MSC_VER ) && ( _MSC_VER <= 800 ))
+#  define FIXED_TABLES
+#endif
+
+/*  9. MASKING OR CASTING FROM LONGER VALUES TO BYTES
+
+    In some systems it is better to mask longer values to extract bytes 
+    rather than using a cast. This option allows this choice.
+*/
+#if 0
+#  define to_byte(x)  ((uint_8t)(x))
+#else
+#  define to_byte(x)  ((x) & 0xff)
+#endif
+
+/*  10. TABLE ALIGNMENT
+
+    On some sytsems speed will be improved by aligning the AES large lookup
+    tables on particular boundaries. This define should be set to a power of
+    two giving the desired alignment. It can be left undefined if alignment
+    is not needed.  This option is specific to the Microsft VC++ compiler -
+    it seems to sometimes cause trouble for the VC++ version 6 compiler.
+*/
+
+#if 1 && defined( _MSC_VER ) && ( _MSC_VER >= 1300 )
+#  define TABLE_ALIGN 32
+#endif
+
+/*  11.  REDUCE CODE AND TABLE SIZE
+
+    This replaces some expanded macros with function calls if AES_ASM_V2 or
+    AES_ASM_V2C are defined
+*/
+
+#if 1 && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C ))
+#  define REDUCE_CODE_SIZE
+#endif
+
+/*  12. TABLE OPTIONS
+
+    This cipher proceeds by repeating in a number of cycles known as 'rounds'
+    which are implemented by a round function which can optionally be speeded
+    up using tables.  The basic tables are each 256 32-bit words, with either
+    one or four tables being required for each round function depending on
+    how much speed is required. The encryption and decryption round functions
+    are different and the last encryption and decrytpion round functions are
+    different again making four different round functions in all.
+
+    This means that:
+      1. Normal encryption and decryption rounds can each use either 0, 1
+         or 4 tables and table spaces of 0, 1024 or 4096 bytes each.
+      2. The last encryption and decryption rounds can also use either 0, 1
+         or 4 tables and table spaces of 0, 1024 or 4096 bytes each.
+
+    Include or exclude the appropriate definitions below to set the number
+    of tables used by this implementation.
+*/
+
+#if 1   /* set tables for the normal encryption round */
+#  define ENC_ROUND   FOUR_TABLES
+#elif 0
+#  define ENC_ROUND   ONE_TABLE
+#else
+#  define ENC_ROUND   NO_TABLES
+#endif
+
+#if 1   /* set tables for the last encryption round */
+#  define LAST_ENC_ROUND  FOUR_TABLES
+#elif 0
+#  define LAST_ENC_ROUND  ONE_TABLE
+#else
+#  define LAST_ENC_ROUND  NO_TABLES
+#endif
+
+#if 1   /* set tables for the normal decryption round */
+#  define DEC_ROUND   FOUR_TABLES
+#elif 0
+#  define DEC_ROUND   ONE_TABLE
+#else
+#  define DEC_ROUND   NO_TABLES
+#endif
+
+#if 1   /* set tables for the last decryption round */
+#  define LAST_DEC_ROUND  FOUR_TABLES
+#elif 0
+#  define LAST_DEC_ROUND  ONE_TABLE
+#else
+#  define LAST_DEC_ROUND  NO_TABLES
+#endif
+
+/*  The decryption key schedule can be speeded up with tables in the same
+    way that the round functions can.  Include or exclude the following
+    defines to set this requirement.
+*/
+#if 1
+#  define KEY_SCHED   FOUR_TABLES
+#elif 0
+#  define KEY_SCHED   ONE_TABLE
+#else
+#  define KEY_SCHED   NO_TABLES
+#endif
+
+/*  ---- END OF USER CONFIGURED OPTIONS ---- */
+
+/* VIA ACE support is only available for VC++ and GCC */
+
+#if !defined( _MSC_VER ) && !defined( __GNUC__ )
+#  if defined( ASSUME_VIA_ACE_PRESENT )
+#    undef ASSUME_VIA_ACE_PRESENT
+#  endif
+#  if defined( USE_VIA_ACE_IF_PRESENT )
+#    undef USE_VIA_ACE_IF_PRESENT
+#  endif
+#endif
+
+#if defined( ASSUME_VIA_ACE_PRESENT ) && !defined( USE_VIA_ACE_IF_PRESENT )
+#  define USE_VIA_ACE_IF_PRESENT
+#endif
+
+#if defined( USE_VIA_ACE_IF_PRESENT ) && !defined ( AES_REV_DKS )
+#  define AES_REV_DKS
+#endif
+
+/* Assembler support requires the use of platform byte order */
+
+#if ( defined( ASM_X86_V1C ) || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) ) \
+    && (ALGORITHM_BYTE_ORDER != PLATFORM_BYTE_ORDER)
+#  undef  ALGORITHM_BYTE_ORDER
+#  define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER
+#endif
+
+/* In this implementation the columns of the state array are each held in
+   32-bit words. The state array can be held in various ways: in an array
+   of words, in a number of individual word variables or in a number of
+   processor registers. The following define maps a variable name x and
+   a column number c to the way the state array variable is to be held.
+   The first define below maps the state into an array x[c] whereas the
+   second form maps the state into a number of individual variables x0,
+   x1, etc.  Another form could map individual state colums to machine
+   register names.
+*/
+
+#if defined( ARRAYS )
+#  define s(x,c) x[c]
+#else
+#  define s(x,c) x##c
+#endif
+
+/*  This implementation provides subroutines for encryption, decryption
+    and for setting the three key lengths (separately) for encryption
+    and decryption. Since not all functions are needed, masks are set
+    up here to determine which will be implemented in C
+*/
+
+#if !defined( AES_ENCRYPT )
+#  define EFUNCS_IN_C   0
+#elif defined( ASSUME_VIA_ACE_PRESENT ) || defined( ASM_X86_V1C ) \
+    || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C )
+#  define EFUNCS_IN_C   ENC_KEYING_IN_C
+#elif !defined( ASM_X86_V2 )
+#  define EFUNCS_IN_C   ( ENCRYPTION_IN_C | ENC_KEYING_IN_C )
+#else
+#  define EFUNCS_IN_C   0
+#endif
+
+#if !defined( AES_DECRYPT )
+#  define DFUNCS_IN_C   0
+#elif defined( ASSUME_VIA_ACE_PRESENT ) || defined( ASM_X86_V1C ) \
+    || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C )
+#  define DFUNCS_IN_C   DEC_KEYING_IN_C
+#elif !defined( ASM_X86_V2 )
+#  define DFUNCS_IN_C   ( DECRYPTION_IN_C | DEC_KEYING_IN_C )
+#else
+#  define DFUNCS_IN_C   0
+#endif
+
+#define FUNCS_IN_C  ( EFUNCS_IN_C | DFUNCS_IN_C )
+
+/* END OF CONFIGURATION OPTIONS */
+
+#define RC_LENGTH   (5 * (AES_BLOCK_SIZE / 4 - 2))
+
+/* Disable or report errors on some combinations of options */
+
+#if ENC_ROUND == NO_TABLES && LAST_ENC_ROUND != NO_TABLES
+#  undef  LAST_ENC_ROUND
+#  define LAST_ENC_ROUND  NO_TABLES
+#elif ENC_ROUND == ONE_TABLE && LAST_ENC_ROUND == FOUR_TABLES
+#  undef  LAST_ENC_ROUND
+#  define LAST_ENC_ROUND  ONE_TABLE
+#endif
+
+#if ENC_ROUND == NO_TABLES && ENC_UNROLL != NONE
+#  undef  ENC_UNROLL
+#  define ENC_UNROLL  NONE
+#endif
+
+#if DEC_ROUND == NO_TABLES && LAST_DEC_ROUND != NO_TABLES
+#  undef  LAST_DEC_ROUND
+#  define LAST_DEC_ROUND  NO_TABLES
+#elif DEC_ROUND == ONE_TABLE && LAST_DEC_ROUND == FOUR_TABLES
+#  undef  LAST_DEC_ROUND
+#  define LAST_DEC_ROUND  ONE_TABLE
+#endif
+
+#if DEC_ROUND == NO_TABLES && DEC_UNROLL != NONE
+#  undef  DEC_UNROLL
+#  define DEC_UNROLL  NONE
+#endif
+
+#if defined( bswap32 )
+#  define aes_sw32    bswap32
+#elif defined( bswap_32 )
+#  define aes_sw32    bswap_32
+#else
+#  define brot(x,n)   (((uint_32t)(x) <<  n) | ((uint_32t)(x) >> (32 - n)))
+#  define aes_sw32(x) ((brot((x),8) & 0x00ff00ff) | (brot((x),24) & 0xff00ff00))
+#endif
+
+/*  upr(x,n):  rotates bytes within words by n positions, moving bytes to
+               higher index positions with wrap around into low positions
+    ups(x,n):  moves bytes by n positions to higher index positions in
+               words but without wrap around
+    bval(x,n): extracts a byte from a word
+
+    WARNING:   The definitions given here are intended only for use with
+               unsigned variables and with shift counts that are compile
+               time constants
+*/
+
+#if ( ALGORITHM_BYTE_ORDER == IS_LITTLE_ENDIAN )
+#  define upr(x,n)      (((uint_32t)(x) << (8 * (n))) | ((uint_32t)(x) >> (32 - 8 * (n))))
+#  define ups(x,n)      ((uint_32t) (x) << (8 * (n)))
+#  define bval(x,n)     to_byte((x) >> (8 * (n)))
+#  define bytes2word(b0, b1, b2, b3)  \
+        (((uint_32t)(b3) << 24) | ((uint_32t)(b2) << 16) | ((uint_32t)(b1) << 8) | (b0))
+#endif
+
+#if ( ALGORITHM_BYTE_ORDER == IS_BIG_ENDIAN )
+#  define upr(x,n)      (((uint_32t)(x) >> (8 * (n))) | ((uint_32t)(x) << (32 - 8 * (n))))
+#  define ups(x,n)      ((uint_32t) (x) >> (8 * (n)))
+#  define bval(x,n)     to_byte((x) >> (24 - 8 * (n)))
+#  define bytes2word(b0, b1, b2, b3)  \
+        (((uint_32t)(b0) << 24) | ((uint_32t)(b1) << 16) | ((uint_32t)(b2) << 8) | (b3))
+#endif
+
+#if defined( SAFE_IO )
+#  define word_in(x,c)    bytes2word(((const uint_8t*)(x)+4*c)[0], ((const uint_8t*)(x)+4*c)[1], \
+                                   ((const uint_8t*)(x)+4*c)[2], ((const uint_8t*)(x)+4*c)[3])
+#  define word_out(x,c,v) { ((uint_8t*)(x)+4*c)[0] = bval(v,0); ((uint_8t*)(x)+4*c)[1] = bval(v,1); \
+                          ((uint_8t*)(x)+4*c)[2] = bval(v,2); ((uint_8t*)(x)+4*c)[3] = bval(v,3); }
+#elif ( ALGORITHM_BYTE_ORDER == PLATFORM_BYTE_ORDER )
+#  define word_in(x,c)    (*((uint_32t*)(x)+(c)))
+#  define word_out(x,c,v) (*((uint_32t*)(x)+(c)) = (v))
+#else
+#  define word_in(x,c)    aes_sw32(*((uint_32t*)(x)+(c)))
+#  define word_out(x,c,v) (*((uint_32t*)(x)+(c)) = aes_sw32(v))
+#endif
+
+/* the finite field modular polynomial and elements */
+
+#define WPOLY   0x011b
+#define BPOLY     0x1b
+
+/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
+
+#define m1  0x80808080
+#define m2  0x7f7f7f7f
+#define gf_mulx(x)  ((((x) & m2) << 1) ^ ((((x) & m1) >> 7) * BPOLY))
+
+/* The following defines provide alternative definitions of gf_mulx that might
+   give improved performance if a fast 32-bit multiply is not available. Note
+   that a temporary variable u needs to be defined where gf_mulx is used.
+
+#define gf_mulx(x) (u = (x) & m1, u |= (u >> 1), ((x) & m2) << 1) ^ ((u >> 3) | (u >> 6))
+#define m4  (0x01010101 * BPOLY)
+#define gf_mulx(x) (u = (x) & m1, ((x) & m2) << 1) ^ ((u - (u >> 7)) & m4)
+*/
+
+/* Work out which tables are needed for the different options   */
+
+#if defined( ASM_X86_V1C )
+#  if defined( ENC_ROUND )
+#    undef  ENC_ROUND
+#  endif
+#  define ENC_ROUND   FOUR_TABLES
+#  if defined( LAST_ENC_ROUND )
+#    undef  LAST_ENC_ROUND
+#  endif
+#  define LAST_ENC_ROUND  FOUR_TABLES
+#  if defined( DEC_ROUND )
+#    undef  DEC_ROUND
+#  endif
+#  define DEC_ROUND   FOUR_TABLES
+#  if defined( LAST_DEC_ROUND )
+#    undef  LAST_DEC_ROUND
+#  endif
+#  define LAST_DEC_ROUND  FOUR_TABLES
+#  if defined( KEY_SCHED )
+#    undef  KEY_SCHED
+#    define KEY_SCHED   FOUR_TABLES
+#  endif
+#endif
+
+#if ( FUNCS_IN_C & ENCRYPTION_IN_C ) || defined( ASM_X86_V1C )
+#  if ENC_ROUND == ONE_TABLE
+#    define FT1_SET
+#  elif ENC_ROUND == FOUR_TABLES
+#    define FT4_SET
+#  else
+#    define SBX_SET
+#  endif
+#  if LAST_ENC_ROUND == ONE_TABLE
+#    define FL1_SET
+#  elif LAST_ENC_ROUND == FOUR_TABLES
+#    define FL4_SET
+#  elif !defined( SBX_SET )
+#    define SBX_SET
+#  endif
+#endif
+
+#if ( FUNCS_IN_C & DECRYPTION_IN_C ) || defined( ASM_X86_V1C )
+#  if DEC_ROUND == ONE_TABLE
+#    define IT1_SET
+#  elif DEC_ROUND == FOUR_TABLES
+#    define IT4_SET
+#  else
+#    define ISB_SET
+#  endif
+#  if LAST_DEC_ROUND == ONE_TABLE
+#    define IL1_SET
+#  elif LAST_DEC_ROUND == FOUR_TABLES
+#    define IL4_SET
+#  elif !defined(ISB_SET)
+#    define ISB_SET
+#  endif
+#endif
+
+#if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )))
+#  if ((FUNCS_IN_C & ENC_KEYING_IN_C) || (FUNCS_IN_C & DEC_KEYING_IN_C))
+#    if KEY_SCHED == ONE_TABLE
+#      if !defined( FL1_SET )  && !defined( FL4_SET ) 
+#        define LS1_SET
+#      endif
+#    elif KEY_SCHED == FOUR_TABLES
+#      if !defined( FL4_SET )
+#        define LS4_SET
+#      endif
+#    elif !defined( SBX_SET )
+#      define SBX_SET
+#    endif
+#  endif
+#  if (FUNCS_IN_C & DEC_KEYING_IN_C)
+#    if KEY_SCHED == ONE_TABLE
+#      define IM1_SET
+#    elif KEY_SCHED == FOUR_TABLES
+#      define IM4_SET
+#    elif !defined( SBX_SET )
+#      define SBX_SET
+#    endif
+#  endif
+#endif
+
+/* generic definitions of Rijndael macros that use tables    */
+
+#define no_table(x,box,vf,rf,c) bytes2word( \
+    box[bval(vf(x,0,c),rf(0,c))], \
+    box[bval(vf(x,1,c),rf(1,c))], \
+    box[bval(vf(x,2,c),rf(2,c))], \
+    box[bval(vf(x,3,c),rf(3,c))])
+
+#define one_table(x,op,tab,vf,rf,c) \
+ (     tab[bval(vf(x,0,c),rf(0,c))] \
+  ^ op(tab[bval(vf(x,1,c),rf(1,c))],1) \
+  ^ op(tab[bval(vf(x,2,c),rf(2,c))],2) \
+  ^ op(tab[bval(vf(x,3,c),rf(3,c))],3))
+
+#define four_tables(x,tab,vf,rf,c) \
+ (  tab[0][bval(vf(x,0,c),rf(0,c))] \
+  ^ tab[1][bval(vf(x,1,c),rf(1,c))] \
+  ^ tab[2][bval(vf(x,2,c),rf(2,c))] \
+  ^ tab[3][bval(vf(x,3,c),rf(3,c))])
+
+#define vf1(x,r,c)  (x)
+#define rf1(r,c)    (r)
+#define rf2(r,c)    ((8+r-c)&3)
+
+/* perform forward and inverse column mix operation on four bytes in long word x in */
+/* parallel. NOTE: x must be a simple variable, NOT an expression in these macros.  */
+
+#if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C ))) 
+
+#if defined( FM4_SET )      /* not currently used */
+#  define fwd_mcol(x)       four_tables(x,t_use(f,m),vf1,rf1,0)
+#elif defined( FM1_SET )    /* not currently used */
+#  define fwd_mcol(x)       one_table(x,upr,t_use(f,m),vf1,rf1,0)
+#else
+#  define dec_fmvars        uint_32t g2
+#  define fwd_mcol(x)       (g2 = gf_mulx(x), g2 ^ upr((x) ^ g2, 3) ^ upr((x), 2) ^ upr((x), 1))
+#endif
+
+#if defined( IM4_SET )
+#  define inv_mcol(x)       four_tables(x,t_use(i,m),vf1,rf1,0)
+#elif defined( IM1_SET )
+#  define inv_mcol(x)       one_table(x,upr,t_use(i,m),vf1,rf1,0)
+#else
+#  define dec_imvars        uint_32t g2, g4, g9
+#  define inv_mcol(x)       (g2 = gf_mulx(x), g4 = gf_mulx(g2), g9 = (x) ^ gf_mulx(g4), g4 ^= g9, \
+                            (x) ^ g2 ^ g4 ^ upr(g2 ^ g9, 3) ^ upr(g4, 2) ^ upr(g9, 1))
+#endif
+
+#if defined( FL4_SET )
+#  define ls_box(x,c)       four_tables(x,t_use(f,l),vf1,rf2,c)
+#elif defined( LS4_SET )
+#  define ls_box(x,c)       four_tables(x,t_use(l,s),vf1,rf2,c)
+#elif defined( FL1_SET )
+#  define ls_box(x,c)       one_table(x,upr,t_use(f,l),vf1,rf2,c)
+#elif defined( LS1_SET )
+#  define ls_box(x,c)       one_table(x,upr,t_use(l,s),vf1,rf2,c)
+#else
+#  define ls_box(x,c)       no_table(x,t_use(s,box),vf1,rf2,c)
+#endif
+
+#endif
+
+#if defined( ASM_X86_V1C ) && defined( AES_DECRYPT ) && !defined( ISB_SET )
+#  define ISB_SET
+#endif
+
+#endif
diff --git a/cbits/gladman/aestab.c b/cbits/gladman/aestab.c
new file mode 100644
--- /dev/null
+++ b/cbits/gladman/aestab.c
@@ -0,0 +1,398 @@
+/*
+ ---------------------------------------------------------------------------
+ Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
+
+ LICENSE TERMS
+
+ The redistribution and use of this software (with or without changes)
+ is allowed without the payment of fees or royalties provided that:
+
+  1. source code distributions include the above copyright notice, this
+     list of conditions and the following disclaimer;
+
+  2. binary distributions include the above copyright notice, this list
+     of conditions and the following disclaimer in their documentation;
+
+  3. the name of the copyright holder is not used to endorse products
+     built using this software without specific written permission.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ ---------------------------------------------------------------------------
+ Issue Date: 20/12/2007
+*/
+
+#define DO_TABLES
+
+#include "aes.h"
+#include "aesopt.h"
+
+#if defined(FIXED_TABLES)
+
+#define sb_data(w) {\
+    w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\
+    w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\
+    w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\
+    w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\
+    w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\
+    w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\
+    w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\
+    w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\
+    w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\
+    w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\
+    w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\
+    w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\
+    w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\
+    w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\
+    w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\
+    w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\
+    w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\
+    w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\
+    w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\
+    w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\
+    w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\
+    w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\
+    w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\
+    w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\
+    w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\
+    w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\
+    w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\
+    w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\
+    w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\
+    w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\
+    w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\
+    w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) }
+
+#define isb_data(w) {\
+    w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\
+    w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\
+    w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\
+    w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\
+    w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\
+    w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\
+    w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\
+    w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\
+    w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\
+    w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\
+    w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\
+    w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\
+    w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\
+    w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\
+    w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\
+    w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\
+    w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\
+    w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\
+    w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\
+    w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\
+    w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\
+    w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\
+    w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\
+    w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\
+    w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\
+    w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\
+    w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\
+    w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\
+    w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\
+    w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\
+    w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\
+    w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d) }
+
+#define mm_data(w) {\
+    w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\
+    w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\
+    w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\
+    w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\
+    w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\
+    w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\
+    w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\
+    w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\
+    w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\
+    w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\
+    w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\
+    w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\
+    w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\
+    w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\
+    w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\
+    w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\
+    w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\
+    w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\
+    w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\
+    w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\
+    w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\
+    w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\
+    w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\
+    w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\
+    w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\
+    w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\
+    w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\
+    w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\
+    w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\
+    w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\
+    w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\
+    w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) }
+
+#define rc_data(w) {\
+    w(0x01), w(0x02), w(0x04), w(0x08), w(0x10),w(0x20), w(0x40), w(0x80),\
+    w(0x1b), w(0x36) }
+
+#define h0(x)   (x)
+
+#define w0(p)   bytes2word(p, 0, 0, 0)
+#define w1(p)   bytes2word(0, p, 0, 0)
+#define w2(p)   bytes2word(0, 0, p, 0)
+#define w3(p)   bytes2word(0, 0, 0, p)
+
+#define u0(p)   bytes2word(f2(p), p, p, f3(p))
+#define u1(p)   bytes2word(f3(p), f2(p), p, p)
+#define u2(p)   bytes2word(p, f3(p), f2(p), p)
+#define u3(p)   bytes2word(p, p, f3(p), f2(p))
+
+#define v0(p)   bytes2word(fe(p), f9(p), fd(p), fb(p))
+#define v1(p)   bytes2word(fb(p), fe(p), f9(p), fd(p))
+#define v2(p)   bytes2word(fd(p), fb(p), fe(p), f9(p))
+#define v3(p)   bytes2word(f9(p), fd(p), fb(p), fe(p))
+
+#endif
+
+#if defined(FIXED_TABLES) || !defined(FF_TABLES)
+
+#define f2(x)   ((x<<1) ^ (((x>>7) & 1) * WPOLY))
+#define f4(x)   ((x<<2) ^ (((x>>6) & 1) * WPOLY) ^ (((x>>6) & 2) * WPOLY))
+#define f8(x)   ((x<<3) ^ (((x>>5) & 1) * WPOLY) ^ (((x>>5) & 2) * WPOLY) \
+                        ^ (((x>>5) & 4) * WPOLY))
+#define f3(x)   (f2(x) ^ x)
+#define f9(x)   (f8(x) ^ x)
+#define fb(x)   (f8(x) ^ f2(x) ^ x)
+#define fd(x)   (f8(x) ^ f4(x) ^ x)
+#define fe(x)   (f8(x) ^ f4(x) ^ f2(x))
+
+#else
+
+#define f2(x) ((x) ? pow[log[x] + 0x19] : 0)
+#define f3(x) ((x) ? pow[log[x] + 0x01] : 0)
+#define f9(x) ((x) ? pow[log[x] + 0xc7] : 0)
+#define fb(x) ((x) ? pow[log[x] + 0x68] : 0)
+#define fd(x) ((x) ? pow[log[x] + 0xee] : 0)
+#define fe(x) ((x) ? pow[log[x] + 0xdf] : 0)
+
+#endif
+
+#include "aestab.h"
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+#if defined(FIXED_TABLES)
+
+/* implemented in case of wrong call for fixed tables */
+
+AES_RETURN aes_init(void)
+{
+    return EXIT_SUCCESS;
+}
+
+#else   /*  Generate the tables for the dynamic table option */
+
+#if defined(FF_TABLES)
+
+#define gf_inv(x)   ((x) ? pow[ 255 - log[x]] : 0)
+
+#else 
+
+/*  It will generally be sensible to use tables to compute finite
+    field multiplies and inverses but where memory is scarse this
+    code might sometimes be better. But it only has effect during
+    initialisation so its pretty unimportant in overall terms.
+*/
+
+/*  return 2 ^ (n - 1) where n is the bit number of the highest bit
+    set in x with x in the range 1 < x < 0x00000200.   This form is
+    used so that locals within fi can be bytes rather than words
+*/
+
+static uint_8t hibit(const uint_32t x)
+{   uint_8t r = (uint_8t)((x >> 1) | (x >> 2));
+
+    r |= (r >> 2);
+    r |= (r >> 4);
+    return (r + 1) >> 1;
+}
+
+/* return the inverse of the finite field element x */
+
+static uint_8t gf_inv(const uint_8t x)
+{   uint_8t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0;
+
+    if(x < 2) 
+        return x;
+
+    for( ; ; )
+    {
+        if(n1)
+            while(n2 >= n1)             /* divide polynomial p2 by p1    */
+            {
+                n2 /= n1;               /* shift smaller polynomial left */ 
+                p2 ^= (p1 * n2) & 0xff; /* and remove from larger one    */
+                v2 ^= v1 * n2;          /* shift accumulated value and   */ 
+                n2 = hibit(p2);         /* add into result               */
+            }
+        else
+            return v1;
+
+        if(n2)                          /* repeat with values swapped    */ 
+            while(n1 >= n2)
+            {
+                n1 /= n2; 
+                p1 ^= p2 * n1; 
+                v1 ^= v2 * n1; 
+                n1 = hibit(p1);
+            }
+        else
+            return v2;
+    }
+}
+
+#endif
+
+/* The forward and inverse affine transformations used in the S-box */
+uint_8t fwd_affine(const uint_8t x)
+{   uint_32t w = x;
+    w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4);
+    return 0x63 ^ ((w ^ (w >> 8)) & 0xff);
+}
+
+uint_8t inv_affine(const uint_8t x)
+{   uint_32t w = x;
+    w = (w << 1) ^ (w << 3) ^ (w << 6);
+    return 0x05 ^ ((w ^ (w >> 8)) & 0xff);
+}
+
+static int init = 0;
+
+AES_RETURN aes_init(void)
+{   uint_32t  i, w;
+
+#if defined(FF_TABLES)
+
+    uint_8t  pow[512], log[256];
+
+    if(init)
+        return EXIT_SUCCESS;
+    /*  log and power tables for GF(2^8) finite field with
+        WPOLY as modular polynomial - the simplest primitive
+        root is 0x03, used here to generate the tables
+    */
+
+    i = 0; w = 1;
+    do
+    {
+        pow[i] = (uint_8t)w;
+        pow[i + 255] = (uint_8t)w;
+        log[w] = (uint_8t)i++;
+        w ^=  (w << 1) ^ (w & 0x80 ? WPOLY : 0);
+    }
+    while (w != 1);
+
+#else
+    if(init)
+        return EXIT_SUCCESS;
+#endif
+
+    for(i = 0, w = 1; i < RC_LENGTH; ++i)
+    {
+        t_set(r,c)[i] = bytes2word(w, 0, 0, 0);
+        w = f2(w);
+    }
+
+    for(i = 0; i < 256; ++i)
+    {   uint_8t    b;
+
+        b = fwd_affine(gf_inv((uint_8t)i));
+        w = bytes2word(f2(b), b, b, f3(b));
+
+#if defined( SBX_SET )
+        t_set(s,box)[i] = b;
+#endif
+
+#if defined( FT1_SET )                 /* tables for a normal encryption round */
+        t_set(f,n)[i] = w;
+#endif
+#if defined( FT4_SET )
+        t_set(f,n)[0][i] = w;
+        t_set(f,n)[1][i] = upr(w,1);
+        t_set(f,n)[2][i] = upr(w,2);
+        t_set(f,n)[3][i] = upr(w,3);
+#endif
+        w = bytes2word(b, 0, 0, 0);
+
+#if defined( FL1_SET )            /* tables for last encryption round (may also   */
+        t_set(f,l)[i] = w;        /* be used in the key schedule)                 */
+#endif
+#if defined( FL4_SET )
+        t_set(f,l)[0][i] = w;
+        t_set(f,l)[1][i] = upr(w,1);
+        t_set(f,l)[2][i] = upr(w,2);
+        t_set(f,l)[3][i] = upr(w,3);
+#endif
+
+#if defined( LS1_SET )			/* table for key schedule if t_set(f,l) above is*/
+        t_set(l,s)[i] = w;      /* not of the required form                     */
+#endif
+#if defined( LS4_SET )
+        t_set(l,s)[0][i] = w;
+        t_set(l,s)[1][i] = upr(w,1);
+        t_set(l,s)[2][i] = upr(w,2);
+        t_set(l,s)[3][i] = upr(w,3);
+#endif
+
+        b = gf_inv(inv_affine((uint_8t)i));
+        w = bytes2word(fe(b), f9(b), fd(b), fb(b));
+
+#if defined( IM1_SET )			/* tables for the inverse mix column operation  */
+        t_set(i,m)[b] = w;
+#endif
+#if defined( IM4_SET )
+        t_set(i,m)[0][b] = w;
+        t_set(i,m)[1][b] = upr(w,1);
+        t_set(i,m)[2][b] = upr(w,2);
+        t_set(i,m)[3][b] = upr(w,3);
+#endif
+
+#if defined( ISB_SET )
+        t_set(i,box)[i] = b;
+#endif
+#if defined( IT1_SET )			/* tables for a normal decryption round */
+        t_set(i,n)[i] = w;
+#endif
+#if defined( IT4_SET )
+        t_set(i,n)[0][i] = w;
+        t_set(i,n)[1][i] = upr(w,1);
+        t_set(i,n)[2][i] = upr(w,2);
+        t_set(i,n)[3][i] = upr(w,3);
+#endif
+        w = bytes2word(b, 0, 0, 0);
+#if defined( IL1_SET )			/* tables for last decryption round */
+        t_set(i,l)[i] = w;
+#endif
+#if defined( IL4_SET )
+        t_set(i,l)[0][i] = w;
+        t_set(i,l)[1][i] = upr(w,1);
+        t_set(i,l)[2][i] = upr(w,2);
+        t_set(i,l)[3][i] = upr(w,3);
+#endif
+    }
+    init = 1;
+    return EXIT_SUCCESS;
+}
+
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+
diff --git a/cbits/gladman/aestab.h b/cbits/gladman/aestab.h
new file mode 100644
--- /dev/null
+++ b/cbits/gladman/aestab.h
@@ -0,0 +1,180 @@
+/*
+ ---------------------------------------------------------------------------
+ Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
+
+ LICENSE TERMS
+
+ The redistribution and use of this software (with or without changes)
+ is allowed without the payment of fees or royalties provided that:
+
+  1. source code distributions include the above copyright notice, this
+     list of conditions and the following disclaimer;
+
+  2. binary distributions include the above copyright notice, this list
+     of conditions and the following disclaimer in their documentation;
+
+  3. the name of the copyright holder is not used to endorse products
+     built using this software without specific written permission.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ ---------------------------------------------------------------------------
+ Issue Date: 20/12/2007
+
+ This file contains the code for declaring the tables needed to implement
+ AES. The file aesopt.h is assumed to be included before this header file.
+ If there are no global variables, the definitions here can be used to put
+ the AES tables in a structure so that a pointer can then be added to the
+ AES context to pass them to the AES routines that need them.   If this
+ facility is used, the calling program has to ensure that this pointer is
+ managed appropriately.  In particular, the value of the t_dec(in,it) item
+ in the table structure must be set to zero in order to ensure that the
+ tables are initialised. In practice the three code sequences in aeskey.c
+ that control the calls to aes_init() and the aes_init() routine itself will
+ have to be changed for a specific implementation. If global variables are
+ available it will generally be preferable to use them with the precomputed
+ FIXED_TABLES option that uses static global tables.
+
+ The following defines can be used to control the way the tables
+ are defined, initialised and used in embedded environments that
+ require special features for these purposes
+
+    the 't_dec' construction is used to declare fixed table arrays
+    the 't_set' construction is used to set fixed table values
+    the 't_use' construction is used to access fixed table values
+
+    256 byte tables:
+
+        t_xxx(s,box)    => forward S box
+        t_xxx(i,box)    => inverse S box
+
+    256 32-bit word OR 4 x 256 32-bit word tables:
+
+        t_xxx(f,n)      => forward normal round
+        t_xxx(f,l)      => forward last round
+        t_xxx(i,n)      => inverse normal round
+        t_xxx(i,l)      => inverse last round
+        t_xxx(l,s)      => key schedule table
+        t_xxx(i,m)      => key schedule table
+
+    Other variables and tables:
+
+        t_xxx(r,c)      => the rcon table
+*/
+
+#if !defined( _AESTAB_H )
+#define _AESTAB_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#define t_dec(m,n) t_##m##n
+#define t_set(m,n) t_##m##n
+#define t_use(m,n) t_##m##n
+
+#if defined(FIXED_TABLES)
+#  if !defined( __GNUC__ ) && (defined( __MSDOS__ ) || defined( __WIN16__ ))
+/*   make tables far data to avoid using too much DGROUP space (PG) */
+#    define CONST const far
+#  else
+#    define CONST const
+#  endif
+#else
+#  define CONST
+#endif
+
+#if defined(DO_TABLES)
+#  define EXTERN
+#else
+#  define EXTERN extern
+#endif
+
+#if defined(_MSC_VER) && defined(TABLE_ALIGN)
+#define ALIGN __declspec(align(TABLE_ALIGN))
+#else
+#define ALIGN
+#endif
+
+#if defined( __WATCOMC__ ) && ( __WATCOMC__ >= 1100 )
+#  define XP_DIR __cdecl
+#else
+#  define XP_DIR
+#endif
+
+#if defined(DO_TABLES) && defined(FIXED_TABLES)
+#define d_1(t,n,b,e)       EXTERN ALIGN CONST XP_DIR t n[256]    =   b(e)
+#define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256] = { b(e), b(f), b(g), b(h) }
+EXTERN ALIGN CONST uint_32t t_dec(r,c)[RC_LENGTH] = rc_data(w0);
+#else
+#define d_1(t,n,b,e)       EXTERN ALIGN CONST XP_DIR t n[256]
+#define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256]
+EXTERN ALIGN CONST uint_32t t_dec(r,c)[RC_LENGTH];
+#endif
+
+#if defined( SBX_SET )
+    d_1(uint_8t, t_dec(s,box), sb_data, h0);
+#endif
+#if defined( ISB_SET )
+    d_1(uint_8t, t_dec(i,box), isb_data, h0);
+#endif
+
+#if defined( FT1_SET )
+    d_1(uint_32t, t_dec(f,n), sb_data, u0);
+#endif
+#if defined( FT4_SET )
+    d_4(uint_32t, t_dec(f,n), sb_data, u0, u1, u2, u3);
+#endif
+
+#if defined( FL1_SET )
+    d_1(uint_32t, t_dec(f,l), sb_data, w0);
+#endif
+#if defined( FL4_SET )
+    d_4(uint_32t, t_dec(f,l), sb_data, w0, w1, w2, w3);
+#endif
+
+#if defined( IT1_SET )
+    d_1(uint_32t, t_dec(i,n), isb_data, v0);
+#endif
+#if defined( IT4_SET )
+    d_4(uint_32t, t_dec(i,n), isb_data, v0, v1, v2, v3);
+#endif
+
+#if defined( IL1_SET )
+    d_1(uint_32t, t_dec(i,l), isb_data, w0);
+#endif
+#if defined( IL4_SET )
+    d_4(uint_32t, t_dec(i,l), isb_data, w0, w1, w2, w3);
+#endif
+
+#if defined( LS1_SET )
+#if defined( FL1_SET )
+#undef  LS1_SET
+#else
+    d_1(uint_32t, t_dec(l,s), sb_data, w0);
+#endif
+#endif
+
+#if defined( LS4_SET )
+#if defined( FL4_SET )
+#undef  LS4_SET
+#else
+    d_4(uint_32t, t_dec(l,s), sb_data, w0, w1, w2, w3);
+#endif
+#endif
+
+#if defined( IM1_SET )
+    d_1(uint_32t, t_dec(i,m), mm_data, v0);
+#endif
+#if defined( IM4_SET )
+    d_4(uint_32t, t_dec(i,m), mm_data, v0, v1, v2, v3);
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/cbits/gladman/brg_endian.h b/cbits/gladman/brg_endian.h
new file mode 100644
--- /dev/null
+++ b/cbits/gladman/brg_endian.h
@@ -0,0 +1,133 @@
+/*
+ ---------------------------------------------------------------------------
+ Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
+
+ LICENSE TERMS
+
+ The redistribution and use of this software (with or without changes)
+ is allowed without the payment of fees or royalties provided that:
+
+  1. source code distributions include the above copyright notice, this
+     list of conditions and the following disclaimer;
+
+  2. binary distributions include the above copyright notice, this list
+     of conditions and the following disclaimer in their documentation;
+
+  3. the name of the copyright holder is not used to endorse products
+     built using this software without specific written permission.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ ---------------------------------------------------------------------------
+ Issue Date: 20/12/2007
+*/
+
+#ifndef _BRG_ENDIAN_H
+#define _BRG_ENDIAN_H
+
+#define IS_BIG_ENDIAN      4321 /* byte 0 is most significant (mc68k) */
+#define IS_LITTLE_ENDIAN   1234 /* byte 0 is least significant (i386) */
+
+/* Include files where endian defines and byteswap functions may reside */
+#if defined( __sun )
+#  include <sys/isa_defs.h>
+#elif defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __NetBSD__ )
+#  include <sys/endian.h>
+#elif defined( BSD ) && ( BSD >= 199103 ) || defined( __APPLE__ ) || \
+      defined( __CYGWIN32__ ) || defined( __DJGPP__ ) || defined( __osf__ )
+#  include <machine/endian.h>
+#elif defined( __linux__ ) || defined( __GNUC__ ) || defined( __GNU_LIBRARY__ )
+#  if !defined( __MINGW32__ ) && !defined( _AIX )
+#    include <endian.h>
+#    if !defined( __BEOS__ )
+#      include <byteswap.h>
+#    endif
+#  endif
+#endif
+
+/* Now attempt to set the define for platform byte order using any  */
+/* of the four forms SYMBOL, _SYMBOL, __SYMBOL & __SYMBOL__, which  */
+/* seem to encompass most endian symbol definitions                 */
+
+#if defined( BIG_ENDIAN ) && defined( LITTLE_ENDIAN )
+#  if defined( BYTE_ORDER ) && BYTE_ORDER == BIG_ENDIAN
+#    define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
+#  elif defined( BYTE_ORDER ) && BYTE_ORDER == LITTLE_ENDIAN
+#    define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
+#  endif
+#elif defined( BIG_ENDIAN )
+#  define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
+#elif defined( LITTLE_ENDIAN )
+#  define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
+#endif
+
+#if defined( _BIG_ENDIAN ) && defined( _LITTLE_ENDIAN )
+#  if defined( _BYTE_ORDER ) && _BYTE_ORDER == _BIG_ENDIAN
+#    define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
+#  elif defined( _BYTE_ORDER ) && _BYTE_ORDER == _LITTLE_ENDIAN
+#    define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
+#  endif
+#elif defined( _BIG_ENDIAN )
+#  define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
+#elif defined( _LITTLE_ENDIAN )
+#  define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
+#endif
+
+#if defined( __BIG_ENDIAN ) && defined( __LITTLE_ENDIAN )
+#  if defined( __BYTE_ORDER ) && __BYTE_ORDER == __BIG_ENDIAN
+#    define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
+#  elif defined( __BYTE_ORDER ) && __BYTE_ORDER == __LITTLE_ENDIAN
+#    define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
+#  endif
+#elif defined( __BIG_ENDIAN )
+#  define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
+#elif defined( __LITTLE_ENDIAN )
+#  define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
+#endif
+
+#if defined( __BIG_ENDIAN__ ) && defined( __LITTLE_ENDIAN__ )
+#  if defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __BIG_ENDIAN__
+#    define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
+#  elif defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __LITTLE_ENDIAN__
+#    define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
+#  endif
+#elif defined( __BIG_ENDIAN__ )
+#  define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
+#elif defined( __LITTLE_ENDIAN__ )
+#  define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
+#endif
+
+/*  if the platform byte order could not be determined, then try to */
+/*  set this define using common machine defines                    */
+#if !defined(PLATFORM_BYTE_ORDER)
+
+#if   defined( __alpha__ ) || defined( __alpha ) || defined( i386 )       || \
+      defined( __i386__ )  || defined( _M_I86 )  || defined( _M_IX86 )    || \
+      defined( __OS2__ )   || defined( sun386 )  || defined( __TURBOC__ ) || \
+      defined( vax )       || defined( vms )     || defined( VMS )        || \
+      defined( __VMS )     || defined( _M_X64 )
+#  define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
+
+#elif defined( AMIGA )   || defined( applec )    || defined( __AS400__ )  || \
+      defined( _CRAY )   || defined( __hppa )    || defined( __hp9000 )   || \
+      defined( ibm370 )  || defined( mc68000 )   || defined( m68k )       || \
+      defined( __MRC__ ) || defined( __MVS__ )   || defined( __MWERKS__ ) || \
+      defined( sparc )   || defined( __sparc)    || defined( SYMANTEC_C ) || \
+      defined( __VOS__ ) || defined( __TIGCC__ ) || defined( __TANDEM )   || \
+      defined( THINK_C ) || defined( __VMCMS__ ) || defined( _AIX )
+#  define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
+
+#elif 0     /* **** EDIT HERE IF NECESSARY **** */
+#  define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
+#elif 0     /* **** EDIT HERE IF NECESSARY **** */
+#  define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
+#else
+#  error Please edit lines 126 or 128 in brg_endian.h to set the platform byte order
+#endif
+
+#endif
+
+#endif
diff --git a/cbits/gladman/brg_types.h b/cbits/gladman/brg_types.h
new file mode 100644
--- /dev/null
+++ b/cbits/gladman/brg_types.h
@@ -0,0 +1,226 @@
+/*
+ ---------------------------------------------------------------------------
+ Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
+
+ LICENSE TERMS
+
+ The redistribution and use of this software (with or without changes)
+ is allowed without the payment of fees or royalties provided that:
+
+  1. source code distributions include the above copyright notice, this
+     list of conditions and the following disclaimer;
+
+  2. binary distributions include the above copyright notice, this list
+     of conditions and the following disclaimer in their documentation;
+
+  3. the name of the copyright holder is not used to endorse products
+     built using this software without specific written permission.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ ---------------------------------------------------------------------------
+ Issue Date: 20/12/2007
+
+ The unsigned integer types defined here are of the form uint_<nn>t where
+ <nn> is the length of the type; for example, the unsigned 32-bit type is
+ 'uint_32t'.  These are NOT the same as the 'C99 integer types' that are
+ defined in the inttypes.h and stdint.h headers since attempts to use these
+ types have shown that support for them is still highly variable.  However,
+ since the latter are of the form uint<nn>_t, a regular expression search
+ and replace (in VC++ search on 'uint_{:z}t' and replace with 'uint\1_t')
+ can be used to convert the types used here to the C99 standard types.
+*/
+
+#ifndef _BRG_TYPES_H
+#define _BRG_TYPES_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#include <limits.h>
+
+#if defined( _MSC_VER ) && ( _MSC_VER >= 1300 )
+#  include <stddef.h>
+#  define ptrint_t intptr_t
+#elif defined( __ECOS__ )
+#  define intptr_t unsigned int
+#  define ptrint_t intptr_t
+#elif defined( __GNUC__ ) && ( __GNUC__ >= 3 )
+#  include <stdint.h>
+#  define ptrint_t intptr_t
+#else
+#  define ptrint_t int
+#endif
+
+#ifndef BRG_UI8
+#  define BRG_UI8
+#  if UCHAR_MAX == 255u
+     typedef unsigned char uint_8t;
+#  else
+#    error Please define uint_8t as an 8-bit unsigned integer type in brg_types.h
+#  endif
+#endif
+
+#ifndef BRG_UI16
+#  define BRG_UI16
+#  if USHRT_MAX == 65535u
+     typedef unsigned short uint_16t;
+#  else
+#    error Please define uint_16t as a 16-bit unsigned short type in brg_types.h
+#  endif
+#endif
+
+#ifndef BRG_UI32
+#  define BRG_UI32
+#  if UINT_MAX == 4294967295u
+#    define li_32(h) 0x##h##u
+     typedef unsigned int uint_32t;
+#  elif ULONG_MAX == 4294967295u
+#    define li_32(h) 0x##h##ul
+     typedef unsigned long uint_32t;
+#  elif defined( _CRAY )
+#    error This code needs 32-bit data types, which Cray machines do not provide
+#  else
+#    error Please define uint_32t as a 32-bit unsigned integer type in brg_types.h
+#  endif
+#endif
+
+#ifndef BRG_UI64
+#  if defined( __BORLANDC__ ) && !defined( __MSDOS__ )
+#    define BRG_UI64
+#    define li_64(h) 0x##h##ui64
+     typedef unsigned __int64 uint_64t;
+#  elif defined( _MSC_VER ) && ( _MSC_VER < 1300 )    /* 1300 == VC++ 7.0 */
+#    define BRG_UI64
+#    define li_64(h) 0x##h##ui64
+     typedef unsigned __int64 uint_64t;
+#  elif defined( __sun ) && defined( ULONG_MAX ) && ULONG_MAX == 0xfffffffful
+#    define BRG_UI64
+#    define li_64(h) 0x##h##ull
+     typedef unsigned long long uint_64t;
+#  elif defined( __MVS__ )
+#    define BRG_UI64
+#    define li_64(h) 0x##h##ull
+     typedef unsigned int long long uint_64t;
+#  elif defined( UINT_MAX ) && UINT_MAX > 4294967295u
+#    if UINT_MAX == 18446744073709551615u
+#      define BRG_UI64
+#      define li_64(h) 0x##h##u
+       typedef unsigned int uint_64t;
+#    endif
+#  elif defined( ULONG_MAX ) && ULONG_MAX > 4294967295u
+#    if ULONG_MAX == 18446744073709551615ul
+#      define BRG_UI64
+#      define li_64(h) 0x##h##ul
+       typedef unsigned long uint_64t;
+#    endif
+#  elif defined( ULLONG_MAX ) && ULLONG_MAX > 4294967295u
+#    if ULLONG_MAX == 18446744073709551615ull
+#      define BRG_UI64
+#      define li_64(h) 0x##h##ull
+       typedef unsigned long long uint_64t;
+#    endif
+#  elif defined( ULONG_LONG_MAX ) && ULONG_LONG_MAX > 4294967295u
+#    if ULONG_LONG_MAX == 18446744073709551615ull
+#      define BRG_UI64
+#      define li_64(h) 0x##h##ull
+       typedef unsigned long long uint_64t;
+#    endif
+#  endif
+#endif
+
+#if !defined( BRG_UI64 )
+#  if defined( NEED_UINT_64T )
+#    error Please define uint_64t as an unsigned 64 bit type in brg_types.h
+#  endif
+#endif
+
+#ifndef RETURN_VALUES
+#  define RETURN_VALUES
+#  if defined( DLL_EXPORT )
+#    if defined( _MSC_VER ) || defined ( __INTEL_COMPILER )
+#      define VOID_RETURN    __declspec( dllexport ) void __stdcall
+#      define INT_RETURN     __declspec( dllexport ) int  __stdcall
+#    elif defined( __GNUC__ )
+#      define VOID_RETURN    __declspec( __dllexport__ ) void
+#      define INT_RETURN     __declspec( __dllexport__ ) int
+#    else
+#      error Use of the DLL is only available on the Microsoft, Intel and GCC compilers
+#    endif
+#  elif defined( DLL_IMPORT )
+#    if defined( _MSC_VER ) || defined ( __INTEL_COMPILER )
+#      define VOID_RETURN    __declspec( dllimport ) void __stdcall
+#      define INT_RETURN     __declspec( dllimport ) int  __stdcall
+#    elif defined( __GNUC__ )
+#      define VOID_RETURN    __declspec( __dllimport__ ) void
+#      define INT_RETURN     __declspec( __dllimport__ ) int
+#    else
+#      error Use of the DLL is only available on the Microsoft, Intel and GCC compilers
+#    endif
+#  elif defined( __WATCOMC__ )
+#    define VOID_RETURN  void __cdecl
+#    define INT_RETURN   int  __cdecl
+#  else
+#    define VOID_RETURN  void
+#    define INT_RETURN   int
+#  endif
+#endif
+
+/*	These defines are used to detect and set the memory alignment of pointers.
+    Note that offsets are in bytes.
+
+	ALIGN_OFFSET(x,n)			return the positive or zero offset of 
+								the memory addressed by the pointer 'x' 
+								from an address that is aligned on an 
+								'n' byte boundary ('n' is a power of 2)
+
+	ALIGN_FLOOR(x,n)			return a pointer that points to memory
+								that is aligned on an 'n' byte boundary 
+								and is not higher than the memory address
+								pointed to by 'x' ('n' is a power of 2)
+
+	ALIGN_CEIL(x,n)				return a pointer that points to memory
+								that is aligned on an 'n' byte boundary 
+								and is not lower than the memory address
+								pointed to by 'x' ('n' is a power of 2)
+*/
+
+#define ALIGN_OFFSET(x,n)	(((ptrint_t)(x)) & ((n) - 1))
+#define ALIGN_FLOOR(x,n)	((uint_8t*)(x) - ( ((ptrint_t)(x)) & ((n) - 1)))
+#define ALIGN_CEIL(x,n)		((uint_8t*)(x) + (-((ptrint_t)(x)) & ((n) - 1)))
+
+/*  These defines are used to declare buffers in a way that allows
+    faster operations on longer variables to be used.  In all these
+    defines 'size' must be a power of 2 and >= 8. NOTE that the 
+    buffer size is in bytes but the type length is in bits
+
+    UNIT_TYPEDEF(x,size)        declares a variable 'x' of length 
+                                'size' bits
+
+    BUFR_TYPEDEF(x,size,bsize)  declares a buffer 'x' of length 'bsize' 
+                                bytes defined as an array of variables
+                                each of 'size' bits (bsize must be a 
+                                multiple of size / 8)
+
+    UNIT_CAST(x,size)           casts a variable to a type of 
+                                length 'size' bits
+
+    UPTR_CAST(x,size)           casts a pointer to a pointer to a 
+                                varaiable of length 'size' bits
+*/
+
+#define UI_TYPE(size)               uint_##size##t
+#define UNIT_TYPEDEF(x,size)        typedef UI_TYPE(size) x
+#define BUFR_TYPEDEF(x,size,bsize)  typedef UI_TYPE(size) x[bsize / (size >> 3)]
+#define UNIT_CAST(x,size)           ((UI_TYPE(size) )(x))  
+#define UPTR_CAST(x,size)           ((UI_TYPE(size)*)(x))
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/cbits/gladman/ctr_inc.c b/cbits/gladman/ctr_inc.c
new file mode 100644
--- /dev/null
+++ b/cbits/gladman/ctr_inc.c
@@ -0,0 +1,17 @@
+#include "brg_types.h"
+#include "aesopt.h"
+#include "ctr_inc.h"
+#include <stdio.h>
+
+#if AES_BLOCK_SIZE != 16
+# error AES block size wrong ?!
+#endif
+
+void ctr_inc(unsigned char *cbuf) {
+  uint_64t *ctr = (uint_64t*)cbuf;
+  int word;
+  for (word = 0; word < 2; word++) {
+    ctr[word]++;
+    if (ctr[word]) break;
+  }
+}
diff --git a/cbits/gladman/ctr_inc.h b/cbits/gladman/ctr_inc.h
new file mode 100644
--- /dev/null
+++ b/cbits/gladman/ctr_inc.h
@@ -0,0 +1,1 @@
+void ctr_inc(unsigned char *);
diff --git a/intel-aes.cabal b/intel-aes.cabal
new file mode 100644
--- /dev/null
+++ b/intel-aes.cabal
@@ -0,0 +1,126 @@
+Name:           intel-aes
+Version:        0.1.1
+
+License:                BSD3
+License-file:           LICENSE
+Stability:              Beta
+Maintainer:		Ryan Newton <rrnewton@gmail.com>
+Author:			Ryan Newton <rrnewton@gmail.com>, Svein Ove Aas <svein.ove@aas.no>, Thomas M. DuBuisson
+Copyright:              Copyright (c) 2011 Intel Corporation
+Synopsis:               Hardware accelerated AES encryption and RNG.
+Description: 
+  AES encryption with optional hardware acceleration.  Plus,
+  statistically sound, splittable random number generation based on AES.
+
+  The package is nothing more than a wrapper around the following Intel-provided AESNI
+  sample library that also includes a portable software implementation by Brian Gladman:
+
+    http://software.intel.com/en-us/articles/download-the-intel-aesni-sample-library/
+
+  The consists of C, assembly sources, and Haskell sources.  It
+  includes prebuilt dynamic libraries for these sources to make the
+  build process less fragile.  (Rebuilding requires the @yasm@
+  assembler.)  But prebuilt shared libraries are not included for all
+  platforms yet.  (Volunteers needed!)
+
+  Regarding portability, see:
+
+    https://github.com/rrnewton/intel-aes/issues/#issue/1
+
+  Finally, note that this package is currently triggering some haddock
+  problems. A manually built copy of the documentation can be found
+  at:
+
+    http://people.csail.mit.edu/newton/intel-aes-doc/
+
+-- Here are some example results from an Intel X5680 processor.
+
+--  How many random numbers can we generate in a second on one thread?
+-- 	  First, timing with System.Random interface:
+-- 	     14,482,725 random ints generated [System.Random stdGen]    
+-- 		 16,061 random ints generated [PureHaskell/reference]   
+-- 		 32,309 random ints generated [PureHaskell]             
+-- 	      2,401,893 random ints generated [Gladman inefficient]     
+-- 	     15,980,625 random ints generated [Gladman]                 
+-- 	      2,329,500 random ints generated [IntelAES inefficient]    
+-- 	     32,383,799 random ints generated [IntelAES]                
+-- 	 Comparison to C's rand():
+-- 	     71,347,778 random ints generated [rand in Haskell loop]    
+
+
+
+Category: Cryptography
+Cabal-Version: >=1.8
+Tested-With: GHC == 7.0.1
+-- Portability:            Untested on Windows.
+
+build-type: Custom
+
+extra-source-files:
+      cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/Makefile
+    , cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/asm/x64/do_rdtsc.s
+    , cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/asm/x64/iaesx64.s
+    , cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/asm/x86/do_rdtsc.s
+    , cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/asm/x86/iaesx86.s
+    , cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/include/iaes_asm_interface.h
+    , cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/include/iaesni.h
+    , cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/mk_lnx_lib.sh
+    , cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/mk_win_lib.bat
+    , cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/src/aessample.c
+    , cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/src/aessampletiming.cpp
+    , cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/src/intel_aes.c
+    , cbits/Intel_AESNI_Sample_Library_v1.0/intel_aes_lib/where_files_come_from_and_license.txt
+    , cbits/Makefile
+    , cbits/c_test.c
+
+    -- Including the gladman implementation for now as well:
+    , cbits/gladman/aes.h, cbits/gladman/aesopt.h, cbits/gladman/aestab.h
+    , cbits/gladman/brg_endian.h, cbits/gladman/brg_types.h, cbits/gladman/aes.txt
+    , cbits/gladman/aes_via_ace.h, cbits/gladman/ctr_inc.h
+
+
+source-repository head
+  type:     git
+  location: git://github.com/rrnewton/intel-aes.git
+
+
+----------------------------------------------------------------------------------------------------
+library
+  build-depends:  base >= 4 && < 5, random, DRBG, split, process, haskell98, time,
+                  DRBG, crypto-api, bytestring, cereal, tagged
+
+  exposed-modules:  Codec.Encryption.BurtonRNGSlow
+                 ,  Codec.Crypto.IntelAES
+                 ,  Codec.Crypto.IntelAES.AESNI
+                 ,  Codec.Crypto.ConvertRNG
+--                 ,  Codec.Crypto.IntelAES.GladmanAES
+                 ,  Codec.Crypto.GladmanAES
+  other-modules:    Data.LargeWord 
+                 ,  Benchmark.BinSearch
+                 ,  Codec.Encryption.AES
+                 ,  Codec.Encryption.AESAux
+                 ,  Codec.Utils
+  GHC-Options: -O2 
+  extra-libraries: intel_aes
+
+  -- The gladman sources are straightforward and can be built by Cabal (unlike the intel C/asm)
+  C-sources: cbits/gladman/aescrypt.c, cbits/gladman/aeskey.c, cbits/gladman/aestab.c,
+             cbits/gladman/aes_modes.c, cbits/gladman/ctr_inc.c
+  Include-Dirs: cbits
+
+
+
+-- ----------------------------------------------------------------------------------------------------
+Executable benchmark-intel-aes-rng
+  Main-is:        SimpleRNGBench.hs
+  Build-Depends:  base >= 4 && < 5, split, rdtsc, unix, random, crypto-api, DRBG
+                , tagged, cereal, bytestring, process, haskell98, time
+--                , AES
+                , intel-aes
+  GHC-Options:    -O2 -threaded -rtsopts 
+  C-sources:	   cbits/c_test.c
+  Include-dirs:    cbits
+
+
+
+--  cabal haddock --hoogle --executables --hyperlink-source --haddock-options="--html"
