cipher-aes128 0.6.4 → 0.7
raw patch · 7 files changed
+184/−32 lines, 7 filesdep ~bytestring
Dependency ranges changed: bytestring
Files
- Crypto/Cipher/AES128.hs +137/−2
- Crypto/Cipher/AES128/Internal.hs +21/−15
- cbits/aes.c +11/−9
- cbits/aes.h +2/−2
- cbits/aes_x86ni.c +1/−1
- cbits/aes_x86ni.h +1/−1
- cipher-aes128.cabal +11/−2
Crypto/Cipher/AES128.hs view
@@ -1,17 +1,27 @@ {-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE RecordWildCards #-} module Crypto.Cipher.AES128- ( AESKey128, AESKey192, AESKey256+ ( -- * Key types with crypto-api instances+ AESKey128, AESKey192, AESKey256 , BlockCipher(..), buildKeyIO, zeroIV+ -- * GCM Operations+ , makeGCMCtx, aesKeyToGCM, GCMCtx, AuthTag(..), AES_GCM+ , Crypto.Cipher.AES128.encryptGCM+ , Crypto.Cipher.AES128.decryptGCM ) where -import Crypto.Cipher.AES128.Internal+import Crypto.Cipher.AES128.Internal as I import Crypto.Classes+import Data.Function (on) import Control.Monad (when) import Data.Serialize import Data.Tagged+import Data.Word (Word8) import Foreign.Ptr import Foreign.ForeignPtr+import Foreign.Marshal.Alloc as F import System.IO.Unsafe+import Data.ByteString (ByteString) import qualified Data.ByteString as B import qualified Data.ByteString.Internal as B import qualified Data.ByteString.Unsafe as B@@ -147,3 +157,128 @@ return (ct,IV newIV) {-# INLINE ctr #-} unCtr = ctr++-- GCM Routines+maxTagLen :: Int+maxTagLen = 16++data AuthTag = AuthTag { unAuthTag :: ByteString }++-- | A tuple of key and precomputed data for use by GCM+data GCMCtx k = GCMCtx { gcmkey :: k+ , gcmpc :: GCMpc+ }++instance Eq AuthTag where+ (==) = constTimeEq `on` unAuthTag++-- A super-class indicating which keys can be used with GCMCtx.+class (BlockCipher k, GetExpanded k) => AES_GCM k where+instance AES_GCM AESKey128+instance AES_GCM AESKey192+instance AES_GCM AESKey256++-- | Given key material produce a context useful for GCM operations+makeGCMCtx :: AES_GCM k => ByteString -> Maybe (GCMCtx k)+makeGCMCtx = fmap aesKeyToGCM . buildKey++-- | Given an AESKey produce a GCM Context.+aesKeyToGCM :: AES_GCM k => k -> GCMCtx k+aesKeyToGCM k = GCMCtx k (I.precomputeGCMdata k)++-- |Encrypts multiple-of-block-sized input, returning a bytestring and tag.+encryptGCM :: AES_GCM k+ => GCMCtx k+ -> ByteString -- ^ IV+ -> ByteString -- ^ Plaintext+ -> ByteString -- ^ AAD+ -> (ByteString, AuthTag)+encryptGCM key iv pt aad = unsafePerformIO $ do+ B.unsafeUseAsCString pt $ \ptPtr -> do+ B.unsafeUseAsCString iv $ \ivPtr -> do+ B.unsafeUseAsCString aad $ \aadPtr -> do+ ctPtr <- F.mallocBytes (B.length pt)+ tagPtr <- F.mallocBytes maxTagLen+ encryptGCMPtr key+ (castPtr ivPtr) (B.length iv)+ (castPtr ptPtr) (B.length pt)+ (castPtr aadPtr) (B.length aad)+ (castPtr ctPtr)+ (castPtr tagPtr)+ ctBS <- B.unsafePackMallocCStringLen (castPtr ctPtr, B.length pt)+ tagBS <- B.unsafePackMallocCStringLen (castPtr tagPtr, maxTagLen)+ return (ctBS, AuthTag tagBS)++-- Encrypts multiple-of-block-sized input, filling a pointer with the+-- result of [ctr, ct, tag].+encryptGCMPtr :: AES_GCM k+ => GCMCtx k+ -> Ptr Word8 -- ^ IV+ -> Int -- ^ IV Length+ -> Ptr Word8 -- ^ Plaintext buffer+ -> Int -- ^ Plaintext length+ -> Ptr Word8 -- ^ AAD buffer+ -> Int -- ^ AAD Length+ -> Ptr Word8 -- ^ ciphertext buffer (at least encBytes large)+ -> Ptr Word8 -- ^ Tag buffer (always allocated to max length)+ -> IO ()+encryptGCMPtr (GCMCtx {..}) ivPtr ivLen+ ptPtr ptLen+ aadPtr aadLen+ ctPtr+ tagPtr =+ do I.encryptGCM gcmkey gcmpc+ (castPtr ivPtr) (fromIntegral ivLen)+ (castPtr aadPtr) (fromIntegral aadLen)+ (castPtr ptPtr) (fromIntegral ptLen)+ (castPtr ctPtr)+ (castPtr tagPtr)++-- | Decrypts multiple-of-block-sized input, returing a bytestring of the+-- [ctr, ct, tag].+decryptGCM :: AES_GCM k+ => GCMCtx k+ -> ByteString -- ^ IV+ -> ByteString -- ^ Ciphertext+ -> ByteString -- ^ AAD+ -> (ByteString, AuthTag)+ -- ^ Plaintext and incremented context (or an error)+decryptGCM gcmdata iv ct aad = unsafePerformIO $ do+ let ivLen = B.length iv+ tagLen = maxTagLen+ ctLen = B.length ct+ B.unsafeUseAsCString iv $ \ivPtr -> do+ B.unsafeUseAsCString ct $ \ctPtr -> do+ B.unsafeUseAsCString aad $ \aadPtr -> do+ tagPtr <- F.mallocBytes tagLen+ ptPtr <- F.mallocBytes ctLen+ decryptGCM_ptr gcmdata+ (castPtr ivPtr) ivLen+ (castPtr ctPtr) ctLen+ (castPtr aadPtr) (B.length aad)+ (castPtr ptPtr)+ (castPtr tagPtr)+ tagBS <- B.unsafePackMallocCStringLen (castPtr tagPtr,tagLen)+ ptBS <- B.unsafePackMallocCStringLen (castPtr ptPtr, ctLen)+ return (ptBS, AuthTag tagBS)++decryptGCM_ptr :: AES_GCM k+ => GCMCtx k+ -> Ptr Word8 -> Int -- IV+ -> Ptr Word8 -> Int -- CT+ -> Ptr Word8 -> Int -- AAD+ -> Ptr Word8 -- Plaintext+ -> Ptr Word8 -- Tag+ -> IO ()+decryptGCM_ptr (GCMCtx {..})+ ivPtr ivLen+ ctPtr ctLen+ aadPtr aadLen+ ptPtr+ tagPtr =+ I.decryptGCM gcmkey gcmpc+ ivPtr (fromIntegral ivLen)+ aadPtr (fromIntegral aadLen)+ ctPtr (fromIntegral ctLen)+ ptPtr+ tagPtr
Crypto/Cipher/AES128/Internal.hs view
@@ -12,6 +12,8 @@ , cipherOnlyGCM , decipherOnlyGCM , finishGCM, aadGCM+ -- * Internal, will not be exported in a near-future release.+ , GetExpanded ) where import Foreign.Ptr@@ -20,6 +22,7 @@ import Foreign.Marshal.Alloc import Data.Word import Data.Bits (shiftL, (.|.))+import System.IO.Unsafe -- AES Bindings data AESKeyStruct@@ -49,6 +52,9 @@ type AESGcmPtr = Ptr GCMStruct data GCMStruct++-- Store the key, the precomputed GCM data, and the current IV by way of+-- a foreign pointer data GCM k = GCM { _gcmFP :: GCMpc , _keyFP :: k , _ctxFP2 :: ForeignPtr CTXStruct@@ -283,7 +289,7 @@ => k -> IO (GCM k) generateGCM keyStruct = do- gcmPC <- precomputeGCMdata keyStruct+ let gcmPC = precomputeGCMdata keyStruct withForeignPtr (expandedKey keyStruct) $ \k -> do c <- c_allocate_ctx allocaBytes 12 $ \ivPtr -> withGCMpc gcmPC $ \g -> do@@ -293,8 +299,8 @@ return (GCM gcmPC keyStruct cFP) {-# INLINE generateGCM #-} -precomputeGCMdata :: GetExpanded k => k -> IO GCMpc-precomputeGCMdata k = do+precomputeGCMdata :: GetExpanded k => k -> GCMpc+precomputeGCMdata k = unsafePerformIO $ do withForeignPtr (expandedKey k) $ \kp -> do g <- c_allocate_gcm c_gcm_init g kp@@ -381,13 +387,13 @@ c_decrypt_ctr pt p iv niv ct (fromIntegral len) encryptGCM :: GetExpanded k- => k- -> GCMpc- -> Ptr Word8 -> Word32 -- IV- -> Ptr Word8 -> Word32 -- AAD- -> Ptr Word8 -> Word32 -- PT- -> Ptr Word8 -- CT- -> Ptr Word8 -- Tag+ => k -- AES{128,192,256}+ -> GCMpc -- Precomputed GCM Data+ -> Ptr Word8 -> Word32 -- IV, len+ -> Ptr Word8 -> Word32 -- AAD, len+ -> Ptr Word8 -> Word32 -- PT, len+ -> Ptr Word8 -- CT (out)+ -> Ptr Word8 -- Tag (128 bits out) -> IO () encryptGCM (expandedKey -> k) (GCMpc g) iv ivLen aad aadLen pt ptLen ct tag = withForeignPtr k $ \kp ->@@ -397,11 +403,11 @@ decryptGCM :: GetExpanded k => k -> GCMpc- -> Ptr Word8 -> Word32 -- IV- -> Ptr Word8 -> Word32 -- AAD- -> Ptr Word8 -> Word32 -- CT- -> Ptr Word8 -- PT- -> Ptr Word8 -- Tag+ -> Ptr Word8 -> Word32 -- IV, len+ -> Ptr Word8 -> Word32 -- AAD, len+ -> Ptr Word8 -> Word32 -- CT, len+ -> Ptr Word8 -- PT (out)+ -> Ptr Word8 -- Tag (out) -> IO () decryptGCM (expandedKey -> k) (GCMpc g) iv ivLen aad aadLen ct ctLen pt tag = withForeignPtr k $ \kp ->
cbits/aes.c view
@@ -34,6 +34,7 @@ #include "bitfn.h" #include <string.h> #include <stdio.h>+#include <stdlib.h> #include "gf.h" #include "aes_x86ni.h"@@ -43,9 +44,9 @@ void tmd_aes_generic_encrypt_cbc(aes_block *output, const aes_key *key, const aes_block *iv, aes_block *newIV, const aes_block *input, uint32_t nb_blocks); void tmd_aes_generic_decrypt_cbc(aes_block *output, const aes_key *key, const aes_block *ivini, aes_block *newIV, const aes_block *input, uint32_t nb_blocks); void tmd_aes_generic_encrypt_ctr(uint8_t *output, const aes_key *key, const aes_block *iv, aes_block *newIV, const uint8_t *input, uint32_t length);-void tmd_aes_generic_encrypt_xts(aes_block *output, aes_key *k1, aes_key *k2, aes_block *dataunit,+void tmd_aes_generic_encrypt_xts(aes_block *output, const aes_key *k1, aes_key *k2, aes_block *dataunit, uint32_t spoint, aes_block *input, uint32_t nb_blocks);-void tmd_aes_generic_decrypt_xts(aes_block *output, aes_key *k1, aes_key *k2, aes_block *dataunit,+void tmd_aes_generic_decrypt_xts(aes_block *output, const aes_key *k1, aes_key *k2, aes_block *dataunit, uint32_t spoint, aes_block *input, uint32_t nb_blocks); void tmd_aes_generic_gcm_encrypt(uint8_t *output, const aes_gcm *gcm, const aes_ctx *ctx, const aes_key *key, const uint8_t *input, uint32_t length, aes_ctx *newCTX); void tmd_aes_generic_gcm_decrypt(uint8_t *output, const aes_gcm *gcm, const aes_ctx *ctx, const aes_key *key, const uint8_t *input, uint32_t length, aes_ctx *newCTX);@@ -118,7 +119,7 @@ [DECRYPT_GCM_256] = tmd_aes_generic_gcm_decrypt, }; -typedef void (*init_f)(const aes_key *, uint8_t *, uint8_t);+typedef void (*init_f)(aes_key *, const uint8_t *, uint8_t); typedef void (*ecb_f)(aes_block *output, const aes_key *key, const aes_block *input, uint32_t nb_blocks); typedef void (*cbc_f)(aes_block *output, const aes_key *key, const aes_block *iv, aes_block *niv, const aes_block *input, uint32_t nb_blocks); typedef void (*ctr_f)(uint8_t *output, const aes_key *key, const aes_block *iv, aes_block *niv, const uint8_t *input, uint32_t length);@@ -152,7 +153,7 @@ #define aes_decrypt_block(o,k,i) \ (((block_f) (tmd_branch_table[DECRYPT_BLOCK_128 + k->strength]))(o,k,i)) #else-#define GET_INIT(strenght) tmd_aes_generic_init+#define GET_INIT(strength) tmd_aes_generic_init #define GET_ECB_ENCRYPT(strength) tmd_aes_generic_encrypt_ecb #define GET_ECB_DECRYPT(strength) tmd_aes_generic_decrypt_ecb #define GET_CBC_ENCRYPT(strength) tmd_aes_generic_encrypt_cbc@@ -291,14 +292,14 @@ e(output, key, iv, newIV, input, len); } -void tmd_aes_encrypt_xts(aes_block *output, aes_key *k1, aes_key *k2, aes_block *dataunit,+void tmd_aes_encrypt_xts(aes_block *output, const 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); } -void tmd_aes_decrypt_xts(aes_block *output, aes_key *k1, aes_key *k2, aes_block *dataunit,+void tmd_aes_decrypt_xts(aes_block *output, const aes_key *k1, aes_key *k2, aes_block *dataunit, uint32_t spoint, aes_block *input, uint32_t nb_blocks) { tmd_aes_generic_decrypt_xts(output, k1, k2, dataunit, spoint, input, nb_blocks);@@ -329,7 +330,8 @@ aes_encrypt_block(&gcm->h, key, &gcm->h); } -void tmd_aes_ctx_init(const aes_gcm *gcm, aes_ctx *ctx, const aes_key *key, const uint8_t *iv, uint32_t len)+void tmd_aes_ctx_init(const aes_gcm *gcm, aes_ctx *ctx+ , const aes_key *key, const uint8_t *iv, uint32_t len) { ctx->length_aad = 0; ctx->length_input = 0;@@ -485,7 +487,7 @@ block128_copy(newIV, &block); } -void tmd_aes_generic_encrypt_xts(aes_block *output, aes_key *k1, aes_key *k2, aes_block *dataunit,+void tmd_aes_generic_encrypt_xts(aes_block *output, const aes_key *k1, aes_key *k2, aes_block *dataunit, uint32_t spoint, aes_block *input, uint32_t nb_blocks) { aes_block block, tweak;@@ -505,7 +507,7 @@ } } -void tmd_aes_generic_decrypt_xts(aes_block *output, aes_key *k1, aes_key *k2, aes_block *dataunit,+void tmd_aes_generic_decrypt_xts(aes_block *output, const aes_key *k1, aes_key *k2, aes_block *dataunit, uint32_t spoint, aes_block *input, uint32_t nb_blocks) { aes_block block, tweak;
cbits/aes.h view
@@ -80,9 +80,9 @@ void tmd_aes_encrypt_ctr(uint8_t *output, const aes_key *key, const aes_block *iv, aes_block *newIV, const uint8_t *input, uint32_t len); void tmd_aes_gen_ctr(aes_block *output, const aes_key *key, aes_block *iv, uint32_t nb_blocks); -void tmd_aes_encrypt_xts(aes_block *output, aes_key *key, aes_key *key2, aes_block *sector,+void tmd_aes_encrypt_xts(aes_block *output, const aes_key *key, aes_key *key2, aes_block *sector, uint32_t spoint, aes_block *input, uint32_t nb_blocks);-void tmd_aes_decrypt_xts(aes_block *output, aes_key *key, aes_key *key2, aes_block *sector,+void tmd_aes_decrypt_xts(aes_block *output, const aes_key *key, aes_key *key2, aes_block *sector, uint32_t spoint, aes_block *input, uint32_t nb_blocks); void tmd_aes_gcm_init(aes_gcm *gcm, const aes_key *key);
cbits/aes_x86ni.c view
@@ -63,7 +63,7 @@ return _mm_xor_si128(key, keygened); } -void tmd_aes_ni_init(aes_key *key, uint8_t *ikey, uint8_t size)+void tmd_aes_ni_init(aes_key *key, const uint8_t *ikey, uint8_t size) { __m128i k[28]; uint64_t *out = (uint64_t *) key->data;
cbits/aes_x86ni.h view
@@ -49,7 +49,7 @@ } #endif -void tmd_aes_ni_init(aes_key *key, uint8_t *origkey, uint8_t size);+void tmd_aes_ni_init(aes_key *key, const uint8_t *origkey, uint8_t size); void tmd_aes_ni_encrypt_block128(aes_block *out, aes_key *key, aes_block *in); void tmd_aes_ni_encrypt_block256(aes_block *out, aes_key *key, aes_block *in); void tmd_aes_ni_decrypt_block128(aes_block *out, aes_key *key, aes_block *in);
cipher-aes128.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/ name: cipher-aes128-version: 0.6.4+version: 0.7 synopsis: AES and common modes using AES-NI when available. description: Cipher-aes128 is an implementation of AES and common modes of operation. It borrows Hanquez's C AES code (see 'cipher-aes') but is unique due to including compile-time detection of@@ -18,6 +18,8 @@ homepage: https://github.com/TomMD/cipher-aes128 bug-reports: https://github.com/TomMD/cipher-aes128/issues build-type: Custom+-- build-type: Simple+-- ^^^ For HaLVM cabal-version: >=1.12 extra-source-files: ./cbits/*.h, ./cbits/*.c@@ -27,6 +29,10 @@ description: Build a program to test the AES implementation default: False +flag halvm+ description: The HaLVM target+ default: False+ library default-language: Haskell2010 exposed-modules: Crypto.Cipher.AES128, Crypto.Cipher.AES128.Internal@@ -43,7 +49,10 @@ , ./cbits/cpu.c , ./cbits/gf.c include-dirs: cbits/- cc-options: -g+ cc-options:+ if flag(halvm)+ cc-options: -maes -mpclmul -mssse3 -DWITH_AESNI+ cpp-options: -DWITH_AESNI -maes -mpclmul -mssse3 -- None by default cc-options: -mssse3 -maes -mpclmul source-repository head