packages feed

clientsession 0.3.0 → 0.4.0

raw patch · 5 files changed

+719/−74 lines, 5 filesdep +QuickCheckdep +randomdep +test-frameworkdep −SimpleAESdep −binarydep −dataencnew-component:exe:runtestsPVP ok

version bump matches the API change (PVP)

Dependencies added: QuickCheck, random, test-framework, test-framework-quickcheck2

Dependencies removed: SimpleAES, binary, dataenc, failure, pureMD5

API changes (from Hackage documentation)

- Web.ClientSession: InvalidBase64 :: String -> ClientSessionException
- Web.ClientSession: InvalidHash :: String -> ClientSessionException
- Web.ClientSession: KeyTooSmall :: ByteString -> ClientSessionException
- Web.ClientSession: MismatchedHash :: ByteString -> ByteString -> ClientSessionException
- Web.ClientSession: actualHash :: ClientSessionException -> ByteString
- Web.ClientSession: data ClientSessionException
- Web.ClientSession: expectedHash :: ClientSessionException -> ByteString
- Web.ClientSession: instance Eq ClientSessionException
- Web.ClientSession: instance Exception ClientSessionException
- Web.ClientSession: instance Show ClientSessionException
- Web.ClientSession: instance Typeable ClientSessionException
+ Web.ClientSession: type Key = ByteString
- Web.ClientSession: decrypt :: (Monad m, Failure ClientSessionException m) => Key -> String -> m ByteString
+ Web.ClientSession: decrypt :: ByteString -> ByteString -> Maybe ByteString
- Web.ClientSession: encrypt :: Key -> ByteString -> IO (String)
+ Web.ClientSession: encrypt :: ByteString -> ByteString -> ByteString

Files

Web/ClientSession.hs view
@@ -1,6 +1,5 @@ {-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE ForeignFunctionInterface #-} --------------------------------------------------------- -- -- Module        : Web.ClientSession@@ -16,97 +15,113 @@ --------------------------------------------------------- module Web.ClientSession     ( -- * Automatic key generation-      getKey+      Key+    , getKey     , defaultKeyFile     , getDefaultKey       -- * Actual encryption/decryption     , encrypt     , decrypt-      -- * Exceptions-    , ClientSessionException (..)     ) where -import Codec.Crypto.SimpleAES-import Control.Failure-import Control.Monad (unless)--import qualified Codec.Crypto.SimpleAES as AES-import qualified Codec.Binary.Base64Url as Base64-import qualified Data.Digest.Pure.MD5 as MD5+import System.Directory+import qualified Data.ByteString as S -import Data.Typeable (Typeable)-import Control.Exception+import System.Random -import System.Directory+import Data.ByteString.Unsafe -import qualified Data.ByteString as S-import qualified Data.ByteString.Lazy as L+import Foreign.C+import Foreign.Ptr+import Foreign.Marshal.Alloc+import Foreign.Storable+import System.IO.Unsafe -import Data.Binary+type Key = S.ByteString  -- | The default key file. defaultKeyFile :: String defaultKeyFile = "client_session_key.aes" --- | Simply calls 'getKey' \"client_session_key.aes\"-getDefaultKey :: IO AES.Key+-- | Simply calls 'getKey' 'defaultKeyFile'.+getDefaultKey :: IO Key getDefaultKey = getKey defaultKeyFile -data ClientSessionException =-      KeyTooSmall S.ByteString-    | InvalidBase64 String-    | InvalidHash String-    | MismatchedHash { expectedHash :: L.ByteString-                     , actualHash   :: L.ByteString-                     }-    deriving (Show, Typeable, Eq)-instance Exception ClientSessionException- -- | Get a key from the given text file. -- -- If the file does not exist a random key will be generated and stored in that -- file. getKey :: FilePath     -- ^ File name where key is stored.-       -> IO AES.Key   -- ^ The actual key.+       -> IO Key       -- ^ The actual key. getKey keyFile = do     exists <- doesFileExist keyFile     if exists-        then S.readFile keyFile-        else do-            key <- AES.randomKey-            S.writeFile keyFile key-            return key+        then do+            key <- S.readFile keyFile+            if S.length key < minKeyLength+                then newKey+                else return key+        else newKey+  where+    newKey = do+        key' <- randomKey+        S.writeFile keyFile key'+        return key' --- | Encrypt with the given key and base-64 encode.--- A hash is stored inside the encrypted key so that, upon decryption,--- integrity can be guaranteed.-encrypt :: AES.Key         -- ^ The key used for encryption.-        -> L.ByteString    -- ^ The data to encrypt.-        -> IO (String)     -- ^ Encrypted and encoded data.-encrypt k bs = do-    let withHash = encode (MD5.md5 bs) `L.append` bs-    encrypted <- AES.encryptMsg mode k withHash-    return $ Base64.encode $ L.unpack encrypted+minKeyLength :: Int+minKeyLength = 16 -mode :: AES.Mode-mode = ECB+randomKey :: IO Key+randomKey = do+    g <- newStdGen+    let (nums, _) =+            foldr+                (\_ (n, g') -> let (n', g'') = next g' in (n' : n, g''))+                ([], g)+                [1..minKeyLength]+    return $ S.pack $ map fromIntegral nums --- | Base-64 decode and decrypt with the given key, if possible.  Calls--- 'failure' if either the original string is not a valid base-64 encoded--- string, or the hash at the beginning of the decrypted string does not match.-decrypt :: (Monad m, Failure ClientSessionException m)-        => AES.Key              -- ^ The key used for encryption.-        -> String               -- ^ Data to decrypt.-        -> m L.ByteString       -- ^ The decrypted data, if possible.-decrypt k x = do-    decoded <- case Base64.decode x of-                    Nothing -> failure $ InvalidBase64 x-                    Just y -> return y-    decrypted <- case AES.decryptMsg' mode k $ L.pack decoded of-                    Left s -> failure $ InvalidHash s-                    Right z -> return z-    let (expected, rest) = L.splitAt 16 decrypted-    let actual = encode $ MD5.md5 rest-    unless (expected == actual) $ failure-                                $ MismatchedHash expected actual-    return rest+encrypt :: S.ByteString -- ^ key+        -> S.ByteString -- ^ data+        -> S.ByteString+encrypt keyBS dataBS = unsafePerformIO $+    unsafeUseAsCString keyBS $ \keyPtr ->+        unsafeUseAsCStringLen dataBS $ \(dataPtr, dataLen) -> do+            let keyPtr' = castPtr keyPtr+                dataPtr' = castPtr dataPtr+                dataLen' = fromIntegral dataLen+            allocaBytes 4 $ \lenp -> do+                newPtr <- c_encrypt dataLen' dataPtr' keyPtr' lenp+                let newPtr' = castPtr newPtr+                len <- peek lenp+                let len' = fromIntegral len+                unsafePackCStringFinalizer newPtr' len' $ free newPtr'++decrypt :: S.ByteString -- ^ key+        -> S.ByteString -- ^ data+        -> Maybe S.ByteString+decrypt keyBS dataBS = unsafePerformIO $+    unsafeUseAsCString keyBS $ \keyPtr ->+        unsafeUseAsCStringLen dataBS $ \(dataPtr, dataLen) -> do+            let keyPtr' = castPtr keyPtr+                dataPtr' = castPtr dataPtr+                dataLen' = fromIntegral dataLen+            allocaBytes 4 $ \lenp -> do+                newPtr <- c_decrypt dataLen' dataPtr' keyPtr' lenp+                if newPtr == nullPtr+                    then return Nothing+                    else do+                        let newPtr' = castPtr newPtr+                        len <- peek lenp+                        let len' = fromIntegral len+                        bs <- unsafePackCStringFinalizer newPtr' len'+                            $ free newPtr'+                        return $ Just bs++foreign import ccall unsafe "encrypt"+    c_encrypt :: CUInt -> Ptr CUChar -> Ptr CUChar -> Ptr CUInt+              -> IO (Ptr CChar)++foreign import ccall unsafe "decrypt"+    c_decrypt :: CUInt -> Ptr CChar -> Ptr CUChar -> Ptr CUInt+              -> IO (Ptr CUChar)
+ c/aestable.c view
@@ -0,0 +1,400 @@+// advanced encryption standard
+// author: karl malbrain, malbrain@yahoo.com
+/*
+This work, including the source code, documentation
+and related data, is placed into the public domain.
+
+The orginal author is Karl Malbrain.
+
+THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY
+OF ANY KIND, NOT EVEN THE IMPLIED WARRANTY OF
+MERCHANTABILITY. THE AUTHOR OF THIS SOFTWARE,
+ASSUMES _NO_ RESPONSIBILITY FOR ANY CONSEQUENCE
+RESULTING FROM THE USE, MODIFICATION, OR
+REDISTRIBUTION OF THIS SOFTWARE.
+*/
+
+typedef unsigned char uchar;
+#include <string.h>
+#include <memory.h>
+
+// AES only supports Nb=4
+#define Nb 4			// number of columns in the state & expanded key
+
+#define Nk 4			// number of columns in a key
+#define Nr 10			// number of rounds in encryption
+
+uchar Sbox[256] = {		// forward s-box
+0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
+0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
+0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
+0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
+0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
+0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
+0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
+0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
+0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
+0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
+0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16};
+
+uchar InvSbox[256] = {	// inverse s-box
+0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
+0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
+0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
+0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
+0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
+0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
+0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
+0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
+0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
+0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
+0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
+0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
+0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
+0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
+0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
+0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d};
+
+// combined Xtimes2[Sbox[]]
+uchar Xtime2Sbox[256] = {
+0xc6, 0xf8, 0xee, 0xf6, 0xff, 0xd6, 0xde, 0x91, 0x60, 0x02, 0xce, 0x56, 0xe7, 0xb5, 0x4d, 0xec, 
+0x8f, 0x1f, 0x89, 0xfa, 0xef, 0xb2, 0x8e, 0xfb, 0x41, 0xb3, 0x5f, 0x45, 0x23, 0x53, 0xe4, 0x9b, 
+0x75, 0xe1, 0x3d, 0x4c, 0x6c, 0x7e, 0xf5, 0x83, 0x68, 0x51, 0xd1, 0xf9, 0xe2, 0xab, 0x62, 0x2a, 
+0x08, 0x95, 0x46, 0x9d, 0x30, 0x37, 0x0a, 0x2f, 0x0e, 0x24, 0x1b, 0xdf, 0xcd, 0x4e, 0x7f, 0xea, 
+0x12, 0x1d, 0x58, 0x34, 0x36, 0xdc, 0xb4, 0x5b, 0xa4, 0x76, 0xb7, 0x7d, 0x52, 0xdd, 0x5e, 0x13, 
+0xa6, 0xb9, 0x00, 0xc1, 0x40, 0xe3, 0x79, 0xb6, 0xd4, 0x8d, 0x67, 0x72, 0x94, 0x98, 0xb0, 0x85, 
+0xbb, 0xc5, 0x4f, 0xed, 0x86, 0x9a, 0x66, 0x11, 0x8a, 0xe9, 0x04, 0xfe, 0xa0, 0x78, 0x25, 0x4b, 
+0xa2, 0x5d, 0x80, 0x05, 0x3f, 0x21, 0x70, 0xf1, 0x63, 0x77, 0xaf, 0x42, 0x20, 0xe5, 0xfd, 0xbf, 
+0x81, 0x18, 0x26, 0xc3, 0xbe, 0x35, 0x88, 0x2e, 0x93, 0x55, 0xfc, 0x7a, 0xc8, 0xba, 0x32, 0xe6, 
+0xc0, 0x19, 0x9e, 0xa3, 0x44, 0x54, 0x3b, 0x0b, 0x8c, 0xc7, 0x6b, 0x28, 0xa7, 0xbc, 0x16, 0xad, 
+0xdb, 0x64, 0x74, 0x14, 0x92, 0x0c, 0x48, 0xb8, 0x9f, 0xbd, 0x43, 0xc4, 0x39, 0x31, 0xd3, 0xf2, 
+0xd5, 0x8b, 0x6e, 0xda, 0x01, 0xb1, 0x9c, 0x49, 0xd8, 0xac, 0xf3, 0xcf, 0xca, 0xf4, 0x47, 0x10, 
+0x6f, 0xf0, 0x4a, 0x5c, 0x38, 0x57, 0x73, 0x97, 0xcb, 0xa1, 0xe8, 0x3e, 0x96, 0x61, 0x0d, 0x0f, 
+0xe0, 0x7c, 0x71, 0xcc, 0x90, 0x06, 0xf7, 0x1c, 0xc2, 0x6a, 0xae, 0x69, 0x17, 0x99, 0x3a, 0x27, 
+0xd9, 0xeb, 0x2b, 0x22, 0xd2, 0xa9, 0x07, 0x33, 0x2d, 0x3c, 0x15, 0xc9, 0x87, 0xaa, 0x50, 0xa5, 
+0x03, 0x59, 0x09, 0x1a, 0x65, 0xd7, 0x84, 0xd0, 0x82, 0x29, 0x5a, 0x1e, 0x7b, 0xa8, 0x6d, 0x2c 
+};
+
+// combined Xtimes3[Sbox[]]
+uchar Xtime3Sbox[256] = {
+0xa5, 0x84, 0x99, 0x8d, 0x0d, 0xbd, 0xb1, 0x54, 0x50, 0x03, 0xa9, 0x7d, 0x19, 0x62, 0xe6, 0x9a, 
+0x45, 0x9d, 0x40, 0x87, 0x15, 0xeb, 0xc9, 0x0b, 0xec, 0x67, 0xfd, 0xea, 0xbf, 0xf7, 0x96, 0x5b, 
+0xc2, 0x1c, 0xae, 0x6a, 0x5a, 0x41, 0x02, 0x4f, 0x5c, 0xf4, 0x34, 0x08, 0x93, 0x73, 0x53, 0x3f, 
+0x0c, 0x52, 0x65, 0x5e, 0x28, 0xa1, 0x0f, 0xb5, 0x09, 0x36, 0x9b, 0x3d, 0x26, 0x69, 0xcd, 0x9f, 
+0x1b, 0x9e, 0x74, 0x2e, 0x2d, 0xb2, 0xee, 0xfb, 0xf6, 0x4d, 0x61, 0xce, 0x7b, 0x3e, 0x71, 0x97, 
+0xf5, 0x68, 0x00, 0x2c, 0x60, 0x1f, 0xc8, 0xed, 0xbe, 0x46, 0xd9, 0x4b, 0xde, 0xd4, 0xe8, 0x4a, 
+0x6b, 0x2a, 0xe5, 0x16, 0xc5, 0xd7, 0x55, 0x94, 0xcf, 0x10, 0x06, 0x81, 0xf0, 0x44, 0xba, 0xe3, 
+0xf3, 0xfe, 0xc0, 0x8a, 0xad, 0xbc, 0x48, 0x04, 0xdf, 0xc1, 0x75, 0x63, 0x30, 0x1a, 0x0e, 0x6d, 
+0x4c, 0x14, 0x35, 0x2f, 0xe1, 0xa2, 0xcc, 0x39, 0x57, 0xf2, 0x82, 0x47, 0xac, 0xe7, 0x2b, 0x95, 
+0xa0, 0x98, 0xd1, 0x7f, 0x66, 0x7e, 0xab, 0x83, 0xca, 0x29, 0xd3, 0x3c, 0x79, 0xe2, 0x1d, 0x76, 
+0x3b, 0x56, 0x4e, 0x1e, 0xdb, 0x0a, 0x6c, 0xe4, 0x5d, 0x6e, 0xef, 0xa6, 0xa8, 0xa4, 0x37, 0x8b, 
+0x32, 0x43, 0x59, 0xb7, 0x8c, 0x64, 0xd2, 0xe0, 0xb4, 0xfa, 0x07, 0x25, 0xaf, 0x8e, 0xe9, 0x18, 
+0xd5, 0x88, 0x6f, 0x72, 0x24, 0xf1, 0xc7, 0x51, 0x23, 0x7c, 0x9c, 0x21, 0xdd, 0xdc, 0x86, 0x85, 
+0x90, 0x42, 0xc4, 0xaa, 0xd8, 0x05, 0x01, 0x12, 0xa3, 0x5f, 0xf9, 0xd0, 0x91, 0x58, 0x27, 0xb9, 
+0x38, 0x13, 0xb3, 0x33, 0xbb, 0x70, 0x89, 0xa7, 0xb6, 0x22, 0x92, 0x20, 0x49, 0xff, 0x78, 0x7a, 
+0x8f, 0xf8, 0x80, 0x17, 0xda, 0x31, 0xc6, 0xb8, 0xc3, 0xb0, 0x77, 0x11, 0xcb, 0xfc, 0xd6, 0x3a 
+};
+
+// modular multiplication tables
+// based on:
+
+// Xtime2[x] = (x & 0x80 ? 0x1b : 0) ^ (x + x)
+// Xtime3[x] = x^Xtime2[x];
+
+uchar Xtime2[256] = {
+0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 
+0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 
+0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 
+0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e, 
+0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e, 
+0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe, 
+0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 
+0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, 
+0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05, 
+0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25, 
+0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45, 
+0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65, 
+0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85, 
+0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5, 
+0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5, 
+0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5}; 
+
+uchar Xtime9[256] = {
+0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77, 
+0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7, 
+0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, 
+0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc, 
+0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01, 
+0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91, 
+0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28, 0x33, 0x3a, 
+0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa, 
+0xec, 0xe5, 0xfe, 0xf7, 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b, 
+0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b, 
+0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0, 
+0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30, 
+0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed, 
+0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d, 
+0xa1, 0xa8, 0xb3, 0xba, 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6, 
+0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46};
+
+uchar XtimeB[256] = {
+0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69, 
+0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9, 
+0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12, 
+0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2, 
+0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f, 
+0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f, 
+0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2, 0xef, 0xe4, 
+0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54, 
+0xf7, 0xfc, 0xe1, 0xea, 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e, 
+0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e, 
+0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5, 
+0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55, 
+0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68, 
+0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8, 
+0x7a, 0x71, 0x6c, 0x67, 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13, 
+0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3}; 
+
+uchar XtimeD[256] = {
+0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b, 
+0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b, 
+0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0, 
+0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20, 
+0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26, 
+0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6, 
+0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87, 0x90, 0x9d, 
+0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d, 
+0xda, 0xd7, 0xc0, 0xcd, 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91, 
+0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41, 
+0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a, 
+0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa, 
+0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc, 
+0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c, 
+0x0c, 0x01, 0x16, 0x1b, 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47, 
+0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97}; 
+
+uchar XtimeE[256] = {
+0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a, 
+0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba, 
+0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81, 
+0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61, 
+0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7, 
+0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17, 
+0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30, 0x22, 0x2c, 
+0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc, 
+0x41, 0x4f, 0x5d, 0x53, 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b, 
+0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb, 
+0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0, 
+0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20, 
+0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6, 
+0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56, 
+0x37, 0x39, 0x2b, 0x25, 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d, 
+0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d}; 
+
+// exchanges columns in each of 4 rows
+// row0 - unchanged, row1- shifted left 1, 
+// row2 - shifted left 2 and row3 - shifted left 3
+void ShiftRows (uchar *state)
+{
+uchar tmp;
+
+	// just substitute row 0
+	state[0] = Sbox[state[0]], state[4] = Sbox[state[4]];
+	state[8] = Sbox[state[8]], state[12] = Sbox[state[12]];
+
+	// rotate row 1
+	tmp = Sbox[state[1]], state[1] = Sbox[state[5]];
+	state[5] = Sbox[state[9]], state[9] = Sbox[state[13]], state[13] = tmp;
+
+	// rotate row 2
+	tmp = Sbox[state[2]], state[2] = Sbox[state[10]], state[10] = tmp;
+	tmp = Sbox[state[6]], state[6] = Sbox[state[14]], state[14] = tmp;
+
+	// rotate row 3
+	tmp = Sbox[state[15]], state[15] = Sbox[state[11]];
+	state[11] = Sbox[state[7]], state[7] = Sbox[state[3]], state[3] = tmp;
+}
+
+// restores columns in each of 4 rows
+// row0 - unchanged, row1- shifted right 1, 
+// row2 - shifted right 2 and row3 - shifted right 3
+void InvShiftRows (uchar *state)
+{
+uchar tmp;
+
+	// restore row 0
+	state[0] = InvSbox[state[0]], state[4] = InvSbox[state[4]];
+	state[8] = InvSbox[state[8]], state[12] = InvSbox[state[12]];
+
+	// restore row 1
+	tmp = InvSbox[state[13]], state[13] = InvSbox[state[9]];
+	state[9] = InvSbox[state[5]], state[5] = InvSbox[state[1]], state[1] = tmp;
+
+	// restore row 2
+	tmp = InvSbox[state[2]], state[2] = InvSbox[state[10]], state[10] = tmp;
+	tmp = InvSbox[state[6]], state[6] = InvSbox[state[14]], state[14] = tmp;
+
+	// restore row 3
+	tmp = InvSbox[state[3]], state[3] = InvSbox[state[7]];
+	state[7] = InvSbox[state[11]], state[11] = InvSbox[state[15]], state[15] = tmp;
+}
+
+// recombine and mix each row in a column
+void MixSubColumns (uchar *state)
+{
+uchar tmp[4 * Nb];
+
+	// mixing column 0
+	tmp[0] = Xtime2Sbox[state[0]] ^ Xtime3Sbox[state[5]] ^ Sbox[state[10]] ^ Sbox[state[15]];
+	tmp[1] = Sbox[state[0]] ^ Xtime2Sbox[state[5]] ^ Xtime3Sbox[state[10]] ^ Sbox[state[15]];
+	tmp[2] = Sbox[state[0]] ^ Sbox[state[5]] ^ Xtime2Sbox[state[10]] ^ Xtime3Sbox[state[15]];
+	tmp[3] = Xtime3Sbox[state[0]] ^ Sbox[state[5]] ^ Sbox[state[10]] ^ Xtime2Sbox[state[15]];
+
+	// mixing column 1
+	tmp[4] = Xtime2Sbox[state[4]] ^ Xtime3Sbox[state[9]] ^ Sbox[state[14]] ^ Sbox[state[3]];
+	tmp[5] = Sbox[state[4]] ^ Xtime2Sbox[state[9]] ^ Xtime3Sbox[state[14]] ^ Sbox[state[3]];
+	tmp[6] = Sbox[state[4]] ^ Sbox[state[9]] ^ Xtime2Sbox[state[14]] ^ Xtime3Sbox[state[3]];
+	tmp[7] = Xtime3Sbox[state[4]] ^ Sbox[state[9]] ^ Sbox[state[14]] ^ Xtime2Sbox[state[3]];
+
+	// mixing column 2
+	tmp[8] = Xtime2Sbox[state[8]] ^ Xtime3Sbox[state[13]] ^ Sbox[state[2]] ^ Sbox[state[7]];
+	tmp[9] = Sbox[state[8]] ^ Xtime2Sbox[state[13]] ^ Xtime3Sbox[state[2]] ^ Sbox[state[7]];
+	tmp[10]  = Sbox[state[8]] ^ Sbox[state[13]] ^ Xtime2Sbox[state[2]] ^ Xtime3Sbox[state[7]];
+	tmp[11]  = Xtime3Sbox[state[8]] ^ Sbox[state[13]] ^ Sbox[state[2]] ^ Xtime2Sbox[state[7]];
+
+	// mixing column 3
+	tmp[12] = Xtime2Sbox[state[12]] ^ Xtime3Sbox[state[1]] ^ Sbox[state[6]] ^ Sbox[state[11]];
+	tmp[13] = Sbox[state[12]] ^ Xtime2Sbox[state[1]] ^ Xtime3Sbox[state[6]] ^ Sbox[state[11]];
+	tmp[14] = Sbox[state[12]] ^ Sbox[state[1]] ^ Xtime2Sbox[state[6]] ^ Xtime3Sbox[state[11]];
+	tmp[15] = Xtime3Sbox[state[12]] ^ Sbox[state[1]] ^ Sbox[state[6]] ^ Xtime2Sbox[state[11]];
+
+	memcpy (state, tmp, sizeof(tmp));
+}
+
+// restore and un-mix each row in a column
+void InvMixSubColumns (uchar *state)
+{
+uchar tmp[4 * Nb];
+int i;
+
+	// restore column 0
+	tmp[0] = XtimeE[state[0]] ^ XtimeB[state[1]] ^ XtimeD[state[2]] ^ Xtime9[state[3]];
+	tmp[5] = Xtime9[state[0]] ^ XtimeE[state[1]] ^ XtimeB[state[2]] ^ XtimeD[state[3]];
+	tmp[10] = XtimeD[state[0]] ^ Xtime9[state[1]] ^ XtimeE[state[2]] ^ XtimeB[state[3]];
+	tmp[15] = XtimeB[state[0]] ^ XtimeD[state[1]] ^ Xtime9[state[2]] ^ XtimeE[state[3]];
+
+	// restore column 1
+	tmp[4] = XtimeE[state[4]] ^ XtimeB[state[5]] ^ XtimeD[state[6]] ^ Xtime9[state[7]];
+	tmp[9] = Xtime9[state[4]] ^ XtimeE[state[5]] ^ XtimeB[state[6]] ^ XtimeD[state[7]];
+	tmp[14] = XtimeD[state[4]] ^ Xtime9[state[5]] ^ XtimeE[state[6]] ^ XtimeB[state[7]];
+	tmp[3] = XtimeB[state[4]] ^ XtimeD[state[5]] ^ Xtime9[state[6]] ^ XtimeE[state[7]];
+
+	// restore column 2
+	tmp[8] = XtimeE[state[8]] ^ XtimeB[state[9]] ^ XtimeD[state[10]] ^ Xtime9[state[11]];
+	tmp[13] = Xtime9[state[8]] ^ XtimeE[state[9]] ^ XtimeB[state[10]] ^ XtimeD[state[11]];
+	tmp[2]  = XtimeD[state[8]] ^ Xtime9[state[9]] ^ XtimeE[state[10]] ^ XtimeB[state[11]];
+	tmp[7]  = XtimeB[state[8]] ^ XtimeD[state[9]] ^ Xtime9[state[10]] ^ XtimeE[state[11]];
+
+	// restore column 3
+	tmp[12] = XtimeE[state[12]] ^ XtimeB[state[13]] ^ XtimeD[state[14]] ^ Xtime9[state[15]];
+	tmp[1] = Xtime9[state[12]] ^ XtimeE[state[13]] ^ XtimeB[state[14]] ^ XtimeD[state[15]];
+	tmp[6] = XtimeD[state[12]] ^ Xtime9[state[13]] ^ XtimeE[state[14]] ^ XtimeB[state[15]];
+	tmp[11] = XtimeB[state[12]] ^ XtimeD[state[13]] ^ Xtime9[state[14]] ^ XtimeE[state[15]];
+
+	for( i=0; i < 4 * Nb; i++ )
+		state[i] = InvSbox[tmp[i]];
+}
+
+// encrypt/decrypt columns of the key
+// n.b. you can replace this with
+//      byte-wise xor if you wish.
+
+void AddRoundKey (unsigned *state, unsigned *key)
+{
+int idx;
+
+	for( idx = 0; idx < 4; idx++ )
+		state[idx] ^= key[idx];
+}
+
+uchar Rcon[11] = {
+0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36};
+
+// produce Nb bytes for each round
+void ExpandKey (uchar *key, uchar *expkey)
+{
+uchar tmp0, tmp1, tmp2, tmp3, tmp4;
+unsigned idx;
+
+	memcpy (expkey, key, Nk * 4);
+
+	for( idx = Nk; idx < Nb * (Nr + 1); idx++ ) {
+		tmp0 = expkey[4*idx - 4];
+		tmp1 = expkey[4*idx - 3];
+		tmp2 = expkey[4*idx - 2];
+		tmp3 = expkey[4*idx - 1];
+		if( !(idx % Nk) ) {
+			tmp4 = tmp3;
+			tmp3 = Sbox[tmp0];
+			tmp0 = Sbox[tmp1] ^ Rcon[idx/Nk];
+			tmp1 = Sbox[tmp2];
+			tmp2 = Sbox[tmp4];
+		} else if( Nk > 6 && idx % Nk == 4 ) {
+			tmp0 = Sbox[tmp0];
+			tmp1 = Sbox[tmp1];
+			tmp2 = Sbox[tmp2];
+			tmp3 = Sbox[tmp3];
+		}
+
+		expkey[4*idx+0] = expkey[4*idx - 4*Nk + 0] ^ tmp0;
+		expkey[4*idx+1] = expkey[4*idx - 4*Nk + 1] ^ tmp1;
+		expkey[4*idx+2] = expkey[4*idx - 4*Nk + 2] ^ tmp2;
+		expkey[4*idx+3] = expkey[4*idx - 4*Nk + 3] ^ tmp3;
+	}
+}
+
+// encrypt one 128 bit block
+void Encrypt (uchar *in, uchar *expkey, uchar *out)
+{
+uchar state[Nb * 4];
+unsigned round;
+
+	memcpy (state, in, Nb * 4);
+	AddRoundKey ((unsigned *)state, (unsigned *)expkey);
+
+	for( round = 1; round < Nr + 1; round++ ) {
+		if( round < Nr )
+			MixSubColumns (state);
+		else
+			ShiftRows (state);
+
+		AddRoundKey ((unsigned *)state, (unsigned *)expkey + round * Nb);
+	}
+
+	memcpy (out, state, sizeof(state));
+}
+
+void Decrypt (uchar *in, uchar *expkey, uchar *out)
+{
+uchar state[Nb * 4];
+unsigned round;
+
+	memcpy (state, in, sizeof(state));
+
+	AddRoundKey ((unsigned *)state, (unsigned *)expkey + Nr * Nb);
+	InvShiftRows(state);
+
+	for( round = Nr; round--; )
+	{
+		AddRoundKey ((unsigned *)state, (unsigned *)expkey + round * Nb);
+		if( round )
+			InvMixSubColumns (state);
+	} 
+
+	memcpy (out, state, sizeof(state));
+}
+ c/helper.c view
@@ -0,0 +1,166 @@+#include <stdlib.h>+#include <stdint.h>+#include <string.h>++typedef unsigned char uchar;+typedef unsigned int uint;+#define Nb 4			// number of columns in the state & expanded key+#define Nr 10			// number of rounds in encryption++void ExpandKey(uchar *key, uchar *expkey);+void Encrypt (uchar *in, uchar *expkey, uchar *out);+void Decrypt (uchar *in, uchar *expkey, uchar *out);++void get_hash(uint *out, uchar *in, uint len)+{+	uint32_t hash = 0;++	for (; len--; ++in) {+		hash = (hash >> 1) + ((hash & 1) << 31);+		hash += *in;+	}++	*out = hash;+}++/* http://base64.sourceforge.net/b64.c.  LICENCE:        Copyright (c) 2001+ * Bob Trower, Trantor Standard Systems Inc. */++static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";++void base64_enc(char *out, uchar *in, uint len)+{+	while (len) {+		uchar buffin[3];+		buffin[0] = *(in++);+		if (--len) {+			buffin[1] = *(in++);+			if (--len) {+				buffin[2] = *(in++);+				--len;+			} else {+				buffin[2] = 0;+			}+		} else {+			buffin[1] = 0;+			buffin[2] = 0;+		}++		*(out++) = cb64[buffin[0] >> 2];+		*(out++) = cb64[ (buffin[0] & 0x03) << 4+			       | (buffin[1] & 0xf0) >> 4];+		*(out++) = cb64[ (buffin[1] & 0x0f) << 2+			       | (buffin[2] & 0xc0) >> 6];+		*(out++) = cb64[buffin[2] & 0x3f];+	}+}++int parse_char(uchar *out, char in)+{+	if ('A' <= in && in <= 'Z') {+		*out = in - 'A';+	} else if ('a' <= in && in <= 'z') {+		*out = in - 'a' + 26;+	} else if ('0' <= in && in <= '9') {+		*out = in - '0' + 52;+	} else if (in == '+') {+		*out = 62;+	} else if (in == '/') {+		*out = 63;+	} else {+		return 0;+	}+	return 1;+}++int base64_dec(uchar *out, char *in, uint len)+{+	for (; len; in += 4, out += 3, len -= 4) {+		uchar tmp[4];+		int i = 0;+		for (i = 0; i < 4; ++i) {+			if (! parse_char(tmp + i, in[i])) return 0;+		}+		out[0] = tmp[0] << 2 | tmp[1] >> 4;+		out[1] = tmp[1] << 4 | tmp[2] >> 2;+		out[2] = ((tmp[2] << 6) & 0xc0) | tmp[3];+	}+	return 1;+}++char * encrypt(uint32_t len, uchar *in, uchar *key, uint *outlen)+{+	uchar expkey[4 * Nb * (Nr + 1)];+	uchar *out;+	uint i;+	uint totlen, encoded_len;+	uchar *tmp;+	uchar buff[16];++	/* 4 bytes for the hash, 4 bytes for the length, then the string.+	 * Need to align to 16 bytes.+	 */+	totlen = len + 8;+	totlen += 16 - (totlen % 16);+	tmp = alloca(totlen);+	bzero(tmp, totlen);+	get_hash((uint*) tmp, in, len);+	memcpy(tmp + 4, &len, 4);+	memcpy(tmp + 8, in, len);++	ExpandKey(key, expkey);+	for (i = 0; i < totlen; i += 16) {+		//Encrypt(tmp + i, expkey, buff);++		//memcpy(tmp + 1, buff, 16);+	}++	encoded_len = (totlen + 2 - ((totlen + 2) % 3)) / 3 * 4;+	out = malloc(encoded_len + 1);+	out[encoded_len] = 0;+	base64_enc(out, tmp, totlen);++	*outlen = encoded_len;+	return out;+}++uchar * decrypt(uint len, char *in, uchar *key, uint *out_len)+{+	uchar expkey[4 * Nb * (Nr + 1)];+	uchar *out;+	uint i;+	uchar buff[16];+	uint outlen;+	uint hash, orig_hash;+	uint orig_len;++	if (! len % 4) return 0;+	outlen = len / 4 * 3;+	out = alloca(outlen);++	if (! base64_dec(out, in, len)) {+		return 0;+	}++	ExpandKey(key, expkey);++	for (i = 0; i < len; i += 16) {+		//Decrypt(out + i, expkey, buff);++		//memcpy(out + i, buff, 16);+	}++	orig_hash = *((uint*) out);+	orig_len = *(out + 4);+	get_hash(&hash, out + 8, orig_len);+	if (orig_hash != hash) {+		return 0;+	}++	uchar *realout = malloc(orig_len + 1);+	realout[orig_len] = 0;+	memcpy(realout, out + 8, orig_len);++	*out_len = orig_len;+	return realout;+}
clientsession.cabal view
@@ -1,5 +1,5 @@ name:            clientsession-version:         0.3.0+version:         0.4.0 license:         BSD3 license-file:    LICENSE author:          Michael Snoyman <michael@snoyman.com>@@ -9,18 +9,36 @@                  Uses base64 encoding to avoid any issues with characters. category:        Web stability:       stable-cabal-version:   >= 1.2+cabal-version:   >= 1.6 build-type:      Simple homepage:        http://github.com/snoyberg/clientsession/tree/master +flag buildtests+  description: Build the executable to run unit tests+  default: False+ library     build-depends:   base >=4 && <5,-                     SimpleAES >= 0.4.1 && < 0.5,-                     pureMD5 >= 1.1.0.0 && < 1.2,-                     dataenc >= 0.13.0.2 && < 0.14,-                     failure >= 0.0.0.2 && < 0.2,                      bytestring >= 0.9 && < 0.10,                      directory >= 1 && < 1.1,-                     binary >= 0.5.0.2 && < 0.6+                     random >= 1.0.0.2 && < 1.1     exposed-modules: Web.ClientSession     ghc-options:     -Wall+    c-sources:       c/aestable.c c/helper.c++executable             runtests+    if flag(buildtests)+        Buildable: True+        cpp-options:   -DTEST+        build-depends: test-framework,+                       test-framework-quickcheck2,+                       QuickCheck >= 2 && < 3+    else+        Buildable: False+    ghc-options:     -Wall+    main-is:         runtests.hs+    c-sources:       c/aestable.c c/helper.c++source-repository head+  type:     git+  location: git://github.com/snoyberg/clientsession.git
+ runtests.hs view
@@ -0,0 +1,46 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+import Test.Framework (defaultMain)+import Test.QuickCheck+import Test.Framework.Providers.QuickCheck2++import qualified Data.ByteString as S++import Web.ClientSession+import System.IO.Unsafe+import Data.Word++main :: IO ()+main = defaultMain+    [ testProperty "encrypt/decrypt success" propEncDec+    , testProperty "encrypt/decrypt failure" propEncDecFailure+    , testProperty "AES encrypt/decrypt success" propAES+    , testProperty "AES encryption changes bs" propAESChanges+    ]++propEncDec :: S.ByteString -> Bool+propEncDec bs = unsafePerformIO $ do+    key <- getDefaultKey+    let s = encrypt key bs+    let bs' = decrypt key s+    return $ Just bs == bs'++propEncDecFailure :: S.ByteString -> Bool+propEncDecFailure bs = unsafePerformIO $ do+    key <- getDefaultKey+    let s = encrypt key bs+    let bs' = decrypt key $ (S.head s + 1) `S.cons` S.drop 1 s+    return $ Just bs /= bs'++propAES :: S.ByteString -> S.ByteString -> Bool+propAES key bs = decrypt key (encrypt key bs) == Just bs++propAESChanges :: S.ByteString -> S.ByteString -> Bool+propAESChanges key bs = encrypt key bs /= bs++instance Arbitrary S.ByteString where+    arbitrary = S.pack `fmap` arbitrary++instance Arbitrary Word8 where+    arbitrary = arbitraryBoundedIntegral