packages feed

cipher-aes 0.1.8 → 0.2.0

raw patch · 17 files changed

+1128/−746 lines, 17 filesdep +byteabledep +crypto-cipher-benchmarksdep +crypto-cipher-testsPVP ok

version bump matches the API change (PVP)

Dependencies added: byteable, crypto-cipher-benchmarks, crypto-cipher-tests, crypto-cipher-types, securemem

API changes (from Hackage documentation)

- Crypto.Cipher.AES: IV :: ByteString -> IV
- Crypto.Cipher.AES: data Key
- Crypto.Cipher.AES: instance Storable GCM
- Crypto.Cipher.AES: keyOfCtx :: Key -> ByteString
- Crypto.Cipher.AES: newtype IV
+ Crypto.Cipher.AES: data AES
+ Crypto.Cipher.AES: data AES128
+ Crypto.Cipher.AES: data AES192
+ Crypto.Cipher.AES: data AES256
+ Crypto.Cipher.AES: initAES :: Byteable b => b -> AES
+ Crypto.Cipher.AES: instance AEADModeImpl AES128 GCM
+ Crypto.Cipher.AES: instance AEADModeImpl AES192 GCM
+ Crypto.Cipher.AES: instance AEADModeImpl AES256 GCM
+ Crypto.Cipher.AES: instance BlockCipher AES128
+ Crypto.Cipher.AES: instance BlockCipher AES192
+ Crypto.Cipher.AES: instance BlockCipher AES256
+ Crypto.Cipher.AES: instance Cipher AES128
+ Crypto.Cipher.AES: instance Cipher AES192
+ Crypto.Cipher.AES: instance Cipher AES256
- Crypto.Cipher.AES: decryptCBC :: Key -> IV -> ByteString -> ByteString
+ Crypto.Cipher.AES: decryptCBC :: Byteable iv => AES -> iv -> ByteString -> ByteString
- Crypto.Cipher.AES: decryptCTR :: Key -> IV -> ByteString -> ByteString
+ Crypto.Cipher.AES: decryptCTR :: Byteable iv => AES -> iv -> ByteString -> ByteString
- Crypto.Cipher.AES: decryptECB :: Key -> ByteString -> ByteString
+ Crypto.Cipher.AES: decryptECB :: AES -> ByteString -> ByteString
- Crypto.Cipher.AES: decryptGCM :: Key -> IV -> ByteString -> ByteString -> (ByteString, ByteString)
+ Crypto.Cipher.AES: decryptGCM :: Byteable iv => AES -> iv -> ByteString -> ByteString -> (ByteString, AuthTag)
- Crypto.Cipher.AES: decryptXTS :: (Key, Key) -> IV -> Word32 -> ByteString -> ByteString
+ Crypto.Cipher.AES: decryptXTS :: Byteable iv => (AES, AES) -> iv -> Word32 -> ByteString -> ByteString
- Crypto.Cipher.AES: encryptCBC :: Key -> IV -> ByteString -> ByteString
+ Crypto.Cipher.AES: encryptCBC :: Byteable iv => AES -> iv -> ByteString -> ByteString
- Crypto.Cipher.AES: encryptCTR :: Key -> IV -> ByteString -> ByteString
+ Crypto.Cipher.AES: encryptCTR :: Byteable iv => AES -> iv -> ByteString -> ByteString
- Crypto.Cipher.AES: encryptECB :: Key -> ByteString -> ByteString
+ Crypto.Cipher.AES: encryptECB :: AES -> ByteString -> ByteString
- Crypto.Cipher.AES: encryptGCM :: Key -> IV -> ByteString -> ByteString -> (ByteString, ByteString)
+ Crypto.Cipher.AES: encryptGCM :: Byteable iv => AES -> iv -> ByteString -> ByteString -> (ByteString, AuthTag)
- Crypto.Cipher.AES: encryptXTS :: (Key, Key) -> IV -> Word32 -> ByteString -> ByteString
+ Crypto.Cipher.AES: encryptXTS :: Byteable iv => (AES, AES) -> iv -> Word32 -> ByteString -> ByteString
- Crypto.Cipher.AES: genCTR :: Key -> IV -> Int -> ByteString
+ Crypto.Cipher.AES: genCTR :: Byteable iv => AES -> iv -> Int -> ByteString
- Crypto.Cipher.AES: initKey :: ByteString -> Key
+ Crypto.Cipher.AES: initKey :: Byteable b => b -> AES

Files

Benchmarks/Benchmarks.hs view
@@ -1,102 +1,7 @@-{-# LANGUAGE CPP #-}-import Criterion-import Criterion.Environment-import Criterion.Config-import Criterion.Monad-import Criterion.Analysis-import Criterion.Measurement--import Text.Printf--import Control.Monad.Trans--import qualified Data.ByteString as B-import qualified Data.ByteString.Lazy as L--import qualified Crypto.Cipher.AES as AES--key128 = AES.initKey $ B.replicate 16 0-key192 = AES.initKey $ B.replicate 24 0-key256 = AES.initKey $ B.replicate 32 0--nullIV = AES.IV $ B.replicate 16 0-nullIVGCM = AES.IV $ B.replicate 12 0--aesEncrypt128 = AES.encryptECB key128-aesEncrypt128CBC = AES.encryptCBC key128 nullIV-aesEncrypt128CTR = AES.encryptCTR key128 nullIV-aesEncrypt128XTS = AES.encryptXTS (key128,key128) nullIV 0-aesEncrypt128GCM = fst . AES.encryptGCM key128 nullIVGCM B.empty--aesEncrypt192 = AES.encryptECB key192-aesEncrypt192CBC = AES.encryptCBC key192 nullIV-aesEncrypt192CTR = AES.encryptCTR key192 nullIV-aesEncrypt192GCM = fst . AES.encryptGCM key192 nullIVGCM B.empty-aesEncrypt256 = AES.encryptECB key256-aesEncrypt256CBC = AES.encryptCBC key256 nullIV-aesEncrypt256CTR = AES.encryptCTR key256 nullIV-aesEncrypt256XTS = AES.encryptXTS (key256,key256) nullIV 0-aesEncrypt256GCM = fst . AES.encryptGCM key256 nullIVGCM B.empty--b16 f   = whnf f $ B.replicate 16 0-b32 f   = whnf f $ B.replicate 32 0-b128 f  = whnf f $ B.replicate 128 0-b512 f  = whnf f $ B.replicate 512 0-b1024 f = whnf f $ B.replicate 1024 0-b4096 f = whnf f $ B.replicate 4096 0-b16384 f = whnf f $ B.replicate 16384 0--doCipher env f = do-	mean16   <- runBenchmark env (b16 f)   >>= \sample -> analyseMean sample 100-	mean32   <- runBenchmark env (b32 f)   >>= \sample -> analyseMean sample 100-	mean128  <- runBenchmark env (b128 f)  >>= \sample -> analyseMean sample 100-	mean512  <- runBenchmark env (b512 f)  >>= \sample -> analyseMean sample 100-	mean1024 <- runBenchmark env (b1024 f) >>= \sample -> analyseMean sample 100-	mean4096 <- runBenchmark env (b4096 f) >>= \sample -> analyseMean sample 100-	mean16384 <- runBenchmark env (b16384 f) >>= \sample -> analyseMean sample 100-	return (mean16, mean32, mean128, mean512, mean1024, mean4096, mean16384)--norm :: Int -> Double -> Double-norm n time-	| n < 1024  = 1.0 / (time * (1024 / fromIntegral n))-	| n == 1024 = 1.0 / time-	| n > 1024  = 1.0 / (time / (fromIntegral n / 1024))--pn :: Int -> Double -> String-pn n time-    | val > (10 * 1024) = printf "%.1f M/s" (val / 1024)-    | otherwise         = printf "%.1f K/s" val-    where val = norm n time--doOne env (cipherName, f) = do-	(mean16, mean32, mean128, mean512, mean1024, mean4096, mean16384) <- doCipher env f-	let s = printf "%12s: %12s %12s %12s %12s %12s %12s %12s\n              %12s %12s %12s %12s %12s %12s %12s"-	               cipherName-	               (secs mean16) (secs mean32) (secs mean128)-	               (secs mean512) (secs mean1024) (secs mean4096) (secs mean16384)-	               (pn 16 mean16) (pn 32 mean32) (pn 128 mean128)-	               (pn 512 mean512) (pn 1024 mean1024) (pn 4096 mean4096) (pn 16384 mean16384)-	return s+import Crypto.Cipher.Benchmarks+import Crypto.Cipher.AES (AES128, AES192, AES256) -main = withConfig defaultConfig $ do-	env <- measureEnvironment-	l   <- mapM (doOne env)-		[ ("AES128"     , aesEncrypt128)-		, ("AES128-CBC" , aesEncrypt128CBC)-		, ("AES128-CTR" , aesEncrypt128CTR)-		, ("AES128-XTS" , aesEncrypt128XTS)-		, ("AES128-GCM" , aesEncrypt128GCM)-		, ("AES192"     , aesEncrypt192)-		, ("AES192-CBC" , aesEncrypt192CBC)-		, ("AES192-CTR" , aesEncrypt192CTR)-		, ("AES192-GCM" , aesEncrypt192GCM)-		, ("AES256"     , aesEncrypt256)-		, ("AES256-CBC" , aesEncrypt256CBC)-		, ("AES256-CTR" , aesEncrypt256CTR)-		, ("AES256-XTS" , aesEncrypt256XTS)-		, ("AES256-GCM" , aesEncrypt256GCM)-		]-	liftIO $ printf "%12s| %12s %12s %12s %12s %12s %12s %12s\n"-	                "cipher" "16 bytes" "32 bytes" "64 bytes" "512 bytes" "1024 bytes" "4096 bytes" "16384 bytes"-	liftIO $ printf "===================================================================================================\n"-	mapM_ (liftIO . putStrLn) l+main = defaultMain+    [GBlockCipher (undefined :: AES128)+    ,GBlockCipher (undefined :: AES192)+    ,GBlockCipher (undefined :: AES256)]
Crypto/Cipher/AES.hs view
@@ -1,5 +1,7 @@ {-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE CPP #-} -- | -- Module      : Crypto.Cipher.AES -- License     : BSD-style@@ -10,12 +12,14 @@ module Crypto.Cipher.AES     (     -- * data types-      Key-    , IV(..)+      AES+    , AES128+    , AES192+    , AES256      -- * creation+    , initAES     , initKey-    , keyOfCtx      -- * misc     , genCTR@@ -35,82 +39,121 @@     , decryptGCM     ) where --- import Data.ByteString (ByteString) import Data.Word import Foreign.Ptr-import Foreign.ForeignPtr-import Foreign.Storable import Foreign.C.Types import Foreign.C.String-import Foreign.Marshal.Alloc import Data.ByteString.Internal import Data.ByteString.Unsafe+import Data.Byteable import qualified Data.ByteString as B import System.IO.Unsafe (unsafePerformIO) --- | AES Key-newtype Key = Key ByteString+import Crypto.Cipher.Types+import Data.SecureMem --- | AES IV-newtype IV = IV ByteString+-- | AES Context (pre-processed key)+newtype AES = AES SecureMem --- | GCM Context-newtype GCM = GCM ByteString+newtype AES128 = AES128 AES+newtype AES192 = AES192 AES+newtype AES256 = AES256 AES -sizeGCM :: Int-sizeGCM = 540+instance Cipher AES128 where+    cipherName    _ = "AES128"+    cipherKeySize _ = Just 16+    cipherInit k    = AES128 $ initAES k -instance Storable GCM where-    sizeOf _    = sizeGCM-    alignment _ = 16-    poke ptr (GCM b) = unsafeUseAsCString b (\cs -> memcpy (castPtr ptr) (castPtr cs) (fromIntegral sizeGCM))-    peek ptr         = create sizeGCM (\bptr -> memcpy bptr (castPtr ptr) (fromIntegral sizeGCM)) >>= return . GCM+instance Cipher AES192 where+    cipherName    _ = "AES192"+    cipherKeySize _ = Just 24+    cipherInit k    = AES192 $ initAES k -keyToPtr :: Key -> (Ptr Key -> IO a) -> IO a-keyToPtr (Key b) f = unsafeUseAsCString b (f . castPtr)+instance Cipher AES256 where+    cipherName    _ = "AES256"+    cipherKeySize _ = Just 32+    cipherInit k    = AES256 $ initAES k -ivToPtr :: IV -> (Ptr IV -> IO a) -> IO a-ivToPtr (IV b) f = unsafeUseAsCString b (f . castPtr)+#define INSTANCE_BLOCKCIPHER(CSTR) \+instance BlockCipher CSTR where \+    { blockSize _ = 16 \+    ; ecbEncrypt (CSTR aes) = encryptECB aes \+    ; ecbDecrypt (CSTR aes) = decryptECB aes \+    ; cbcEncrypt (CSTR aes) = encryptCBC aes \+    ; cbcDecrypt (CSTR aes) = decryptCBC aes \+    ; ctrCombine (CSTR aes) = encryptCTR aes \+    ; xtsEncrypt (CSTR aes1, CSTR aes2) = encryptXTS (aes1,aes2) \+    ; xtsDecrypt (CSTR aes1, CSTR aes2) = decryptXTS (aes1,aes2) \+    ; aeadInit AEAD_GCM cipher@(CSTR aes) iv = Just $ AEAD cipher $ AEADState $ gcmInit aes iv \+    ; aeadInit _        _                  _ = Nothing \+    }; \+\+instance AEADModeImpl CSTR GCM where \+    { aeadStateAppendHeader (CSTR _) gcmState bs = gcmAppendAAD gcmState bs \+    ; aeadStateEncrypt (CSTR aes) gcmState input = gcmAppendEncrypt aes gcmState input \+    ; aeadStateDecrypt (CSTR aes) gcmState input = gcmAppendDecrypt aes gcmState input \+    ; aeadStateFinalize (CSTR aes) gcmState len  = gcmFinish aes gcmState len \+    } -withKeyAndIV :: Key -> IV -> (Ptr Key -> Ptr IV -> IO a) -> IO a-withKeyAndIV key iv f = keyToPtr key $ \kptr -> ivToPtr iv $ \ivp -> f kptr ivp+INSTANCE_BLOCKCIPHER(AES128)+INSTANCE_BLOCKCIPHER(AES192)+INSTANCE_BLOCKCIPHER(AES256) -withKey2AndIV :: Key -> Key -> IV -> (Ptr Key -> Ptr Key -> Ptr IV -> IO a) -> IO a+-- | GCM State+newtype GCM = GCM SecureMem++sizeGCM :: Int+sizeGCM = 80++keyToPtr :: AES -> (Ptr AES -> IO a) -> IO a+keyToPtr (AES b) f = withSecureMemPtr b (f . castPtr)++ivToPtr :: Byteable iv => iv -> (Ptr Word8 -> IO a) -> IO a+ivToPtr iv f = withBytePtr iv (f . castPtr)++withKeyAndIV :: Byteable iv => AES -> iv -> (Ptr AES -> Ptr Word8 -> IO a) -> IO a+withKeyAndIV ctx iv f = keyToPtr ctx $ \kptr -> ivToPtr iv $ \ivp -> f kptr ivp++withKey2AndIV :: Byteable iv => AES -> AES -> iv -> (Ptr AES -> Ptr AES -> Ptr Word8 -> IO a) -> IO a withKey2AndIV key1 key2 iv f =     keyToPtr key1 $ \kptr1 -> keyToPtr key2 $ \kptr2 -> ivToPtr iv $ \ivp -> f kptr1 kptr2 ivp +withGCMKeyAndCopySt :: AES -> GCM -> (Ptr GCM -> Ptr AES -> IO a) -> IO (a, GCM)+withGCMKeyAndCopySt aes (GCM gcmSt) f =+    keyToPtr aes $ \aesPtr -> do+        newSt <- secureMemCopy gcmSt+        a     <- withSecureMemPtr newSt $ \gcmStPtr -> f (castPtr gcmStPtr) aesPtr+        return (a, GCM newSt)++withNewGCMSt :: GCM -> (Ptr GCM -> IO ()) -> IO GCM+withNewGCMSt (GCM gcmSt) f = withSecureMemCopy gcmSt (f . castPtr) >>= \sm2 -> return (GCM sm2)+ -- | initialize key-{-# NOINLINE initKey #-}-initKey :: ByteString -> Key-initKey b@(B.length -> len)-    | len == 16 = doInit 10-    | len == 24 = doInit 12-    | len == 32 = doInit 14-    | otherwise = error "wrong key size: need to be 16, 24 or 32 bytes."-      where doInit nbR = unsafePerformIO $ unsafeUseAsCString b (allocAndFill nbR)-            allocAndFill nbR ikey = do-                ptr <- mallocBytes (16+2*2*16*nbR)-                c_aes_init ptr (castPtr ikey) (fromIntegral len)-                fptr <- newForeignPtr c_free_finalizer (castPtr ptr)-                return $ Key $ fromForeignPtr fptr 0 (16+2*2*16*nbR)+--+-- rounds need to be 10 / 12 / 14. any other values will cause undefined behavior+initAES :: Byteable b => b -> AES+initAES k+    | len == 16 = initWithRounds 10+    | len == 24 = initWithRounds 12+    | len == 32 = initWithRounds 14+    | otherwise = error "not a valid key length"+  where len = byteableLength k+        initWithRounds nbR = AES $ unsafeCreateSecureMem (16+2*2*16*nbR) aesInit+        aesInit ptr = withBytePtr k $ \ikey ->+            c_aes_init (castPtr ptr) (castPtr ikey) (fromIntegral len) --- | return the user key from the Key context-keyOfCtx :: Key -> ByteString-keyOfCtx (Key bs) = B.take sz (B.drop 8 bs)-    where nbRound            = unsafeHead $ B.take 1 bs-          sz | nbRound == 10 = 16-             | nbRound == 12 = 24-             | nbRound == 14 = 32-             | otherwise     = error "not a valid key"+{-# DEPRECATED initKey "use initAES" #-}+initKey :: Byteable b => b -> AES+initKey = initAES  -- | encrypt using Electronic Code Book (ECB) {-# NOINLINE encryptECB #-}-encryptECB :: Key -> ByteString -> ByteString+encryptECB :: AES -> ByteString -> ByteString encryptECB = doECB c_aes_encrypt_ecb  -- | encrypt using Cipher Block Chaining (CBC) {-# NOINLINE encryptCBC #-}-encryptCBC :: Key -> IV -> ByteString -> ByteString+encryptCBC :: Byteable iv => AES -> iv -> ByteString -> ByteString encryptCBC = doCBC c_aes_encrypt_cbc  -- | generate a counter mode pad. this is generally xor-ed to an input@@ -120,36 +163,46 @@ -- more data will be returned, so that the returned bytestring is -- a multiple of the block cipher size. {-# NOINLINE genCTR #-}-genCTR :: Key        -- ^ Cipher Key.-       -> IV         -- ^ usually a 128 bit integer.-       -> Int        -- ^ length of bytes required.+genCTR :: Byteable iv+       => AES -- ^ Cipher Key.+       -> iv  -- ^ usually a 128 bit integer.+       -> Int -- ^ length of bytes required.        -> ByteString-genCTR key iv len = unsafeCreate (nbBlocks * 16) generate-    where-          generate o = withKeyAndIV key iv $ \k i -> c_aes_gen_ctr (castPtr o) k i (fromIntegral nbBlocks)-          (nbBlocks',r) = len `divMod` 16-          nbBlocks = if r == 0 then nbBlocks' else nbBlocks' + 1+genCTR ctx iv len+    | len <= 0  = B.empty+    | otherwise = unsafeCreate (nbBlocks * 16) generate+  where generate o = withKeyAndIV ctx iv $ \k i -> c_aes_gen_ctr (castPtr o) k i (fromIntegral nbBlocks)+        (nbBlocks',r) = len `quotRem` 16+        nbBlocks = if r == 0 then nbBlocks' else nbBlocks' + 1  -- | encrypt using Counter mode (CTR) -- -- in CTR mode encryption and decryption is the same operation. {-# NOINLINE encryptCTR #-}-encryptCTR :: Key -> IV -> ByteString -> ByteString-encryptCTR key iv input = unsafeCreate len doEncrypt-    where doEncrypt o = withKeyAndIV key iv $ \k v -> unsafeUseAsCString input $ \i ->-                            c_aes_encrypt_ctr (castPtr o) k v i (fromIntegral len)-          len = B.length input+encryptCTR :: Byteable iv+           => AES+           -> iv+           -> ByteString+           -> ByteString+encryptCTR ctx iv input+    | len <= 0  = B.empty+    | otherwise = unsafeCreate len doEncrypt+  where doEncrypt o = withKeyAndIV ctx iv $ \k v -> unsafeUseAsCString input $ \i ->+                      c_aes_encrypt_ctr (castPtr o) k v i (fromIntegral len)+        len = B.length input  -- | encrypt using Galois counter mode (GCM) -- return the encrypted bytestring and the tag associated -- -- note: encrypted data is identical to CTR mode in GCM, however -- a tag is also computed.-encryptGCM :: Key        -- ^ Key-           -> IV         -- ^ initial vector+{-# NOINLINE encryptGCM #-}+encryptGCM :: Byteable iv+           => AES        -- ^ Key+           -> iv         -- ^ initial vector            -> ByteString -- ^ data to authenticate (AAD)            -> ByteString -- ^ data to encrypt-           -> (ByteString, ByteString) -- ^ ciphertext and tag+           -> (ByteString, AuthTag) -- ^ ciphertext and tag encryptGCM = doGCM gcmAppendEncrypt  -- | encrypt using XTS@@ -157,164 +210,173 @@ -- the first key is the normal block encryption key -- the second key is used for the initial block tweak {-# NOINLINE encryptXTS #-}-encryptXTS :: (Key,Key) -> IV -> Word32 -> ByteString -> ByteString+encryptXTS :: Byteable iv => (AES,AES) -> iv -> Word32 -> ByteString -> ByteString encryptXTS = doXTS c_aes_encrypt_xts  -- | decrypt using Electronic Code Book (ECB) {-# NOINLINE decryptECB #-}-decryptECB :: Key -> ByteString -> ByteString+decryptECB :: AES -> ByteString -> ByteString decryptECB = doECB c_aes_decrypt_ecb  -- | decrypt using Cipher block chaining (CBC) {-# NOINLINE decryptCBC #-}-decryptCBC :: Key -> IV -> ByteString -> ByteString+decryptCBC :: Byteable iv => AES -> iv -> ByteString -> ByteString decryptCBC = doCBC c_aes_decrypt_cbc  -- | decrypt using Counter mode (CTR). -- -- in CTR mode encryption and decryption is the same operation.-decryptCTR :: Key -> IV -> ByteString -> ByteString+decryptCTR :: Byteable iv => AES -> iv -> ByteString -> ByteString decryptCTR = encryptCTR  -- | decrypt using XTS {-# NOINLINE decryptXTS #-}-decryptXTS :: (Key,Key) -> IV -> Word32 -> ByteString -> ByteString+decryptXTS :: Byteable iv => (AES,AES) -> iv -> Word32 -> ByteString -> ByteString decryptXTS = doXTS c_aes_decrypt_xts  -- | decrypt using Galois Counter Mode (GCM) {-# NOINLINE decryptGCM #-}-decryptGCM :: Key -> IV -> ByteString -> ByteString -> (ByteString, ByteString)+decryptGCM :: Byteable iv => AES -> iv -> ByteString -> ByteString -> (ByteString, AuthTag) decryptGCM = doGCM gcmAppendDecrypt  {-# INLINE doECB #-}-doECB :: (Ptr b -> Ptr Key -> CString -> CUInt -> IO ())-      -> Key -> ByteString -> ByteString-doECB f key input+doECB :: (Ptr b -> Ptr AES -> CString -> CUInt -> IO ())+      -> AES -> ByteString -> ByteString+doECB f ctx input     | r /= 0    = error "cannot use with non multiple of block size"-    | otherwise = unsafeCreate len $ \o -> keyToPtr key $ \k -> unsafeUseAsCString input $ \i ->-            f (castPtr o) k i (fromIntegral nbBlocks)-    where (nbBlocks, r) = len `divMod` 16-          len           = (B.length input)+    | otherwise = unsafeCreate len $ \o ->+                  keyToPtr ctx $ \k ->+                  unsafeUseAsCString input $ \i ->+                  f (castPtr o) k i (fromIntegral nbBlocks)+  where (nbBlocks, r) = len `quotRem` 16+        len           = (B.length input)   {-# INLINE doCBC #-}-doCBC :: (Ptr b -> Ptr Key -> Ptr IV -> CString -> CUInt -> IO ())-      -> Key -> IV -> ByteString -> ByteString-doCBC f key iv input+doCBC :: Byteable iv+      => (Ptr b -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ())+      -> AES -> iv -> ByteString -> ByteString+doCBC f ctx iv input+    | len == 0  = B.empty     | r /= 0    = error "cannot use with non multiple of block size"-    | otherwise = unsafeCreate len $ \o -> withKeyAndIV key iv $ \k v -> unsafeUseAsCString input $ \i ->-            f (castPtr o) k v i (fromIntegral nbBlocks)-    where (nbBlocks, r) = len `divMod` 16-          len           = (B.length input)+    | otherwise = unsafeCreate len $ \o ->+                  withKeyAndIV ctx iv $ \k v ->+                  unsafeUseAsCString input $ \i ->+                  f (castPtr o) k v i (fromIntegral nbBlocks)+  where (nbBlocks, r) = len `quotRem` 16+        len           = B.length input  {-# INLINE doXTS #-}-doXTS :: (Ptr b -> Ptr Key -> Ptr Key -> Ptr IV -> CUInt -> CString -> CUInt -> IO ())-      -> (Key, Key) -> IV -> Word32 -> ByteString -> ByteString+doXTS :: Byteable iv+      => (Ptr b -> Ptr AES -> Ptr AES -> Ptr Word8 -> CUInt -> CString -> CUInt -> IO ())+      -> (AES, AES) -> iv -> Word32 -> ByteString -> ByteString doXTS f (key1,key2) iv spoint input+    | len == 0  = B.empty     | r /= 0    = error "cannot use with non multiple of block size (yet)"     | otherwise = unsafeCreate len $ \o -> withKey2AndIV key1 key2 iv $ \k1 k2 v -> unsafeUseAsCString input $ \i ->             f (castPtr o) k1 k2 v (fromIntegral spoint) i (fromIntegral nbBlocks)-    where (nbBlocks, r) = len `divMod` 16-          len           = (B.length input)+  where (nbBlocks, r) = len `quotRem` 16+        len           = B.length input  {-# INLINE doGCM #-}-doGCM :: (GCM -> ByteString -> (ByteString, GCM)) -> Key -> IV -> ByteString -> ByteString -> (ByteString, ByteString)-doGCM f key iv aad input = (cipher, tag)-    where-          tag             = gcmFinish after 16-          (cipher, after) = f afterAAD input-          afterAAD        = gcmAppendAAD ini aad-          ini             = gcmInit key iv--allocaFrom :: Storable a => a -> (Ptr a -> IO b) -> IO b-allocaFrom z f = alloca $ \ptr -> poke ptr z >> f ptr+doGCM :: Byteable iv => (AES -> GCM -> ByteString -> (ByteString, GCM)) -> AES -> iv -> ByteString -> ByteString -> (ByteString, AuthTag)+doGCM f ctx iv aad input = (output, tag)+  where tag             = gcmFinish ctx after 16+        (output, after) = f ctx afterAAD input+        afterAAD        = gcmAppendAAD ini aad+        ini             = gcmInit ctx iv  -- | initialize a gcm context {-# NOINLINE gcmInit #-}-gcmInit :: Key -> IV -> GCM-gcmInit key iv@(IV b) = unsafePerformIO $ alloca doInit-    where doInit gcm = withKeyAndIV key iv (\k v -> c_aes_gcm_init gcm k v (fromIntegral $ B.length b)) >> peek gcm+gcmInit :: Byteable iv => AES -> iv -> GCM+gcmInit ctx iv = unsafePerformIO $ do+    sm <- createSecureMem sizeGCM $ \gcmStPtr ->+            withKeyAndIV ctx iv $ \k v ->+            c_aes_gcm_init (castPtr gcmStPtr) k v (fromIntegral $ byteableLength iv)+    return $ GCM sm  -- | append data which is going to just be authentified to the GCM context. -- -- need to happen after initialization and before appending encryption/decryption data. {-# NOINLINE gcmAppendAAD #-} gcmAppendAAD :: GCM -> ByteString -> GCM-gcmAppendAAD gcm input = unsafePerformIO $ allocaFrom gcm doAppend-    where doAppend p = do-                unsafeUseAsCString input $ \i -> c_aes_gcm_aad p i (fromIntegral $ B.length input) -                peek p+gcmAppendAAD gcmSt input = unsafePerformIO doAppend+  where doAppend =+            withNewGCMSt gcmSt $ \gcmStPtr ->+            unsafeUseAsCString input $ \i ->+            c_aes_gcm_aad gcmStPtr i (fromIntegral $ B.length input)  -- | append data to encrypt and append to the GCM context -- -- bytestring need to be multiple of AES block size, unless it's the last call to this function. -- need to happen after AAD appending, or after initialization if no AAD data. {-# NOINLINE gcmAppendEncrypt #-}-gcmAppendEncrypt :: GCM -> ByteString -> (ByteString, GCM)-gcmAppendEncrypt gcm input = unsafePerformIO $ allocaFrom gcm doEnc-    where len = B.length input-          doEnc p = do-                output <- create len $ \o -> unsafeUseAsCString input $ \i -> c_aes_gcm_encrypt (castPtr o) p i (fromIntegral len)-                ngcm   <- peek p-                return (output, ngcm)+gcmAppendEncrypt :: AES -> GCM -> ByteString -> (ByteString, GCM)+gcmAppendEncrypt ctx gcm input = unsafePerformIO $ withGCMKeyAndCopySt ctx gcm doEnc+  where len = B.length input+        doEnc gcmStPtr aesPtr =+            create len $ \o ->+            unsafeUseAsCString input $ \i ->+            c_aes_gcm_encrypt (castPtr o) gcmStPtr aesPtr i (fromIntegral len)  -- | append data to decrypt and append to the GCM context -- -- bytestring need to be multiple of AES block size, unless it's the last call to this function. -- need to happen after AAD appending, or after initialization if no AAD data. {-# NOINLINE gcmAppendDecrypt #-}-gcmAppendDecrypt :: GCM -> ByteString -> (ByteString, GCM)-gcmAppendDecrypt gcm input = unsafePerformIO $ allocaFrom gcm doDec-    where len = B.length input-          doDec p = do-                output <- create len $ \o -> unsafeUseAsCString input $ \i -> c_aes_gcm_decrypt (castPtr o) p i (fromIntegral len)-                ngcm   <- peek p-                return (output, ngcm)+gcmAppendDecrypt :: AES -> GCM -> ByteString -> (ByteString, GCM)+gcmAppendDecrypt ctx gcm input = unsafePerformIO $ withGCMKeyAndCopySt ctx gcm doDec+  where len = B.length input+        doDec gcmStPtr aesPtr =+            create len $ \o ->+            unsafeUseAsCString input $ \i ->+            c_aes_gcm_decrypt (castPtr o) gcmStPtr aesPtr i (fromIntegral len)  -- | Generate the Tag from GCM context {-# NOINLINE gcmFinish #-}-gcmFinish :: GCM -> Int -> ByteString-gcmFinish gcm taglen = B.take taglen (unsafeCreate 16 $ \t -> allocaFrom gcm (finish t))-    where finish t p = c_aes_gcm_finish (castPtr t) p+gcmFinish :: AES -> GCM -> Int -> AuthTag+gcmFinish ctx gcm taglen = AuthTag $ B.take taglen computeTag+  where computeTag = unsafeCreate 16 $ \t ->+                        withGCMKeyAndCopySt ctx gcm (c_aes_gcm_finish (castPtr t)) >> return ()  foreign import ccall "aes.h aes_initkey"-    c_aes_init :: Ptr Key -> CString -> CUInt -> IO ()+    c_aes_init :: Ptr AES -> CString -> CUInt -> IO ()  foreign import ccall "aes.h aes_encrypt_ecb"-    c_aes_encrypt_ecb :: CString -> Ptr Key -> CString -> CUInt -> IO ()+    c_aes_encrypt_ecb :: CString -> Ptr AES -> CString -> CUInt -> IO ()  foreign import ccall "aes.h aes_decrypt_ecb"-    c_aes_decrypt_ecb :: CString -> Ptr Key -> CString -> CUInt -> IO ()+    c_aes_decrypt_ecb :: CString -> Ptr AES -> CString -> CUInt -> IO ()  foreign import ccall "aes.h aes_encrypt_cbc"-    c_aes_encrypt_cbc :: CString -> Ptr Key -> Ptr IV -> CString -> CUInt -> IO ()+    c_aes_encrypt_cbc :: CString -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ()  foreign import ccall "aes.h aes_decrypt_cbc"-    c_aes_decrypt_cbc :: CString -> Ptr Key -> Ptr IV -> CString -> CUInt -> IO ()+    c_aes_decrypt_cbc :: CString -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ()  foreign import ccall "aes.h aes_encrypt_xts"-    c_aes_encrypt_xts :: CString -> Ptr Key -> Ptr Key -> Ptr IV -> CUInt -> CString -> CUInt -> IO ()+    c_aes_encrypt_xts :: CString -> Ptr AES -> Ptr AES -> Ptr Word8 -> CUInt -> CString -> CUInt -> IO ()  foreign import ccall "aes.h aes_decrypt_xts"-    c_aes_decrypt_xts :: CString -> Ptr Key -> Ptr Key -> Ptr IV -> CUInt -> CString -> CUInt -> IO ()+    c_aes_decrypt_xts :: CString -> Ptr AES -> Ptr AES -> Ptr Word8 -> CUInt -> CString -> CUInt -> IO ()  foreign import ccall "aes.h aes_gen_ctr"-    c_aes_gen_ctr :: CString -> Ptr Key -> Ptr IV -> CUInt -> IO ()+    c_aes_gen_ctr :: CString -> Ptr AES -> Ptr Word8 -> CUInt -> IO ()  foreign import ccall "aes.h aes_encrypt_ctr"-    c_aes_encrypt_ctr :: CString -> Ptr Key -> Ptr IV -> CString -> CUInt -> IO ()+    c_aes_encrypt_ctr :: CString -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ()  foreign import ccall "aes.h aes_gcm_init"-    c_aes_gcm_init :: Ptr GCM -> Ptr Key -> Ptr IV -> CUInt -> IO ()+    c_aes_gcm_init :: Ptr GCM -> Ptr AES -> Ptr Word8 -> CUInt -> IO ()  foreign import ccall "aes.h aes_gcm_aad"     c_aes_gcm_aad :: Ptr GCM -> CString -> CUInt -> IO ()  foreign import ccall "aes.h aes_gcm_encrypt"-    c_aes_gcm_encrypt :: CString -> Ptr GCM -> CString -> CUInt -> IO ()+    c_aes_gcm_encrypt :: CString -> Ptr GCM -> Ptr AES -> CString -> CUInt -> IO ()  foreign import ccall "aes.h aes_gcm_decrypt"-    c_aes_gcm_decrypt :: CString -> Ptr GCM -> CString -> CUInt -> IO ()+    c_aes_gcm_decrypt :: CString -> Ptr GCM -> Ptr AES -> CString -> CUInt -> IO ()  foreign import ccall "aes.h aes_gcm_finish"-    c_aes_gcm_finish :: CString -> Ptr GCM -> IO ()+    c_aes_gcm_finish :: CString -> Ptr GCM -> Ptr AES -> IO ()
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2008-2012 Vincent Hanquez <vincent@snarc.org>+Copyright (c) 2008-2013 Vincent Hanquez <vincent@snarc.org>  All rights reserved. 
Tests/KATCBC.hs view
@@ -1,5 +1,5 @@ {-# LANGUAGE OverloadedStrings #-}-module KATCBC (vectors_encrypt, vectors_decrypt) where+module KATCBC where  import qualified Data.ByteString as B import Data.ByteString.Char8 ()
Tests/KATECB.hs view
@@ -1,4 +1,4 @@-module KATECB (vectors_encrypt, vectors_decrypt) where+module KATECB where  import qualified Data.ByteString as B 
Tests/KATGCM.hs view
@@ -1,5 +1,5 @@ {-# LANGUAGE OverloadedStrings #-}-module KATGCM (vectors_encrypt, vectors_decrypt) where+module KATGCM where  import qualified Data.ByteString as B import Data.ByteString.Char8 ()
Tests/KATXTS.hs view
@@ -1,5 +1,5 @@ {-# LANGUAGE OverloadedStrings #-}-module KATXTS (vectors_encrypt, vectors_decrypt) where+module KATXTS where  import qualified Data.ByteString as B import Data.ByteString.Char8 ()
Tests/Tests.hs view
@@ -9,138 +9,52 @@  import Test.QuickCheck import Test.QuickCheck.Test-import Test.Framework.Providers.QuickCheck2 (testProperty) +import Data.Byteable import qualified Data.ByteString as B import qualified Crypto.Cipher.AES as AES+import Crypto.Cipher.Types -- (iv128, IV(..), AuthTag(..), key128, key192, key256)+import Crypto.Cipher.Tests  import qualified KATECB import qualified KATCBC import qualified KATXTS import qualified KATGCM -encryptBlock initF encryptF key plaintext =-    B.unpack $ encryptF (initF (B.pack key)) plaintext--katECBTests vectors f = concatMap makeTests vectors-    where makeTests (name, v) = map (\(z,i) -> testProperty (name ++ " " ++ show i) $ makeTest z) $ zip v [0..]-               where makeTest (AES.initKey -> key,plaintext,expected) = assertEq expected $ f key plaintext--katCBCTests vectors f = concatMap makeTests vectors-    where makeTests (name, v) = map (\(z,i) -> testProperty (name ++ " " ++ show i) $ makeTest z) $ zip v [0..]-            where makeTest (AES.initKey -> key,AES.IV -> iv,plaintext,expected) = assertEq expected $ f key iv plaintext--katXTSTests vectors f = concatMap makeTests vectors-    where makeTests (name, v) = map (\(z,i) -> testProperty (name ++ " " ++ show i) $ makeTest z) $ zip v [0..]-              where makeTest (AES.initKey -> key1,AES.initKey -> key2, AES.IV -> iv,plaintext,_,expected) =-                        (assertEq expected $ f (key1,key2) iv 0 plaintext)--katGCMTests vectors f = concatMap makeTests vectors-    where makeTests (name, v) = map (\(z,i) -> testProperty (name ++ " " ++ show i) $ makeTest z) $ zip v [0..]-            where makeTest (AES.initKey -> key, AES.IV -> iv, aad, plaintext, expectedOutput, taglen, expectedTag) =-                        let (output,tag) = f key iv aad plaintext in-                        assertEq expectedOutput output && (assertEq tag expectedTag)---data ECBUnit = ECBUnit B.ByteString B.ByteString-    deriving (Show,Eq)-data CBCUnit = CBCUnit B.ByteString B.ByteString B.ByteString-    deriving (Show,Eq)-data CTRUnit = CTRUnit B.ByteString B.ByteString B.ByteString-    deriving (Show,Eq)-data XTSUnit = XTSUnit B.ByteString B.ByteString B.ByteString B.ByteString-    deriving (Show,Eq)-data GCMUnit = GCMUnit B.ByteString B.ByteString B.ByteString B.ByteString-    deriving (Show,Eq)-data KeyUnit = KeyUnit B.ByteString-    deriving (Show,Eq)--generateKeyOf size = B.pack <$> replicateM size arbitrary-generateKey = elements [16,24,32] >>= generateKeyOf--generateIv = B.pack <$> replicateM 16 arbitrary-generateIvGCM = choose (12,90) >>= \sz -> (B.pack <$> replicateM sz arbitrary)--generatePlaintextMultiple16 = choose (1,128) >>= \size -> replicateM (size*16) arbitrary >>= return . B.pack--generatePlaintext = choose (0,324) >>= \size -> replicateM size arbitrary >>= return . B.pack--instance Arbitrary ECBUnit where-    arbitrary = ECBUnit <$> generateKey-                        <*> generatePlaintextMultiple16--instance Arbitrary CBCUnit where-    arbitrary = CBCUnit <$> generateKey-                        <*> generateIv-                        <*> generatePlaintextMultiple16--instance Arbitrary CTRUnit where-    arbitrary = CTRUnit <$> generateKey-                        <*> generateIv-                        <*> generatePlaintext--instance Arbitrary GCMUnit where-    arbitrary = GCMUnit <$> generateKey-                        <*> generateIvGCM-                        <*> generatePlaintext-                        <*> generatePlaintext--instance Arbitrary XTSUnit where-    arbitrary = do-        size <- elements [16,32]-        XTSUnit <$> generateKeyOf size-                <*> generateKeyOf size-                <*> generateIv-                <*> generatePlaintextMultiple16--instance Arbitrary KeyUnit where-    arbitrary = KeyUnit <$> generateKey--idECBTests (ECBUnit (AES.initKey -> key) plaintext) =-    plaintext `assertEq` AES.decryptECB key (AES.encryptECB key plaintext)--idCBCTests (CBCUnit (AES.initKey -> key) (AES.IV -> iv) plaintext) =-    plaintext `assertEq` AES.decryptCBC key iv (AES.encryptCBC key iv plaintext)--idCTRTests (CTRUnit (AES.initKey -> key) (AES.IV -> iv) plaintext) =-    plaintext `assertEq` AES.decryptCTR key iv (AES.encryptCTR key iv plaintext)--idXTSTests (XTSUnit (AES.initKey -> key1) (AES.initKey -> key2) (AES.IV -> iv) plaintext) =-    plaintext `assertEq` AES.decryptXTS (key1, key2) iv 0 (AES.encryptXTS (key1, key2) iv 0 plaintext)+toKatECB (k,p,c) = KAT_ECB { ecbKey = k, ecbPlaintext = p, ecbCiphertext = c }+toKatCBC (k,iv,p,c) = KAT_CBC { cbcKey = k, cbcIV = iv, cbcPlaintext = p, cbcCiphertext = c }+toKatXTS (k1,k2,iv,p,_,c) = KAT_XTS { xtsKey1 = k1, xtsKey2 = k2, xtsIV = iv, xtsPlaintext = p, xtsCiphertext = c }+toKatGCM (k,iv,h,p,c,taglen,tag) =+    KAT_AEAD { aeadMode       = AEAD_GCM+             , aeadKey        = k+             , aeadIV         = iv+             , aeadHeader     = h+             , aeadPlaintext  = p+             , aeadCiphertext = c+             , aeadTaglen     = taglen+             , aeadTag        = AuthTag tag+             } -idGCMTests (GCMUnit (AES.initKey -> key) (AES.IV -> iv) aad plaintext) =-    let (cipherText, tag) = AES.encryptGCM key iv aad plaintext in-    let (plaintext2, tag2) = AES.decryptGCM key iv aad cipherText in-    (plaintext `assertEq` plaintext2) && (tag == tag2)+kats128 = defaultKATs+    { kat_ECB  = map toKatECB KATECB.vectors_aes128_enc+    , kat_CBC  = map toKatCBC KATCBC.vectors_aes128_enc+    , kat_XTS  = map toKatXTS KATXTS.vectors_aes128_enc+    , kat_AEAD = map toKatGCM KATGCM.vectors_aes128_enc+    } -idKey (KeyUnit keyBs) = keyBs == AES.keyOfCtx (AES.initKey keyBs)+kats192 = defaultKATs+    { kat_ECB  = map toKatECB KATECB.vectors_aes192_enc+    , kat_CBC  = map toKatCBC KATCBC.vectors_aes192_enc+    } -assertEq expected got-	| expected == got = True-	| otherwise       = error ("expected: " ++ showhex expected ++ " got: " ++ showhex got)-    where showhex = concatMap toHex . B.unpack-          toHex b = let (l,r) = b `divMod` 16 in map (toHexChar . fromIntegral) [l,r]-          toHexChar c-                  | c >= 0 && c <= 9   = toEnum (c + fromEnum '0')-                  | c >= 10 && c <= 16 = toEnum (c + fromEnum 'a')-                  | otherwise          = '_'+kats256 = defaultKATs+    { kat_ECB  = map toKatECB KATECB.vectors_aes256_enc+    , kat_CBC  = map toKatCBC KATCBC.vectors_aes256_enc+    , kat_XTS  = map toKatXTS KATXTS.vectors_aes256_enc+    } -tests =-    [ testProperty "key-id" idKey-    , testGroup "KAT-ECB-Encrypt" $ katECBTests KATECB.vectors_encrypt AES.encryptECB-    , testGroup "KAT-ECB-Decrypt" $ katECBTests KATECB.vectors_decrypt AES.decryptECB-    , testGroup "KAT-CBC-Encrypt" $ katCBCTests KATCBC.vectors_encrypt AES.encryptCBC-    , testGroup "KAT-CBC-Decrypt" $ katCBCTests KATCBC.vectors_decrypt AES.decryptCBC-    , testGroup "KAT-XTS-Encrypt" $ katXTSTests KATXTS.vectors_encrypt AES.encryptXTS-    , testGroup "KAT-XTS-Decrypt" $ katXTSTests KATXTS.vectors_decrypt AES.decryptXTS-    , testGroup "KAT-GCM-Encrypt" $ katGCMTests KATGCM.vectors_encrypt AES.encryptGCM-    , testGroup "decrypt-encrypt-is-ID"-        [ testProperty "ECB" idECBTests-        , testProperty "CBC" idCBCTests-        , testProperty "CTR" idCTRTests-        , testProperty "XTS" idXTSTests-        , testProperty "GCM" idGCMTests-        ]+main = defaultMain+    [ testBlockCipher kats128 (undefined :: AES.AES128)+    , testBlockCipher kats192 (undefined :: AES.AES192)+    , testBlockCipher kats256 (undefined :: AES.AES256)     ]--main = defaultMain tests
cbits/aes.c view
@@ -38,134 +38,363 @@ #include "gf.h" #include "aes_x86ni.h" -void aes_encrypt_block(aes_block *output, aes_key *key, aes_block *input)-{-#if defined(ARCH_X86) && defined(WITH_AESNI)-	if (have_aesni() && key->nbr == 10)-		return aes_ni_encrypt_ecb((uint8_t *) output, key, (uint8_t *) input, 1);+void aes_generic_encrypt_ecb(aes_block *output, aes_key *key, aes_block *input, uint32_t nb_blocks);+void aes_generic_decrypt_ecb(aes_block *output, aes_key *key, aes_block *input, uint32_t nb_blocks);+void aes_generic_encrypt_cbc(aes_block *output, aes_key *key, aes_block *iv, aes_block *input, uint32_t nb_blocks);+void aes_generic_decrypt_cbc(aes_block *output, aes_key *key, aes_block *iv, aes_block *input, uint32_t nb_blocks);+void aes_generic_encrypt_ctr(uint8_t *output, aes_key *key, aes_block *iv, uint8_t *input, uint32_t length);+void aes_generic_encrypt_xts(aes_block *output, aes_key *k1, aes_key *k2, aes_block *dataunit,+                             uint32_t spoint, aes_block *input, uint32_t nb_blocks);+void aes_generic_decrypt_xts(aes_block *output, aes_key *k1, aes_key *k2, aes_block *dataunit,+                             uint32_t spoint, aes_block *input, uint32_t nb_blocks);+void aes_generic_gcm_encrypt(uint8_t *output, aes_gcm *gcm, aes_key *key, uint8_t *input, uint32_t length);+void aes_generic_gcm_decrypt(uint8_t *output, aes_gcm *gcm, aes_key *key, uint8_t *input, uint32_t length);++enum {+	/* init */+	INIT_128, INIT_192, INIT_256,+	/* single block */+	ENCRYPT_BLOCK_128, ENCRYPT_BLOCK_192, ENCRYPT_BLOCK_256,+	DECRYPT_BLOCK_128, DECRYPT_BLOCK_192, DECRYPT_BLOCK_256,+	/* ecb */+	ENCRYPT_ECB_128, ENCRYPT_ECB_192, ENCRYPT_ECB_256,+	DECRYPT_ECB_128, DECRYPT_ECB_192, DECRYPT_ECB_256,+	/* cbc */+	ENCRYPT_CBC_128, ENCRYPT_CBC_192, ENCRYPT_CBC_256,+	DECRYPT_CBC_128, DECRYPT_CBC_192, DECRYPT_CBC_256,+	/* ctr */+	ENCRYPT_CTR_128, ENCRYPT_CTR_192, ENCRYPT_CTR_256,+	/* xts */+	ENCRYPT_XTS_128, ENCRYPT_XTS_192, ENCRYPT_XTS_256,+	DECRYPT_XTS_128, DECRYPT_XTS_192, DECRYPT_XTS_256,+	/* xts */+	ENCRYPT_GCM_128, ENCRYPT_GCM_192, ENCRYPT_GCM_256,+	DECRYPT_GCM_128, DECRYPT_GCM_192, DECRYPT_GCM_256,+};++void *branch_table[] = {+	/* INIT */+	[INIT_128]          = aes_generic_init,+	[INIT_192]          = aes_generic_init,+	[INIT_256]          = aes_generic_init,+	/* BLOCK */+	[ENCRYPT_BLOCK_128] = aes_generic_encrypt_block,+	[ENCRYPT_BLOCK_192] = aes_generic_encrypt_block,+	[ENCRYPT_BLOCK_256] = aes_generic_encrypt_block,+	[DECRYPT_BLOCK_128] = aes_generic_decrypt_block,+	[DECRYPT_BLOCK_192] = aes_generic_decrypt_block,+	[DECRYPT_BLOCK_256] = aes_generic_decrypt_block,+	/* ECB */+	[ENCRYPT_ECB_128]   = aes_generic_encrypt_ecb,+	[ENCRYPT_ECB_192]   = aes_generic_encrypt_ecb,+	[ENCRYPT_ECB_256]   = aes_generic_encrypt_ecb,+	[DECRYPT_ECB_128]   = aes_generic_decrypt_ecb,+	[DECRYPT_ECB_192]   = aes_generic_decrypt_ecb,+	[DECRYPT_ECB_256]   = aes_generic_decrypt_ecb,+	/* CBC */+	[ENCRYPT_CBC_128]   = aes_generic_encrypt_cbc,+	[ENCRYPT_CBC_192]   = aes_generic_encrypt_cbc,+	[ENCRYPT_CBC_256]   = aes_generic_encrypt_cbc,+	[DECRYPT_CBC_128]   = aes_generic_decrypt_cbc,+	[DECRYPT_CBC_192]   = aes_generic_decrypt_cbc,+	[DECRYPT_CBC_256]   = aes_generic_decrypt_cbc,+	/* CTR */+	[ENCRYPT_CTR_128]   = aes_generic_encrypt_ctr,+	[ENCRYPT_CTR_192]   = aes_generic_encrypt_ctr,+	[ENCRYPT_CTR_256]   = aes_generic_encrypt_ctr,+	/* XTS */+	[ENCRYPT_XTS_128]   = aes_generic_encrypt_xts,+	[ENCRYPT_XTS_192]   = aes_generic_encrypt_xts,+	[ENCRYPT_XTS_256]   = aes_generic_encrypt_xts,+	[DECRYPT_XTS_128]   = aes_generic_decrypt_xts,+	[DECRYPT_XTS_192]   = aes_generic_decrypt_xts,+	[DECRYPT_XTS_256]   = aes_generic_decrypt_xts,+	/* GCM */+	[ENCRYPT_GCM_128]   = aes_generic_gcm_encrypt,+	[ENCRYPT_GCM_192]   = aes_generic_gcm_encrypt,+	[ENCRYPT_GCM_256]   = aes_generic_gcm_encrypt,+	[DECRYPT_GCM_128]   = aes_generic_gcm_decrypt,+	[DECRYPT_GCM_192]   = aes_generic_gcm_decrypt,+	[DECRYPT_GCM_256]   = aes_generic_gcm_decrypt,+};++typedef void (*init_f)(aes_key *, uint8_t *, uint8_t);+typedef void (*ecb_f)(aes_block *output, aes_key *key, aes_block *input, uint32_t nb_blocks);+typedef void (*cbc_f)(aes_block *output, aes_key *key, aes_block *iv, aes_block *input, uint32_t nb_blocks);+typedef void (*ctr_f)(uint8_t *output, aes_key *key, aes_block *iv, uint8_t *input, uint32_t length);+typedef void (*xts_f)(aes_block *output, aes_key *k1, aes_key *k2, aes_block *dataunit, uint32_t spoint, aes_block *input, uint32_t nb_blocks);+typedef void (*gcm_crypt_f)(uint8_t *output, aes_gcm *gcm, aes_key *key, uint8_t *input, uint32_t length);+typedef void (*block_f)(aes_block *output, aes_key *key, aes_block *input);++#ifdef WITH_AESNI+#define GET_INIT(strength) \+	((init_f) (branch_table[INIT_128 + strength]))+#define GET_ECB_ENCRYPT(strength) \+	((ecb_f) (branch_table[ENCRYPT_ECB_128 + strength]))+#define GET_ECB_DECRYPT(strength) \+	((ecb_f) (branch_table[DECRYPT_ECB_128 + strength]))+#define GET_CBC_ENCRYPT(strength) \+	((cbc_f) (branch_table[ENCRYPT_CBC_128 + strength]))+#define GET_CBC_DECRYPT(strength) \+	((cbc_f) (branch_table[DECRYPT_CBC_128 + strength]))+#define GET_CTR_ENCRYPT(strength) \+	((ctr_f) (branch_table[ENCRYPT_CTR_128 + strength]))+#define GET_XTS_ENCRYPT(strength) \+	((xts_f) (branch_table[ENCRYPT_XTS_128 + strength]))+#define GET_XTS_DECRYPT(strength) \+	((xts_f) (branch_table[DECRYPT_XTS_128 + strength]))+#define GET_GCM_ENCRYPT(strength) \+	((gcm_crypt_f) (branch_table[ENCRYPT_GCM_128 + strength]))+#define GET_GCM_DECRYPT(strength) \+	((gcm_crypt_f) (branch_table[DECRYPT_GCM_128 + strength]))+#define aes_encrypt_block(o,k,i) \+	(((block_f) (branch_table[ENCRYPT_BLOCK_128 + k->strength]))(o,k,i))+#define aes_decrypt_block(o,k,i) \+	(((block_f) (branch_table[DECRYPT_BLOCK_128 + k->strength]))(o,k,i))+#else+#define GET_INIT(strenght) aes_generic_init+#define GET_ECB_ENCRYPT(strength) aes_generic_encrypt_ecb+#define GET_ECB_DECRYPT(strength) aes_generic_decrypt_ecb+#define GET_CBC_ENCRYPT(strength) aes_generic_encrypt_cbc+#define GET_CBC_DECRYPT(strength) aes_generic_decrypt_cbc+#define GET_CTR_ENCRYPT(strength) aes_generic_encrypt_ctr+#define GET_XTS_ENCRYPT(strength) aes_generic_encrypt_xts+#define GET_XTS_DECRYPT(strength) aes_generic_decrypt_xts+#define GET_GCM_ENCRYPT(strength) aes_generic_gcm_encrypt+#define GET_GCM_DECRYPT(strength) aes_generic_gcm_decrypt+#define aes_encrypt_block(o,k,i) aes_generic_encrypt_block(o,k,i)+#define aes_decrypt_block(o,k,i) aes-generic_decrypt_block(o,k,i) #endif-	aes_generic_encrypt_block(output, key, input);-} -void aes_decrypt_block(aes_block *output, aes_key *key, aes_block *input)+void initialize_table_ni(int aesni, int pclmul) {-#if defined(ARCH_X86) && defined(WITH_AESNI)-	if (have_aesni() && key->nbr == 10)-		return aes_ni_decrypt_ecb((uint8_t *) output, key, (uint8_t *) input, 1);-#endif-	aes_generic_decrypt_block(output, key, input);+	if (!aesni)+		return;+	branch_table[INIT_128] = aes_ni_init;+	branch_table[INIT_256] = aes_ni_init;++	branch_table[ENCRYPT_BLOCK_128] = aes_ni_encrypt_block128;+	branch_table[DECRYPT_BLOCK_128] = aes_ni_decrypt_block128;+	branch_table[ENCRYPT_BLOCK_256] = aes_ni_encrypt_block256;+	branch_table[DECRYPT_BLOCK_256] = aes_ni_decrypt_block256;+	/* ECB */+	branch_table[ENCRYPT_ECB_128] = aes_ni_encrypt_ecb128;+	branch_table[DECRYPT_ECB_128] = aes_ni_decrypt_ecb128;+	branch_table[ENCRYPT_ECB_256] = aes_ni_encrypt_ecb256;+	branch_table[DECRYPT_ECB_256] = aes_ni_decrypt_ecb256;+	/* CBC */+	branch_table[ENCRYPT_CBC_128] = aes_ni_encrypt_cbc128;+	branch_table[DECRYPT_CBC_128] = aes_ni_decrypt_cbc128;+	branch_table[ENCRYPT_CBC_256] = aes_ni_encrypt_cbc256;+	branch_table[DECRYPT_CBC_256] = aes_ni_decrypt_cbc256;+	/* CTR */+	branch_table[ENCRYPT_CTR_128] = aes_ni_encrypt_ctr128;+	branch_table[ENCRYPT_CTR_256] = aes_ni_encrypt_ctr256;+	/* XTS */+	branch_table[ENCRYPT_XTS_128] = aes_ni_encrypt_xts128;+	branch_table[ENCRYPT_XTS_256] = aes_ni_encrypt_xts256;+	/* GCM */+	branch_table[ENCRYPT_GCM_128] = aes_ni_gcm_encrypt128;+	branch_table[ENCRYPT_GCM_256] = aes_ni_gcm_encrypt256; }  void aes_initkey(aes_key *key, uint8_t *origkey, uint8_t size) { 	switch (size) {-	case 16: key->nbr = 10; break;-	case 24: key->nbr = 12; break;-	case 32: key->nbr = 14; break;+	case 16: key->nbr = 10; key->strength = 0; break;+	case 24: key->nbr = 12; key->strength = 1; break;+	case 32: key->nbr = 14; key->strength = 2; break; 	} #if defined(ARCH_X86) && defined(WITH_AESNI)-	if (have_aesni() && size == 16)-		return aes_ni_init(key, origkey, size);+	initialize_hw(initialize_table_ni); #endif-	aes_generic_init(key, origkey, size);+	init_f _init = GET_INIT(key->strength);+	_init(key, origkey, size); } -void aes_encrypt_ecb(uint8_t *output, aes_key *key, uint8_t *input, uint32_t nb_blocks)+void aes_encrypt_ecb(aes_block *output, aes_key *key, aes_block *input, uint32_t nb_blocks) {-	if (!nb_blocks)-		return;+	ecb_f e = GET_ECB_ENCRYPT(key->strength);+	e(output, key, input, nb_blocks);+} -#if defined(ARCH_X86) && defined(WITH_AESNI)-	if (have_aesni() && key->nbr == 10)-		return aes_ni_encrypt_ecb(output, key, input, nb_blocks);-#endif+void aes_decrypt_ecb(aes_block *output, aes_key *key, aes_block *input, uint32_t nb_blocks)+{+	ecb_f d = GET_ECB_DECRYPT(key->strength);+	d(output, key, input, nb_blocks);+} -	for ( ; nb_blocks-- > 0; input += 16, output += 16) {-		aes_encrypt_block((block128 *) output, key, (block128 *) input);-	}+void aes_encrypt_cbc(aes_block *output, aes_key *key, aes_block *iv, aes_block *input, uint32_t nb_blocks)+{+	cbc_f e = GET_CBC_ENCRYPT(key->strength);+	e(output, key, iv, input, nb_blocks); } -void aes_decrypt_ecb(uint8_t *output, aes_key *key, uint8_t *input, uint32_t nb_blocks)+void aes_decrypt_cbc(aes_block *output, aes_key *key, aes_block *iv, aes_block *input, uint32_t nb_blocks) {-	if (!nb_blocks)-		return;+	cbc_f d = GET_CBC_DECRYPT(key->strength);+	d(output, key, iv, input, nb_blocks);+} -#if defined(ARCH_X86) && defined(WITH_AESNI)-	if (have_aesni() && key->nbr == 10)-		return aes_ni_decrypt_ecb(output, key, input, nb_blocks);-#endif+void aes_gen_ctr(aes_block *output, aes_key *key, aes_block *iv, uint32_t nb_blocks)+{+	aes_block block; -	for ( ; nb_blocks-- > 0; input += 16, output += 16) {-		aes_decrypt_block((block128 *) output, key, (block128 *) input);+	/* preload IV in block */+	block128_copy(&block, iv);++	for ( ; nb_blocks-- > 0; output++, block128_inc_be(&block)) {+		aes_encrypt_block(output, key, &block); 	} } -void aes_encrypt_cbc(uint8_t *output, aes_key *key, aes_block *iv, uint8_t *input, uint32_t nb_blocks)+void aes_encrypt_ctr(uint8_t *output, aes_key *key, aes_block *iv, uint8_t *input, uint32_t len) {-	aes_block block;+	ctr_f e = GET_CTR_ENCRYPT(key->strength);+	e(output, key, iv, input, len);+} -	if (!nb_blocks)-		return;-#if defined(ARCH_X86) && defined(WITH_AESNI)-	if (have_aesni() && key->nbr == 10)-		return aes_ni_encrypt_cbc(output, key, (uint8_t *) iv, input, nb_blocks);-#endif+void aes_encrypt_xts(aes_block *output, aes_key *k1, aes_key *k2, aes_block *dataunit,+                     uint32_t spoint, aes_block *input, uint32_t nb_blocks)+{+	xts_f e = GET_XTS_ENCRYPT(k1->strength);+	e(output, k1, k2, dataunit, spoint, input, nb_blocks);+} -	/* preload IV in block */-	block128_copy(&block, iv);+void aes_decrypt_xts(aes_block *output, aes_key *k1, aes_key *k2, aes_block *dataunit,+                     uint32_t spoint, aes_block *input, uint32_t nb_blocks)+{+	aes_generic_decrypt_xts(output, k1, k2, dataunit, spoint, input, nb_blocks);+} -	for ( ; nb_blocks-- > 0; input += 16, output += 16) {-		block128_xor(&block, (block128 *) input);+void aes_gcm_encrypt(uint8_t *output, aes_gcm *gcm, aes_key *key, uint8_t *input, uint32_t length)+{+	gcm_crypt_f e = GET_GCM_ENCRYPT(key->strength);+	e(output, gcm, key, input, length);+} -		aes_encrypt_block(&block, key, &block);+void aes_gcm_decrypt(uint8_t *output, aes_gcm *gcm, aes_key *key, uint8_t *input, uint32_t length)+{+	gcm_crypt_f d = GET_GCM_DECRYPT(key->strength);+	d(output, gcm, key, input, length);+} -		block128_copy((block128 *) output, &block);-	}+static void gcm_ghash_add(aes_gcm *gcm, block128 *b)+{+	block128_xor(&gcm->tag, b);+	gf_mul(&gcm->tag, &gcm->h); } -void aes_decrypt_cbc(uint8_t *output, aes_key *key, aes_block *ivini, uint8_t *input, uint32_t nb_blocks)+void aes_gcm_init(aes_gcm *gcm, aes_key *key, uint8_t *iv, uint32_t len) {-	aes_block block,blocko;-	aes_block iv;+	gcm->length_aad = 0;+	gcm->length_input = 0; -	if (!nb_blocks)-		return;-#if defined(ARCH_X86) && defined(WITH_AESNI)-	if (have_aesni() && key->nbr == 10) {-		return aes_ni_decrypt_cbc(output, key, (uint8_t *) ivini, input, nb_blocks);+	block128_zero(&gcm->h);+	block128_zero(&gcm->tag);+	block128_zero(&gcm->iv);++	/* prepare H : encrypt_K(0^128) */+	aes_encrypt_block(&gcm->h, key, &gcm->h);++	if (len == 12) {+		block128_copy_bytes(&gcm->iv, iv, 12);+		gcm->iv.b[15] = 0x01;+	} else {+		uint32_t origlen = len << 3;+		int i;+		for (; len >= 16; len -= 16, iv += 16) {+			block128_xor(&gcm->iv, (block128 *) iv);+			gf_mul(&gcm->iv, &gcm->h);+		}+		if (len > 0) {+			block128_xor_bytes(&gcm->iv, iv, len);+			gf_mul(&gcm->iv, &gcm->h);+		}+		for (i = 15; origlen; --i, origlen >>= 8)+			gcm->iv.b[i] ^= (uint8_t) origlen;+		gf_mul(&gcm->iv, &gcm->h); 	}-#endif -	/* preload IV in block */-	block128_copy(&iv, ivini);+	block128_copy(&gcm->civ, &gcm->iv);+} -	aes_decrypt_block(&block, key, &block);+void aes_gcm_aad(aes_gcm *gcm, uint8_t *input, uint32_t length)+{+	gcm->length_aad += length;+	for (; length >= 16; input += 16, length -= 16) {+		gcm_ghash_add(gcm, (block128 *) input);+	}+	if (length > 0) {+		aes_block tmp;+		block128_zero(&tmp);+		block128_copy_bytes(&tmp, input, length);+		gcm_ghash_add(gcm, &tmp);+	} -	for ( ;nb_blocks-- > 0; input += 16, output += 16) {-		block128_copy(&block, (block128 *) input);+} -		aes_decrypt_block(&blocko, key, &block);+void aes_gcm_finish(uint8_t *tag, aes_gcm *gcm, aes_key *key)+{+	aes_block lblock;+	int i; -		block128_vxor((block128 *) output, &blocko, &iv);-		block128_copy(&iv, &block);+	/* tag = (tag-1 xor (lenbits(a) | lenbits(c)) ) . H */+	lblock.q[0] = cpu_to_be64(gcm->length_aad << 3);+	lblock.q[1] = cpu_to_be64(gcm->length_input << 3);+	gcm_ghash_add(gcm, &lblock);++	aes_encrypt_block(&lblock, key, &gcm->iv);+	block128_xor(&gcm->tag, &lblock);++	for (i = 0; i < 16; i++) {+		tag[i] = gcm->tag.b[i]; 	} } -void aes_gen_ctr(uint8_t *output, aes_key *key, aes_block *iv, uint32_t nb_blocks)+void aes_generic_encrypt_ecb(aes_block *output, aes_key *key, aes_block *input, uint32_t nb_blocks) {+	for ( ; nb_blocks-- > 0; input++, output++) {+		aes_generic_encrypt_block(output, key, input);+	}+}++void aes_generic_decrypt_ecb(aes_block *output, aes_key *key, aes_block *input, uint32_t nb_blocks)+{+	for ( ; nb_blocks-- > 0; input++, output++) {+		aes_generic_decrypt_block(output, key, input);+	}+}++void aes_generic_encrypt_cbc(aes_block *output, aes_key *key, aes_block *iv, aes_block *input, uint32_t nb_blocks)+{ 	aes_block block; -	if (!nb_blocks)-		return; 	/* preload IV in block */ 	block128_copy(&block, iv);+	for ( ; nb_blocks-- > 0; input++, output++) {+		block128_xor(&block, (block128 *) input);+		aes_generic_encrypt_block(&block, key, &block);+		block128_copy((block128 *) output, &block);+	}+} -	for ( ; nb_blocks-- > 0; output += 16, block128_inc_be(&block)) {-		aes_encrypt_block((block128 *) output, key, &block);+void aes_generic_decrypt_cbc(aes_block *output, aes_key *key, aes_block *ivini, aes_block *input, uint32_t nb_blocks)+{+	aes_block block, blocko;+	aes_block iv;++	/* preload IV in block */+	block128_copy(&iv, ivini);+	for ( ; nb_blocks-- > 0; input++, output++) {+		block128_copy(&block, (block128 *) input);+		aes_generic_decrypt_block(&blocko, key, &block);+		block128_vxor((block128 *) output, &blocko, &iv);+		block128_copy(&iv, &block); 	} } -void aes_encrypt_ctr(uint8_t *output, aes_key *key, aes_block *iv, uint8_t *input, uint32_t len)+void aes_generic_encrypt_ctr(uint8_t *output, aes_key *key, aes_block *iv, uint8_t *input, uint32_t len) { 	aes_block block, o; 	uint32_t nb_blocks = len / 16;@@ -183,27 +412,17 @@ 		aes_encrypt_block(&o, key, &block); 		for (i = 0; i < (len % 16); i++) { 			*output = ((uint8_t *) &o)[i] ^ *input;-			output += 1;-			input += 1;+			output++;+			input++; 		} 	} } -void aes_encrypt_xts(uint8_t *output, aes_key *k1, aes_key *k2, aes_block *dataunit,-                     uint32_t spoint, uint8_t *input, uint32_t nb_blocks)+void aes_generic_encrypt_xts(aes_block *output, aes_key *k1, aes_key *k2, aes_block *dataunit,+                             uint32_t spoint, aes_block *input, uint32_t nb_blocks) { 	aes_block block, tweak; -	if (!nb_blocks)-		return;--#if defined(ARCH_X86) && defined(WITH_AESNI)-	if (have_aesni() && k1->nbr == 10) {-		aes_ni_encrypt_xts(output, k1, k2, (uint8_t *) dataunit, spoint, input, nb_blocks);-		return;-	}-#endif- 	/* load IV and encrypt it using k2 as the tweak */ 	block128_copy(&tweak, dataunit); 	aes_encrypt_block(&tweak, k2, &tweak);@@ -212,21 +431,18 @@ 	while (spoint-- > 0) 		gf_mulx(&tweak); -	for ( ; nb_blocks-- > 0; input += 16, output += 16, gf_mulx(&tweak)) {-		block128_vxor(&block, (block128 *) input, &tweak);+	for ( ; nb_blocks-- > 0; input++, output++, gf_mulx(&tweak)) {+		block128_vxor(&block, input, &tweak); 		aes_encrypt_block(&block, k1, &block);-		block128_vxor((block128 *) output, &block, &tweak);+		block128_vxor(output, &block, &tweak); 	} } -void aes_decrypt_xts(uint8_t *output, aes_key *k1, aes_key *k2, aes_block *dataunit,-                     uint32_t spoint, uint8_t *input, uint32_t nb_blocks)+void aes_generic_decrypt_xts(aes_block *output, aes_key *k1, aes_key *k2, aes_block *dataunit,+                             uint32_t spoint, aes_block *input, uint32_t nb_blocks) { 	aes_block block, tweak; -	if (!nb_blocks)-		return;- 	/* load IV and encrypt it using k2 as the tweak */ 	block128_copy(&tweak, dataunit); 	aes_encrypt_block(&tweak, k2, &tweak);@@ -235,71 +451,14 @@ 	while (spoint-- > 0) 		gf_mulx(&tweak); -	for ( ; nb_blocks-- > 0; input += 16, output += 16, gf_mulx(&tweak)) {-		block128_vxor(&block, (block128 *) input, &tweak);+	for ( ; nb_blocks-- > 0; input++, output++, gf_mulx(&tweak)) {+		block128_vxor(&block, input, &tweak); 		aes_decrypt_block(&block, k1, &block);-		block128_vxor((block128 *) output, &block, &tweak);+		block128_vxor(output, &block, &tweak); 	} } -static void gcm_ghash_add(aes_gcm *gcm, block128 *b)-{-	block128_xor(&gcm->tag, b);-	gf_mul(&gcm->tag, &gcm->h);-}--void aes_gcm_init(aes_gcm *gcm, aes_key *key, uint8_t *iv, uint32_t len)-{-	gcm->length_aad = 0;-	gcm->length_input = 0;--	block128_zero(&gcm->h);-	block128_zero(&gcm->tag);-	block128_zero(&gcm->iv);--	memcpy(&gcm->key, key, sizeof(aes_key));--	/* prepare H : encrypt_K(0^128) */-	aes_encrypt_block(&gcm->h, key, &gcm->h);--	if (len == 12) {-		block128_copy_bytes(&gcm->iv, iv, 12);-		gcm->iv.b[15] = 0x01;-	} else {-		uint32_t origlen = len << 3;-		int i;-		for (; len >= 16; len -= 16, iv += 16) {-			block128_xor(&gcm->iv, (block128 *) iv);-			gf_mul(&gcm->iv, &gcm->h);-		}-		if (len > 0) {-			block128_xor_bytes(&gcm->iv, iv, len);-			gf_mul(&gcm->iv, &gcm->h);-		}-		for (i = 15; origlen; --i, origlen >>= 8)-			gcm->iv.b[i] ^= (uint8_t) origlen;-		gf_mul(&gcm->iv, &gcm->h);-	}--	block128_copy(&gcm->civ, &gcm->iv);-}--void aes_gcm_aad(aes_gcm *gcm, uint8_t *input, uint32_t length)-{-	gcm->length_aad += length;-	for (; length >= 16; input += 16, length -= 16) {-		gcm_ghash_add(gcm, (block128 *) input);-	}-	if (length > 0) {-		aes_block tmp;-		block128_zero(&tmp);-		block128_copy_bytes(&tmp, input, length);-		gcm_ghash_add(gcm, &tmp);-	}--}--void aes_gcm_encrypt(uint8_t *output, aes_gcm *gcm, uint8_t *input, uint32_t length)+void aes_generic_gcm_encrypt(uint8_t *output, aes_gcm *gcm, aes_key *key, uint8_t *input, uint32_t length) { 	aes_block out; @@ -307,7 +466,7 @@ 	for (; length >= 16; input += 16, output += 16, length -= 16) { 		block128_inc_be(&gcm->civ); -		aes_encrypt_block(&out, &gcm->key, &gcm->civ);+		aes_encrypt_block(&out, key, &gcm->civ); 		block128_xor(&out, (block128 *) input); 		gcm_ghash_add(gcm, &out); 		block128_copy((block128 *) output, &out);@@ -318,11 +477,11 @@  		block128_inc_be(&gcm->civ); 		/* create e(civ) in out */-		aes_encrypt_block(&out, &gcm->key, &gcm->civ);+		aes_encrypt_block(&out, key, &gcm->civ); 		/* initialize a tmp as input and xor it to e(civ) */ 		block128_zero(&tmp); 		block128_copy_bytes(&tmp, input, length);-		block128_xor_bytes(&tmp, out.b, length); +		block128_xor_bytes(&tmp, out.b, length);  		gcm_ghash_add(gcm, &tmp); @@ -332,7 +491,7 @@ 	} } -void aes_gcm_decrypt(uint8_t *output, aes_gcm *gcm, uint8_t *input, uint32_t length)+void aes_generic_gcm_decrypt(uint8_t *output, aes_gcm *gcm, aes_key *key, uint8_t *input, uint32_t length) { 	aes_block out; @@ -340,7 +499,7 @@ 	for (; length >= 16; input += 16, output += 16, length -= 16) { 		block128_inc_be(&gcm->civ); -		aes_encrypt_block(&out, &gcm->key, &gcm->civ);+		aes_encrypt_block(&out, key, &gcm->civ); 		gcm_ghash_add(gcm, (block128 *) input); 		block128_xor(&out, (block128 *) input); 		block128_copy((block128 *) output, &out);@@ -355,8 +514,8 @@ 		block128_copy_bytes(&tmp, input, length); 		gcm_ghash_add(gcm, &tmp); -		aes_encrypt_block(&out, &gcm->key, &gcm->civ);-		block128_xor_bytes(&tmp, out.b, length); +		aes_encrypt_block(&out, key, &gcm->civ);+		block128_xor_bytes(&tmp, out.b, length);  		for (i = 0; i < length; i++) { 			output[i] = tmp.b[i];@@ -364,20 +523,3 @@ 	} } -void aes_gcm_finish(uint8_t *tag, aes_gcm *gcm)-{-	aes_block lblock;-	int i;--	/* tag = (tag-1 xor (lenbits(a) | lenbits(c)) ) . H */-	lblock.q[0] = cpu_to_be64(gcm->length_aad << 3);-	lblock.q[1] = cpu_to_be64(gcm->length_input << 3);-	gcm_ghash_add(gcm, &lblock);--	aes_encrypt_block(&lblock, &gcm->key, &gcm->iv);-	block128_xor(&gcm->tag, &lblock);--	for (i = 0; i < 16; i++) {-		tag[i] = gcm->tag.b[i];-	}-}
cbits/aes.h view
@@ -37,13 +37,15 @@  typedef block128 aes_block; +/* size = 456 */ typedef struct { 	uint8_t nbr; /* number of rounds: 10 (128), 12 (192), 14 (256) */-	uint8_t _padding[7];+	uint8_t strength; /* 128 = 0, 192 = 1, 256 = 2 */+	uint8_t _padding[6]; 	uint8_t data[16*14*2]; } aes_key; -/* size = 4*16+2*8+aes_key=456 = 536 */+/* size = 4*16+2*8= 80 */ typedef struct { 	aes_block tag; 	aes_block h;@@ -51,7 +53,6 @@ 	aes_block civ; 	uint64_t length_aad; 	uint64_t length_input;-	aes_key key; } aes_gcm;  /* in bytes: either 16,24,32 */@@ -60,22 +61,23 @@ void aes_encrypt(aes_block *output, aes_key *key, aes_block *input); void aes_decrypt(aes_block *output, aes_key *key, aes_block *input); -void aes_encrypt_ecb(uint8_t *output, aes_key *key, uint8_t *input, uint32_t nb_blocks);-void aes_decrypt_ecb(uint8_t *output, aes_key *key, uint8_t *input, uint32_t nb_blocks);+void aes_encrypt_ecb(aes_block *output, aes_key *key, aes_block *input, uint32_t nb_blocks);+void aes_decrypt_ecb(aes_block *output, aes_key *key, aes_block *input, uint32_t nb_blocks); -void aes_encrypt_cbc(uint8_t *output, aes_key *key, aes_block *iv, uint8_t *input, uint32_t nb_blocks);-void aes_decrypt_cbc(uint8_t *output, aes_key *key, aes_block *iv, uint8_t *input, uint32_t nb_blocks);+void aes_encrypt_cbc(aes_block *output, aes_key *key, aes_block *iv, aes_block *input, uint32_t nb_blocks);+void aes_decrypt_cbc(aes_block *output, aes_key *key, aes_block *iv, aes_block *input, uint32_t nb_blocks); -void aes_gen_ctr(uint8_t *output, aes_key *key, aes_block *iv, uint32_t nb_blocks);+void aes_gen_ctr(aes_block *output, aes_key *key, aes_block *iv, uint32_t nb_blocks); -void aes_encrypt_xts(uint8_t *output, aes_key *key, aes_key *key2, aes_block *sector,-                     uint32_t spoint, uint8_t *input, uint32_t nb_blocks);-void aes_decrypt_xts(uint8_t *output, aes_key *key, aes_key *key2, aes_block *sector,-                     uint32_t spoint, uint8_t *input, uint32_t nb_blocks);+void aes_encrypt_xts(aes_block *output, aes_key *key, aes_key *key2, aes_block *sector,+                     uint32_t spoint, aes_block *input, uint32_t nb_blocks);+void aes_decrypt_xts(aes_block *output, aes_key *key, aes_key *key2, aes_block *sector,+                     uint32_t spoint, aes_block *input, uint32_t nb_blocks);  void aes_gcm_init(aes_gcm *gcm, aes_key *key, uint8_t *iv, uint32_t len); void aes_gcm_aad(aes_gcm *gcm, uint8_t *input, uint32_t length);-void aes_gcm_encrypt(uint8_t *output, aes_gcm *gcm, uint8_t *input, uint32_t length);-void aes_gcm_finish(uint8_t *tag, aes_gcm *gcm);+void aes_gcm_encrypt(uint8_t *output, aes_gcm *gcm, aes_key *key, uint8_t *input, uint32_t length);+void aes_gcm_decrypt(uint8_t *output, aes_gcm *gcm, aes_key *key, uint8_t *input, uint32_t length);+void aes_gcm_finish(uint8_t *tag, aes_gcm *gcm, aes_key *key);  #endif
cbits/aes_x86ni.c view
@@ -1,5 +1,5 @@ /*- * Copyright (c) 2012 Vincent Hanquez <vincent@snarc.org>+ * Copyright (c) 2012-2013 Vincent Hanquez <vincent@snarc.org>  *   * All rights reserved.  * @@ -32,70 +32,154 @@  #include <wmmintrin.h> #include <tmmintrin.h>+#include <string.h> #include "aes.h" #include "aes_x86ni.h"+#include "block128.h" #include "cpu.h"  #ifdef ARCH_X86 #define ALIGN_UP(addr, size) (((addr) + ((size) - 1)) & (~((size) - 1))) #define ALIGNMENT(n) __attribute__((aligned(n))) -static __m128i aes_128_key_expansion(__m128i key, __m128i keygened)+static __m128i aes_128_key_expansion(__m128i key, __m128i keygened, int shuffle) {-	keygened = _mm_shuffle_epi32(keygened, _MM_SHUFFLE(3,3,3,3));+	keygened = _mm_shuffle_epi32(keygened, shuffle); 	key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); 	key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); 	key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); 	return _mm_xor_si128(key, keygened); } -static void aes_generate_key128(aes_key *key, uint8_t *ikey)+void aes_ni_init(aes_key *key, uint8_t *ikey, uint8_t size) {-	__m128i k[20];+	__m128i k[28]; 	uint64_t *out = (uint64_t *) key->data; 	int i; -	k[0] = _mm_loadu_si128((const __m128i*) ikey);+	switch (size) {+	case 16:+		k[0] = _mm_loadu_si128((const __m128i*) ikey); -#define AES_128_key_exp(K, RCON) aes_128_key_expansion(K, _mm_aeskeygenassist_si128(K, RCON))-	k[1]  = AES_128_key_exp(k[0], 0x01);-	k[2]  = AES_128_key_exp(k[1], 0x02);-	k[3]  = AES_128_key_exp(k[2], 0x04);-	k[4]  = AES_128_key_exp(k[3], 0x08);-	k[5]  = AES_128_key_exp(k[4], 0x10);-	k[6]  = AES_128_key_exp(k[5], 0x20);-	k[7]  = AES_128_key_exp(k[6], 0x40);-	k[8]  = AES_128_key_exp(k[7], 0x80);-	k[9]  = AES_128_key_exp(k[8], 0x1B);-	k[10] = AES_128_key_exp(k[9], 0x36);+		#define AES_128_key_exp(K, RCON) aes_128_key_expansion(K, _mm_aeskeygenassist_si128(K, RCON), 0xff)+		k[1]  = AES_128_key_exp(k[0], 0x01);+		k[2]  = AES_128_key_exp(k[1], 0x02);+		k[3]  = AES_128_key_exp(k[2], 0x04);+		k[4]  = AES_128_key_exp(k[3], 0x08);+		k[5]  = AES_128_key_exp(k[4], 0x10);+		k[6]  = AES_128_key_exp(k[5], 0x20);+		k[7]  = AES_128_key_exp(k[6], 0x40);+		k[8]  = AES_128_key_exp(k[7], 0x80);+		k[9]  = AES_128_key_exp(k[8], 0x1B);+		k[10] = AES_128_key_exp(k[9], 0x36); -	/* generate decryption keys in reverse order.-	 * k[10] is shared by last encryption and first decryption rounds-	 * k[20] is shared by first encryption round (and is the original user key) */-	k[11] = _mm_aesimc_si128(k[9]);-	k[12] = _mm_aesimc_si128(k[8]);-	k[13] = _mm_aesimc_si128(k[7]);-	k[14] = _mm_aesimc_si128(k[6]);-	k[15] = _mm_aesimc_si128(k[5]);-	k[16] = _mm_aesimc_si128(k[4]);-	k[17] = _mm_aesimc_si128(k[3]);-	k[18] = _mm_aesimc_si128(k[2]);-	k[19] = _mm_aesimc_si128(k[1]);+		/* generate decryption keys in reverse order.+		 * k[10] is shared by last encryption and first decryption rounds+		 * k[20] is shared by first encryption round (and is the original user key) */+		k[11] = _mm_aesimc_si128(k[9]);+		k[12] = _mm_aesimc_si128(k[8]);+		k[13] = _mm_aesimc_si128(k[7]);+		k[14] = _mm_aesimc_si128(k[6]);+		k[15] = _mm_aesimc_si128(k[5]);+		k[16] = _mm_aesimc_si128(k[4]);+		k[17] = _mm_aesimc_si128(k[3]);+		k[18] = _mm_aesimc_si128(k[2]);+		k[19] = _mm_aesimc_si128(k[1]); -	for (i = 0; i < 20; i++)-		_mm_storeu_si128(((__m128i *) out) + i, k[i]);+		for (i = 0; i < 20; i++)+			_mm_storeu_si128(((__m128i *) out) + i, k[i]);+		break;+	case 32:+#define AES_256_key_exp_1(K1, K2, RCON) aes_128_key_expansion(K1, _mm_aeskeygenassist_si128(K2, RCON), 0xff)+#define AES_256_key_exp_2(K1, K2)       aes_128_key_expansion(K1, _mm_aeskeygenassist_si128(K2, 0x00), 0xaa)+		k[0]  = _mm_loadu_si128((const __m128i*) ikey);+		k[1]  = _mm_loadu_si128((const __m128i*) (ikey+16));+		k[2]  = AES_256_key_exp_1(k[0], k[1], 0x01);+		k[3]  = AES_256_key_exp_2(k[1], k[2]);+		k[4]  = AES_256_key_exp_1(k[2], k[3], 0x02);+		k[5]  = AES_256_key_exp_2(k[3], k[4]);+		k[6]  = AES_256_key_exp_1(k[4], k[5], 0x04);+		k[7]  = AES_256_key_exp_2(k[5], k[6]);+		k[8]  = AES_256_key_exp_1(k[6], k[7], 0x08);+		k[9]  = AES_256_key_exp_2(k[7], k[8]);+		k[10] = AES_256_key_exp_1(k[8], k[9], 0x10);+		k[11] = AES_256_key_exp_2(k[9], k[10]);+		k[12] = AES_256_key_exp_1(k[10], k[11], 0x20);+		k[13] = AES_256_key_exp_2(k[11], k[12]);+		k[14] = AES_256_key_exp_1(k[12], k[13], 0x40);++		k[15] = _mm_aesimc_si128(k[13]);+		k[16] = _mm_aesimc_si128(k[12]);+		k[17] = _mm_aesimc_si128(k[11]);+		k[18] = _mm_aesimc_si128(k[10]);+		k[19] = _mm_aesimc_si128(k[9]);+		k[20] = _mm_aesimc_si128(k[8]);+		k[21] = _mm_aesimc_si128(k[7]);+		k[22] = _mm_aesimc_si128(k[6]);+		k[23] = _mm_aesimc_si128(k[5]);+		k[24] = _mm_aesimc_si128(k[4]);+		k[25] = _mm_aesimc_si128(k[3]);+		k[26] = _mm_aesimc_si128(k[2]);+		k[27] = _mm_aesimc_si128(k[1]);+		for (i = 0; i < 28; i++)+			_mm_storeu_si128(((__m128i *) out) + i, k[i]);+		break;+	default:+		break;+	} } -void aes_ni_init(aes_key *key, uint8_t *origkey, uint8_t size)+/* TO OPTIMISE: use pcmulqdq... or some faster code.+ * this is the lamest way of doing it, but i'm out of time.+ * this is basically a copy of gf_mulx in gf.c */+static __m128i gfmulx(__m128i v) {-	switch (size) {-	case 16: aes_generate_key128(key, origkey); break;-	default: break;-	}+	uint64_t v_[2] ALIGNMENT(16);+	const uint64_t gf_mask = 0x8000000000000000;++	_mm_store_si128((__m128i *) v_, v);+	uint64_t r = ((v_[1] & gf_mask) ? 0x87 : 0);+	v_[1] = (v_[1] << 1) | (v_[0] & gf_mask ? 1 : 0);+	v_[0] = (v_[0] << 1) ^ r;+	v = _mm_load_si128((__m128i *) v_);+	return v; } +static void unopt_gf_mul(block128 *a, block128 *b)+{+	uint64_t a0, a1, v0, v1;+	int i, j; -#define PRELOAD_ENC_KEYS(k) \+	a0 = a1 = 0;+	v0 = cpu_to_be64(a->q[0]);+	v1 = cpu_to_be64(a->q[1]);++	for (i = 0; i < 16; i++)+		for (j = 0x80; j != 0; j >>= 1) {+			uint8_t x = b->b[i] & j;+			a0 ^= x ? v0 : 0;+			a1 ^= x ? v1 : 0;+			x = (uint8_t) v1 & 1;+			v1 = (v1 >> 1) | (v0 << 63);+			v0 = (v0 >> 1) ^ (x ? (0xe1ULL << 56) : 0);+		}+	a->q[0] = cpu_to_be64(a0);+	a->q[1] = cpu_to_be64(a1);+}++static __m128i ghash_add(__m128i tag, __m128i h, __m128i m)+{+	aes_block _t, _h;+	tag = _mm_xor_si128(tag, m);++	_mm_store_si128((__m128i *) &_t, tag);+	_mm_store_si128((__m128i *) &_h, h);+	unopt_gf_mul(&_t, &_h);+	tag = _mm_load_si128((__m128i *) &_t);+	return tag;+}++#define PRELOAD_ENC_KEYS128(k) \ 	__m128i K0  = _mm_loadu_si128(((__m128i *) k)+0); \ 	__m128i K1  = _mm_loadu_si128(((__m128i *) k)+1); \ 	__m128i K2  = _mm_loadu_si128(((__m128i *) k)+2); \@@ -108,7 +192,14 @@ 	__m128i K9  = _mm_loadu_si128(((__m128i *) k)+9); \ 	__m128i K10 = _mm_loadu_si128(((__m128i *) k)+10); -#define DO_ENC_BLOCK(m) \+#define PRELOAD_ENC_KEYS256(k) \+	PRELOAD_ENC_KEYS128(k) \+	__m128i K11 = _mm_loadu_si128(((__m128i *) k)+11); \+	__m128i K12 = _mm_loadu_si128(((__m128i *) k)+12); \+	__m128i K13 = _mm_loadu_si128(((__m128i *) k)+13); \+	__m128i K14 = _mm_loadu_si128(((__m128i *) k)+14);++#define DO_ENC_BLOCK128(m) \ 	m = _mm_xor_si128(m, K0); \ 	m = _mm_aesenc_si128(m, K1); \ 	m = _mm_aesenc_si128(m, K2); \@@ -121,20 +212,49 @@ 	m = _mm_aesenc_si128(m, K9); \ 	m = _mm_aesenclast_si128(m, K10); -#define PRELOAD_DEC_KEYS(k) \-	__m128i K0  = _mm_loadu_si128(((__m128i *) k)+10+0); \-	__m128i K1  = _mm_loadu_si128(((__m128i *) k)+10+1); \-	__m128i K2  = _mm_loadu_si128(((__m128i *) k)+10+2); \-	__m128i K3  = _mm_loadu_si128(((__m128i *) k)+10+3); \-	__m128i K4  = _mm_loadu_si128(((__m128i *) k)+10+4); \-	__m128i K5  = _mm_loadu_si128(((__m128i *) k)+10+5); \-	__m128i K6  = _mm_loadu_si128(((__m128i *) k)+10+6); \-	__m128i K7  = _mm_loadu_si128(((__m128i *) k)+10+7); \-	__m128i K8  = _mm_loadu_si128(((__m128i *) k)+10+8); \-	__m128i K9  = _mm_loadu_si128(((__m128i *) k)+10+9); \+#define DO_ENC_BLOCK256(m) \+	m = _mm_xor_si128(m, K0); \+	m = _mm_aesenc_si128(m, K1); \+	m = _mm_aesenc_si128(m, K2); \+	m = _mm_aesenc_si128(m, K3); \+	m = _mm_aesenc_si128(m, K4); \+	m = _mm_aesenc_si128(m, K5); \+	m = _mm_aesenc_si128(m, K6); \+	m = _mm_aesenc_si128(m, K7); \+	m = _mm_aesenc_si128(m, K8); \+	m = _mm_aesenc_si128(m, K9); \+	m = _mm_aesenc_si128(m, K10); \+	m = _mm_aesenc_si128(m, K11); \+	m = _mm_aesenc_si128(m, K12); \+	m = _mm_aesenc_si128(m, K13); \+	m = _mm_aesenclast_si128(m, K14);++/* load K0 at K9 from index 'at' */+#define PRELOAD_DEC_KEYS_AT(k, at) \+	__m128i K0  = _mm_loadu_si128(((__m128i *) k)+at+0); \+	__m128i K1  = _mm_loadu_si128(((__m128i *) k)+at+1); \+	__m128i K2  = _mm_loadu_si128(((__m128i *) k)+at+2); \+	__m128i K3  = _mm_loadu_si128(((__m128i *) k)+at+3); \+	__m128i K4  = _mm_loadu_si128(((__m128i *) k)+at+4); \+	__m128i K5  = _mm_loadu_si128(((__m128i *) k)+at+5); \+	__m128i K6  = _mm_loadu_si128(((__m128i *) k)+at+6); \+	__m128i K7  = _mm_loadu_si128(((__m128i *) k)+at+7); \+	__m128i K8  = _mm_loadu_si128(((__m128i *) k)+at+8); \+	__m128i K9  = _mm_loadu_si128(((__m128i *) k)+at+9); \++#define PRELOAD_DEC_KEYS128(k) \+	PRELOAD_DEC_KEYS_AT(k, 10) \ 	__m128i K10 = _mm_loadu_si128(((__m128i *) k)+0); -#define DO_DEC_BLOCK(m) \+#define PRELOAD_DEC_KEYS256(k) \+	PRELOAD_DEC_KEYS_AT(k, 14) \+	__m128i K10 = _mm_loadu_si128(((__m128i *) k)+14+10); \+	__m128i K11 = _mm_loadu_si128(((__m128i *) k)+14+11); \+	__m128i K12 = _mm_loadu_si128(((__m128i *) k)+14+12); \+	__m128i K13 = _mm_loadu_si128(((__m128i *) k)+14+13); \+	__m128i K14 = _mm_loadu_si128(((__m128i *) k)+0);++#define DO_DEC_BLOCK128(m) \ 	m = _mm_xor_si128(m, K0); \ 	m = _mm_aesdec_si128(m, K1); \ 	m = _mm_aesdec_si128(m, K2); \@@ -147,128 +267,52 @@ 	m = _mm_aesdec_si128(m, K9); \ 	m = _mm_aesdeclast_si128(m, K10); -void aes_ni_encrypt_ecb(uint8_t *out, aes_key *key, uint8_t *in, uint32_t blocks)-{-	__m128i *k = (__m128i *) key->data;--	PRELOAD_ENC_KEYS(k);--	while (blocks-- > 0) {-		__m128i m = _mm_loadu_si128((__m128i *) in);--		DO_ENC_BLOCK(m);--		_mm_storeu_si128((__m128i *) out, m);-		in += 16;-		out += 16;-	}-}--void aes_ni_decrypt_ecb(uint8_t *out, aes_key *key, uint8_t *in, uint32_t blocks)-{-	__m128i *k = (__m128i *) key->data;--	PRELOAD_DEC_KEYS(k);--	while (blocks-- > 0) {-		__m128i m = _mm_loadu_si128((__m128i *) in);--		DO_DEC_BLOCK(m);--		_mm_storeu_si128((__m128i *) out, m);-		in += 16;-		out += 16;-	}-}--void aes_ni_encrypt_cbc(uint8_t *out, aes_key *key, uint8_t *_iv, uint8_t *in, uint32_t blocks)-{-	__m128i *k = (__m128i *) key->data;-	__m128i iv = _mm_loadu_si128((__m128i *) _iv);--	PRELOAD_ENC_KEYS(k);--	while (blocks-- > 0) {-		__m128i m = _mm_loadu_si128((__m128i *) in);-		m = _mm_xor_si128(m, iv);--		DO_ENC_BLOCK(m);--		_mm_storeu_si128((__m128i *) out, m);-		iv = m;--		in += 16;-		out += 16;-	}-}--void aes_ni_decrypt_cbc(uint8_t *out, aes_key *key, uint8_t *_iv, uint8_t *in, uint32_t blocks)-{-	__m128i *k = (__m128i *) key->data;-	__m128i iv = _mm_loadu_si128((__m128i *) _iv);--	PRELOAD_DEC_KEYS(k);--	while (blocks-- > 0) {-		__m128i m = _mm_loadu_si128((__m128i *) in);-		__m128i ivnext = m;--		DO_DEC_BLOCK(m);-		m = _mm_xor_si128(m, iv);--		_mm_storeu_si128((__m128i *) out, m);-		iv = ivnext;--		in += 16;-		out += 16;-	}-}--/* TO OPTIMISE: use pcmulqdq... or some faster code.- * this is the lamest way of doing it, but i'm out of time.- * this is basically a copy of gf_mulx in gf.c */-static __m128i gfmulx(__m128i v)-{-	uint64_t v_[2] ALIGNMENT(16);-	const uint64_t gf_mask = 0x8000000000000000;--	_mm_store_si128((__m128i *) v_, v);-	uint64_t r = ((v_[1] & gf_mask) ? 0x87 : 0);-	v_[1] = (v_[1] << 1) | (v_[0] & gf_mask ? 1 : 0);-	v_[0] = (v_[0] << 1) ^ r;-	v = _mm_load_si128((__m128i *) v_);-	return v;-}--void aes_ni_encrypt_xts(uint8_t *out, aes_key *key1, aes_key *key2,-                        uint8_t *_tweak, uint32_t spoint, uint8_t *in, uint32_t blocks)-{-	__m128i tweak = _mm_loadu_si128((__m128i *) _tweak);--	do {-		__m128i *k2 = (__m128i *) key2->data;-		PRELOAD_ENC_KEYS(k2);-		DO_ENC_BLOCK(tweak);--		while (spoint-- > 0)-			tweak = gfmulx(tweak);-	} while (0) ;+#define DO_DEC_BLOCK256(m) \+	m = _mm_xor_si128(m, K0); \+	m = _mm_aesdec_si128(m, K1); \+	m = _mm_aesdec_si128(m, K2); \+	m = _mm_aesdec_si128(m, K3); \+	m = _mm_aesdec_si128(m, K4); \+	m = _mm_aesdec_si128(m, K5); \+	m = _mm_aesdec_si128(m, K6); \+	m = _mm_aesdec_si128(m, K7); \+	m = _mm_aesdec_si128(m, K8); \+	m = _mm_aesdec_si128(m, K9); \+	m = _mm_aesdec_si128(m, K10); \+	m = _mm_aesdec_si128(m, K11); \+	m = _mm_aesdec_si128(m, K12); \+	m = _mm_aesdec_si128(m, K13); \+	m = _mm_aesdeclast_si128(m, K14); -	do {-		__m128i *k1 = (__m128i *) key1->data;-		PRELOAD_ENC_KEYS(k1);+#define SIZE 128+#define SIZED(m) m##128+#define PRELOAD_ENC PRELOAD_ENC_KEYS128+#define DO_ENC_BLOCK DO_ENC_BLOCK128+#define PRELOAD_DEC PRELOAD_DEC_KEYS128+#define DO_DEC_BLOCK DO_DEC_BLOCK128+#include "aes_x86ni_impl.c" -		for ( ; blocks-- > 0; in += 16, out += 16, tweak = gfmulx(tweak)) {-			__m128i m = _mm_loadu_si128((__m128i *) in);+#undef SIZE+#undef SIZED+#undef PRELOAD_ENC+#undef PRELOAD_DEC+#undef DO_ENC_BLOCK+#undef DO_DEC_BLOCK -			m = _mm_xor_si128(m, tweak);-			DO_ENC_BLOCK(m);-			m = _mm_xor_si128(m, tweak);+#define SIZED(m) m##256+#define SIZE 256+#define PRELOAD_ENC PRELOAD_ENC_KEYS256+#define DO_ENC_BLOCK DO_ENC_BLOCK256+#define PRELOAD_DEC PRELOAD_DEC_KEYS256+#define DO_DEC_BLOCK DO_DEC_BLOCK256+#include "aes_x86ni_impl.c" -			_mm_storeu_si128((__m128i *) out, m);-		}-	} while (0);-}+#undef SIZE+#undef SIZED+#undef PRELOAD_ENC+#undef PRELOAD_DEC+#undef DO_ENC_BLOCK+#undef DO_DEC_BLOCK  #endif 
cbits/aes_x86ni.h view
@@ -38,14 +38,39 @@ #include <wmmintrin.h> #include <tmmintrin.h> #include "aes.h"+#include "block128.h" +#ifdef IMPL_DEBUG+static void block128_sse_print(__m128i m)+{+	block128 b;+	_mm_storeu_si128((__m128i *) &b.b, m);+	block128_print(&b);+}+#endif+ void aes_ni_init(aes_key *key, uint8_t *origkey, uint8_t size);-void aes_ni_encrypt_ecb(uint8_t *out, aes_key *key, uint8_t *in, uint32_t blocks);-void aes_ni_decrypt_ecb(uint8_t *out, aes_key *key, uint8_t *in, uint32_t blocks);-void aes_ni_encrypt_cbc(uint8_t *out, aes_key *key, uint8_t *_iv, uint8_t *in, uint32_t blocks);-void aes_ni_decrypt_cbc(uint8_t *out, aes_key *key, uint8_t *_iv, uint8_t *in, uint32_t blocks);-void aes_ni_encrypt_xts(uint8_t *out, aes_key *key1, aes_key *key2,-                        uint8_t *_tweak, uint32_t spoint, uint8_t *in, uint32_t blocks);+void aes_ni_encrypt_block128(aes_block *out, aes_key *key, aes_block *in);+void aes_ni_encrypt_block256(aes_block *out, aes_key *key, aes_block *in);+void aes_ni_decrypt_block128(aes_block *out, aes_key *key, aes_block *in);+void aes_ni_decrypt_block256(aes_block *out, aes_key *key, aes_block *in);+void aes_ni_encrypt_ecb128(aes_block *out, aes_key *key, aes_block *in, uint32_t blocks);+void aes_ni_encrypt_ecb256(aes_block *out, aes_key *key, aes_block *in, uint32_t blocks);+void aes_ni_decrypt_ecb128(aes_block *out, aes_key *key, aes_block *in, uint32_t blocks);+void aes_ni_decrypt_ecb256(aes_block *out, aes_key *key, aes_block *in, uint32_t blocks);+void aes_ni_encrypt_cbc128(aes_block *out, aes_key *key, aes_block *_iv, aes_block *in, uint32_t blocks);+void aes_ni_encrypt_cbc256(aes_block *out, aes_key *key, aes_block *_iv, aes_block *in, uint32_t blocks);+void aes_ni_decrypt_cbc128(aes_block *out, aes_key *key, aes_block *_iv, aes_block *in, uint32_t blocks);+void aes_ni_decrypt_cbc256(aes_block *out, aes_key *key, aes_block *_iv, aes_block *in, uint32_t blocks);+void aes_ni_encrypt_ctr128(uint8_t *out, aes_key *key, aes_block *_iv, uint8_t *in, uint32_t length);+void aes_ni_encrypt_ctr256(uint8_t *out, aes_key *key, aes_block *_iv, uint8_t *in, uint32_t length);+void aes_ni_encrypt_xts128(aes_block *out, aes_key *key1, aes_key *key2,+                           aes_block *_tweak, uint32_t spoint, aes_block *in, uint32_t blocks);+void aes_ni_encrypt_xts256(aes_block *out, aes_key *key1, aes_key *key2,+                           aes_block *_tweak, uint32_t spoint, aes_block *in, uint32_t blocks);++void aes_ni_gcm_encrypt128(uint8_t *out, aes_gcm *gcm, aes_key *key, uint8_t *in, uint32_t length);+void aes_ni_gcm_encrypt256(uint8_t *out, aes_gcm *gcm, aes_key *key, uint8_t *in, uint32_t length);  void gf_mul_x86ni(block128 *res, block128 *a_, block128 *b_); 
+ cbits/aes_x86ni_impl.c view
@@ -0,0 +1,263 @@+/*+ * Copyright (c) 2012-2013 Vincent Hanquez <vincent@snarc.org>+ *+ * All rights reserved.+ *+ * Redistribution and use in source and binary forms, with or without+ * modification, are permitted provided that the following conditions+ * are met:+ * 1. Redistributions of source code must retain the above copyright+ *    notice, this list of conditions and the following disclaimer.+ * 2. Redistributions in binary form must reproduce the above copyright+ *    notice, this list of conditions and the following disclaimer in the+ *    documentation and/or other materials provided with the distribution.+ * 3. Neither the name of the author nor the names of his contributors+ *    may be used to endorse or promote products derived from this software+ *    without specific prior written permission.+ *+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF+ * SUCH DAMAGE.+ */++void SIZED(aes_ni_encrypt_block)(aes_block *out, aes_key *key, aes_block *in)+{+	__m128i *k = (__m128i *) key->data;+	PRELOAD_ENC(k);+	__m128i m = _mm_loadu_si128((__m128i *) in);+	DO_ENC_BLOCK(m);+	_mm_storeu_si128((__m128i *) out, m);+}++void SIZED(aes_ni_decrypt_block)(aes_block *out, aes_key *key, aes_block *in)+{+	__m128i *k = (__m128i *) key->data;+	PRELOAD_DEC(k);+	__m128i m = _mm_loadu_si128((__m128i *) in);+	DO_DEC_BLOCK(m);+	_mm_storeu_si128((__m128i *) out, m);+}++void SIZED(aes_ni_encrypt_ecb)(aes_block *out, aes_key *key, aes_block *in, uint32_t blocks)+{+	__m128i *k = (__m128i *) key->data;++	PRELOAD_ENC(k);+	for (; blocks-- > 0; in += 1, out += 1) {+		__m128i m = _mm_loadu_si128((__m128i *) in);+		DO_ENC_BLOCK(m);+		_mm_storeu_si128((__m128i *) out, m);+	}+}++void SIZED(aes_ni_decrypt_ecb)(aes_block *out, aes_key *key, aes_block *in, uint32_t blocks)+{+	__m128i *k = (__m128i *) key->data;++	PRELOAD_DEC(k);++	for (; blocks-- > 0; in += 1, out += 1) {+		__m128i m = _mm_loadu_si128((__m128i *) in);+		DO_DEC_BLOCK(m);+		_mm_storeu_si128((__m128i *) out, m);+	}+}++void SIZED(aes_ni_encrypt_cbc)(aes_block *out, aes_key *key, aes_block *_iv, aes_block *in, uint32_t blocks)+{+	__m128i *k = (__m128i *) key->data;+	__m128i iv = _mm_loadu_si128((__m128i *) _iv);++	PRELOAD_ENC(k);++	for (; blocks-- > 0; in += 1, out += 1) {+		__m128i m = _mm_loadu_si128((__m128i *) in);+		m = _mm_xor_si128(m, iv);+		DO_ENC_BLOCK(m);+		iv = m;+		_mm_storeu_si128((__m128i *) out, m);+	}+}++void SIZED(aes_ni_decrypt_cbc)(aes_block *out, aes_key *key, aes_block *_iv, aes_block *in, uint32_t blocks)+{+	__m128i *k = (__m128i *) key->data;+	__m128i iv = _mm_loadu_si128((__m128i *) _iv);++	PRELOAD_DEC(k);++	for (; blocks-- > 0; in += 1, out += 1) {+		__m128i m = _mm_loadu_si128((__m128i *) in);+		__m128i ivnext = m;++		DO_DEC_BLOCK(m);+		m = _mm_xor_si128(m, iv);++		_mm_storeu_si128((__m128i *) out, m);+		iv = ivnext;+	}+}++void SIZED(aes_ni_encrypt_ctr)(uint8_t *output, aes_key *key, aes_block *_iv, uint8_t *input, uint32_t len)+{+	__m128i *k = (__m128i *) key->data;+	__m128i bswap_mask = _mm_setr_epi8(7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8);+	__m128i one        = _mm_set_epi32(0,1,0,0);+	uint32_t nb_blocks = len / 16;+	uint32_t part_block_len = len % 16;++	/* get the IV in little endian format */+	__m128i iv = _mm_loadu_si128((__m128i *) _iv);+	iv = _mm_shuffle_epi8(iv, bswap_mask);++	PRELOAD_ENC(k);++	for (; nb_blocks-- > 0; output += 16, input += 16) {+		/* put back the iv in big endian mode,+		 * encrypt it and and xor it the input block+		 */+		__m128i tmp = _mm_shuffle_epi8(iv, bswap_mask);+		DO_ENC_BLOCK(tmp);+		__m128i m = _mm_loadu_si128((__m128i *) input);+		m = _mm_xor_si128(m, tmp);++		_mm_storeu_si128((__m128i *) output, m);+		/* iv += 1 */+		iv = _mm_add_epi64(iv, one);+	}++	if (part_block_len != 0) {+		aes_block block;+		memset(&block.b, 0, 16);+		memcpy(&block.b, input, part_block_len);++		__m128i m = _mm_loadu_si128((__m128i *) &block);+		__m128i tmp = _mm_shuffle_epi8(iv, bswap_mask);++		DO_ENC_BLOCK(tmp);+		m = _mm_xor_si128(m, tmp);+		_mm_storeu_si128((__m128i *) &block.b, m);+		memcpy(output, &block.b, part_block_len);+	}++	return ;+}++void SIZED(aes_ni_encrypt_xts)(aes_block *out, aes_key *key1, aes_key *key2,+                               aes_block *_tweak, uint32_t spoint, aes_block *in, uint32_t blocks)+{+	__m128i tweak = _mm_loadu_si128((__m128i *) _tweak);++	do {+		__m128i *k2 = (__m128i *) key2->data;+		PRELOAD_ENC(k2);+		DO_ENC_BLOCK(tweak);++		while (spoint-- > 0)+			tweak = gfmulx(tweak);+	} while (0) ;++	do {+		__m128i *k1 = (__m128i *) key1->data;+		PRELOAD_ENC(k1);++		for ( ; blocks-- > 0; in += 1, out += 1, tweak = gfmulx(tweak)) {+			__m128i m = _mm_loadu_si128((__m128i *) in);++			m = _mm_xor_si128(m, tweak);+			DO_ENC_BLOCK(m);+			m = _mm_xor_si128(m, tweak);++			_mm_storeu_si128((__m128i *) out, m);+		}+	} while (0);+}++void SIZED(aes_ni_gcm_encrypt)(uint8_t *output, aes_gcm *gcm, aes_key *key, uint8_t *input, uint32_t length)+{+	__m128i *k = (__m128i *) key->data;+	__m128i bswap_mask = _mm_setr_epi8(7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8);+	__m128i one        = _mm_set_epi32(0,1,0,0);+	uint32_t nb_blocks = length / 16;+	uint32_t part_block_len = length % 16;++	gcm->length_input += length;++	__m128i h  = _mm_loadu_si128((__m128i *) &gcm->h);+	__m128i tag = _mm_loadu_si128((__m128i *) &gcm->tag);+	__m128i iv = _mm_loadu_si128((__m128i *) &gcm->civ);+	iv = _mm_shuffle_epi8(iv, bswap_mask);++	PRELOAD_ENC(k);++	for (; nb_blocks-- > 0; output += 16, input += 16) {+		/* iv += 1 */+		iv = _mm_add_epi64(iv, one);++		/* put back iv in big endian, encrypt it,+		 * and xor it to input */+		__m128i tmp = _mm_shuffle_epi8(iv, bswap_mask);+		DO_ENC_BLOCK(tmp);+		__m128i m = _mm_loadu_si128((__m128i *) input);+		m = _mm_xor_si128(m, tmp);++		tag = ghash_add(tag, h, m);++		/* store it out */+		_mm_storeu_si128((__m128i *) output, m);+	}+	if (part_block_len > 0) {+		__m128i mask;+		aes_block block;+		/* FIXME could do something a bit more clever (slli & sub & and maybe) ... */+		switch (part_block_len) {+		case 1: mask = _mm_setr_epi8(0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80); break;+		case 2: mask = _mm_setr_epi8(0,1,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80); break;+		case 3: mask = _mm_setr_epi8(0,1,2,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80); break;+		case 4: mask = _mm_setr_epi8(0,1,2,3,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80); break;+		case 5: mask = _mm_setr_epi8(0,1,2,3,4,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80); break;+		case 6: mask = _mm_setr_epi8(0,1,2,3,4,5,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80); break;+		case 7: mask = _mm_setr_epi8(0,1,2,3,4,5,6,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80); break;+		case 8: mask = _mm_setr_epi8(0,1,2,3,4,5,6,7,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80); break;+		case 9: mask = _mm_setr_epi8(0,1,2,3,4,5,6,7,8,0x80,0x80,0x80,0x80,0x80,0x80,0x80); break;+		case 10: mask = _mm_setr_epi8(0,1,2,3,4,5,6,7,8,9,0x80,0x80,0x80,0x80,0x80,0x80); break;+		case 11: mask = _mm_setr_epi8(0,1,2,3,4,5,6,7,8,9,10,0x80,0x80,0x80,0x80,0x80); break;+		case 12: mask = _mm_setr_epi8(0,1,2,3,4,5,6,7,8,9,10,11,0x80,0x80,0x80,0x80); break;+		case 13: mask = _mm_setr_epi8(0,1,2,3,4,5,6,7,8,9,10,11,12,0x80,0x80,0x80); break;+		case 14: mask = _mm_setr_epi8(0,1,2,3,4,5,6,7,8,9,10,11,12,13,0x80,0x80); break;+		case 15: mask = _mm_setr_epi8(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,0x80); break;+		default: mask = _mm_setr_epi8(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15); break;+		}+		memset(&block.b, 0, 16);+		memcpy(&block.b, input, part_block_len);++		/* iv += 1 */+		iv = _mm_add_epi64(iv, one);++		/* put back iv in big endian mode, encrypt it and xor it with input */+		__m128i tmp = _mm_shuffle_epi8(iv, bswap_mask);+		DO_ENC_BLOCK(tmp);++		__m128i m = _mm_loadu_si128((__m128i *) &block);+		m = _mm_xor_si128(m, tmp);+		m = _mm_shuffle_epi8(m, mask);++		tag = ghash_add(tag, h, m);++		/* make output */+		_mm_storeu_si128((__m128i *) &block.b, m);+		memcpy(output, &block.b, part_block_len);+	}+	/* store back IV & tag */+	__m128i tmp = _mm_shuffle_epi8(iv, bswap_mask);+	_mm_storeu_si128((__m128i *) &gcm->civ, tmp);+	_mm_storeu_si128((__m128i *) &gcm->tag, tag);+}
cbits/block128.h view
@@ -84,4 +84,16 @@ 		b->q[1] = cpu_to_be64(v); } +#ifdef IMPL_DEBUG+#include <stdio.h>+static inline void block128_print(block128 *b)+{+	int i;+	for (i = 0; i < 16; i++) {+		printf("%02x ", b->b[i]);+	}+	printf("\n");+}+#endif+ #endif
cbits/cpu.c view
@@ -54,18 +54,22 @@ }  #ifdef USE_AESNI-int have_aesni(void)+void initialize_hw(void (*init_table)(int, int)) {-	static int v = -1;-	if (v == -1) {+	static int inited = 0;+	if (inited == 0) { 		uint32_t eax, ebx, ecx, edx;+		int aesni, pclmul;++		inited = 1; 		cpuid(1, &eax, &ebx, &ecx, &edx);-		v = (ecx & 0x02000000);+		aesni = (ecx & 0x02000000);+		pclmul = (ecx & 0x00000001);+		init_table(aesni, pclmul); 	}-	return v; } #else-#define have_aesni() 	(0)+#define initialize_hw(init_table) 	(0) #endif  #endif
cbits/cpu.h view
@@ -37,9 +37,9 @@ #endif  #ifdef USE_AESNI-int have_aesni(void);+void initialize_hw(void (*init_table)(int, int)); #else-#define have_aesni() 	(0)+#define initialize_hw(init_table) 	(0) #endif  #endif
cipher-aes.cabal view
@@ -1,5 +1,5 @@ Name:                cipher-aes-Version:             0.1.8+Version:             0.2.0 Description:     Fast AES cipher implementation with advanced mode of operations.     .@@ -12,7 +12,7 @@     .     The software implementation uses S-Boxes, which might suffer for cache timing issues.     However do notes that most other known software implementations, including very popular-    one (openssl, gnutls) also uses same implementation. If it matters for your+    one (openssl, gnutls) also uses similar implementation. If it matters for your     case, you should make sure you have AES-NI available, or you'll need to use a different     implementation.     .@@ -28,12 +28,16 @@ Cabal-Version:       >=1.8 Extra-Source-Files:  Tests/*.hs                      cbits/*.h+                     cbits/aes_x86ni_impl.c  Library   Build-Depends:     base >= 4 && < 5                    , bytestring+                   , byteable+                   , crypto-cipher-types+                   , securemem >= 0.1.2   Exposed-modules:   Crypto.Cipher.AES-  ghc-options:       -Wall+  ghc-options:       -Wall -optc-O3 -fno-cse -fwarn-tabs   C-sources:         cbits/aes_generic.c                      cbits/aes.c                      cbits/gf.c@@ -48,7 +52,10 @@   Main-Is:           Tests.hs   Build-depends:     base >= 4 && < 5                    , cipher-aes+                   , crypto-cipher-types+                   , crypto-cipher-tests                    , bytestring+                   , byteable                    , QuickCheck >= 2                    , test-framework >= 0.3.3                    , test-framework-quickcheck2 >= 0.2.9@@ -60,6 +67,8 @@   Build-depends:     base >= 4 && < 5                    , bytestring                    , cipher-aes+                   , crypto-cipher-types+                   , crypto-cipher-benchmarks                    , criterion                    , mtl