cipher-aes128 0.4.1 → 0.5
raw patch · 7 files changed
+225/−102 lines, 7 files
Files
- Crypto/Cipher/AES128.hs +1/−0
- Crypto/Cipher/AES128/Internal.hs +84/−32
- cbits/aes/aes.c +107/−61
- cbits/include/aes.h +19/−0
- cbits/include/aes_types.h +8/−5
- cbits/include/block128.h +2/−2
- cipher-aes128.cabal +4/−2
Crypto/Cipher/AES128.hs view
@@ -1,3 +1,4 @@+{-# OPTIONS_GHC -fno-warn-orphans #-} module Crypto.Cipher.AES128 ( AESKey ) where
Crypto/Cipher/AES128/Internal.hs view
@@ -1,11 +1,12 @@ {-# LANGUAGE ForeignFunctionInterface, EmptyDataDecls #-} module Crypto.Cipher.AES128.Internal- ( AESKey(..), RawKey(..)- , generateKey+ ( AESKey(..), RawKey(..), GCM(..)+ , generateKey, generateGCM , encryptECB , decryptECB , encryptGCM , decryptGCM+ , finishGCM , encryptCTR , decryptCTR ) where@@ -13,6 +14,7 @@ import Foreign.Ptr import Foreign.ForeignPtr import Foreign.Storable+import Foreign.Marshal.Alloc import Data.Word import Data.Bits (shiftL, (.|.)) @@ -23,6 +25,10 @@ data AESKey = AESKey { rawKey :: !RawKey , expandedKey :: ForeignPtr AESKeyStruct } +type AESGcmPtr = Ptr GCMStruct+data GCMStruct+data GCM = GCM { _gcmFP :: ForeignPtr GCMStruct }+ foreign import ccall unsafe "aes/aes.h generate_key128" c_generate_key128 :: AESKeyPtr -> Ptr Word8 -> IO () @@ -32,28 +38,51 @@ foreign import ccall unsafe "aes/aes.h &free_key128" c_free_key128 :: FunPtr (AESKeyPtr -> IO ()) +foreign import ccall unsafe "aes/aes.h free_key128"+ c_key128_free :: AESKeyPtr -> IO ()+ foreign import ccall unsafe "aes/aes.h encrypt_ecb" c_encrypt_ecb :: AESKeyPtr -> Ptr Word8 -> Ptr Word8 -> Word32 -> IO () foreign import ccall unsafe "aes/aes.h decrypt_ecb" c_decrypt_ecb :: AESKeyPtr -> Ptr Word8 -> Ptr Word8 -> Word32 -> IO () -foreign import ccall unsafe "aes/aes.h aes_gcm_full_encrypt"- c_encrypt_gcm :: AESKeyPtr- -> Ptr Word8 -> Word32 -- ^ IV and length- -> Ptr Word8 -> Word32 -- ^ AAD and length- -> Ptr Word8 -> Word32 -- ^ PT and length- -> Ptr Word8 -> Ptr Word8 -- ^ Result CT and TAG+foreign import ccall unsafe "aes/aes.h allocate_gcm"+ c_gcm_allocate :: IO AESGcmPtr++foreign import ccall unsafe "aes/aes.h aes_gcm_init"+ c_gcm_init :: AESGcmPtr+ -> AESKeyPtr+ -> Ptr Word8 -> Word32 -- ^ IV and length+ -> IO ()++foreign import ccall unsafe "aes/aes.h aes_gcm_enc_finish"+ c_gcm_encrypt :: Ptr Word8 -- Output+ -> Ptr Word8 -- Tag+ -> AESGcmPtr+ -> Ptr Word8 -> Word32 -- IV and length+ -> Ptr Word8 -> Word32 -- PT and length+ -> Ptr Word8 -> Word32 -- AAD and length -> IO () -foreign import ccall unsafe "aes/aes.h aes_gcm_full_decrypt"- c_decrypt_gcm :: AESKeyPtr- -> Ptr Word8 -> Word32 -- ^ IV and length- -> Ptr Word8 -> Word32 -- ^ AAD and length- -> Ptr Word8 -> Word32 -- ^ CT and length- -> Ptr Word8 -> Ptr Word8 -- ^ Result PT and TAG+foreign import ccall unsafe "aes/aes.h aes_gcm_dec_finish"+ c_gcm_decrypt :: Ptr Word8 -- Output+ -> Ptr Word8 -- Tag+ -> AESGcmPtr+ -> Ptr Word8 -> Word32 -- IV and length+ -> Ptr Word8 -> Word32 -- PT and length+ -> Ptr Word8 -> Word32 -- AAD and length -> IO () +foreign import ccall unsafe "aes/aes.h allocate_gcm"+ c_gcm_finish :: Ptr Word8 -> AESGcmPtr -> IO ()++foreign import ccall unsafe "aes/aes.h &free_gcm"+ c_free_gcm :: FunPtr (AESGcmPtr -> IO ())++foreign import ccall unsafe "aes/aes.h free_gcm"+ _c_gcm_free :: AESGcmPtr -> IO ()+ foreign import ccall unsafe "aes/aes.h encrypt_ctr" c_encrypt_ctr :: AESKeyPtr -> Ptr Word8 -- ^ 128 bit IV@@ -105,6 +134,21 @@ return a {-# INLINE generateKey #-} +-- Given a 16 byte buffer, allocate and return an key expansion useful for+-- GCM+generateGCM :: Ptr Word64 -- ^ Buffer of 16 bytes of key material+ -> IO GCM+generateGCM keyPtr = do+ g <- c_gcm_allocate+ k <- c_allocate_key128+ c_generate_key128 k (castPtr keyPtr)+ allocaBytes 12 $ \ivPtr -> do+ mapM_ (\i -> pokeElemOff ivPtr i (0::Word8)) [0..11]+ c_gcm_init g k ivPtr 12+ c_key128_free k+ fmap GCM (newForeignPtr c_free_gcm g)+{-# INLINE generateGCM #-}+ -- An encrypt function that can handle up to blks < maxBound `div` 16 :: Word32 -- simultaneous blocks. encryptECB :: AESKey -- ^ The key@@ -125,27 +169,35 @@ | otherwise = withForeignPtr k $ \p -> c_decrypt_ecb p dst src (fromIntegral blks) {-# INLINE decryptECB #-} -encryptGCM :: AESKey- -> Ptr Word8 -> Int -- IV- -> Ptr Word8 -> Int -- AAD- -> Ptr Word8 -> Int -- PT- -> Ptr Word8 -- CT (output)- -> Ptr Word8 -- Tag (output)+encryptGCM :: GCM+ -> Ptr Word8 -> Int -- IV and length+ -> Ptr Word8 -> Int -- PT and length+ -> Ptr Word8 -> Int -- AAD and length+ -> Ptr Word8 -- CT (length assumed to match PT)+ -> Ptr Word8 -- Tag (length assumed to match blocksize) -> IO ()-encryptGCM (AESKey _ k) iv ivLen aad aadLen pt ptLen ct tag = withForeignPtr k $ \p -> do- c_encrypt_gcm p iv (fromIntegral ivLen) aad (fromIntegral aadLen) pt (fromIntegral ptLen) ct tag-{-# INLINE encryptGCM #-}+encryptGCM (GCM k) iv ivlen pt ptlen aad aadlen ct tg = withForeignPtr k $ \g ->+ c_gcm_encrypt ct tg g iv (fromIntegral ivlen)+ pt (fromIntegral ptlen)+ aad (fromIntegral aadlen) -decryptGCM :: AESKey- -> Ptr Word8 -> Int -- IV- -> Ptr Word8 -> Int -- AAD- -> Ptr Word8 -> Int -- CT- -> Ptr Word8 -- PT (output)- -> Ptr Word8 -- Tag (output)+decryptGCM :: GCM+ -> Ptr Word8 -> Int -- IV and length+ -> Ptr Word8 -> Int -- CT and length+ -> Ptr Word8 -> Int -- AAD and length+ -> Ptr Word8 -- PT (length assumed to match PT)+ -> Ptr Word8 -- Tag (length assumed to match blocksize) -> IO ()-decryptGCM (AESKey _ k) iv ivLen aad aadLen ct ctLen pt tag = withForeignPtr k $ \p -> do- c_decrypt_gcm p iv (fromIntegral ivLen) aad (fromIntegral aadLen) ct (fromIntegral ctLen) pt tag-{-# INLINE decryptGCM #-}+decryptGCM (GCM k) iv ivlen ct ctlen aad aadlen pt tg = withForeignPtr k $ \g ->+ c_gcm_decrypt pt tg g+ iv (fromIntegral ivlen)+ ct (fromIntegral ctlen)+ aad (fromIntegral aadlen)++finishGCM :: GCM+ -> Ptr Word8 -- Tag, must point to 16 byte buffer (or larger)+ -> IO ()+finishGCM (GCM k) tagPtr = withForeignPtr k $ \g -> c_gcm_finish tagPtr g encryptCTR :: AESKey -> Ptr Word8 -- ^ IV
cbits/aes/aes.c view
@@ -8,7 +8,7 @@ #include "aes_x86ni.h" #endif #include "bitfn.h"-static void gf_mul(block128 *a, block128 *b);+static void gf_mul(block128 *a, const block128 *b); #ifdef TRY_NI /**@@ -32,6 +32,13 @@ return k; } +aes_gcm *allocate_gcm()+{+ void *g=NULL;+ g = (void *)malloc(sizeof(aes_gcm));+ return g;+}+ /* Generate Key */ #ifdef TRY_NI static void detect_and_generate_key128(AESKey *k, const uint8_t *bytes);@@ -78,6 +85,12 @@ free(k); } +void free_gcm(aes_gcm *g)+{+ memset(g, 0, sizeof(aes_gcm));+ free(g);+}+ /* ECB Encrypt */ #ifdef TRY_NI static void detect_and_encrypt_ecb(const AESKey *k, uint8_t *dst, const uint8_t *src, const uint32_t nr);@@ -168,89 +181,118 @@ /* GCM */-static void gcm_ghash_add(aes_gcm *gcm, block128 *b)+static void gcm_ghash_add(const aes_gcm *gcm, aes_gcm_ctx *ctx, block128 *b) {- block128_xor(&gcm->tag, b);- gf_mul(&gcm->tag, &gcm->h);+ block128_xor(&ctx->tag, b);+ gf_mul(&ctx->tag, &gcm->h); } -static void aes_gcm_init(aes_gcm *gcm, const aes_key *key, uint8_t *iv, uint32_t len)+void aes_gcm_ctx_init(aes_gcm_ctx *ctx, const aes_gcm *gcm, const 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) */- encrypt_ecb(key, (uint8_t *)&gcm->h, (const uint8_t *)&gcm->h, 1);+ ctx->length_aad = 0;+ ctx->length_input = 0;+ block128_zero(&ctx->tag); + block128_zero(&ctx->iv); if (len == 12) {- block128_copy_bytes(&gcm->iv, iv, 12);- gcm->iv.b[15] = 0x01;+ block128_copy_bytes(&ctx->iv, iv, 12);+ ctx->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);+ block128_xor(&ctx->iv, (block128 *) iv);+ gf_mul(&ctx->iv, &gcm->h); } if (len > 0) {- block128_xor_bytes(&gcm->iv, iv, len);- gf_mul(&gcm->iv, &gcm->h);+ block128_xor_bytes(&ctx->iv, iv, len);+ gf_mul(&ctx->iv, &gcm->h); } for (i = 15; origlen; --i, origlen >>= 8)- gcm->iv.b[i] ^= (uint8_t) origlen;- gf_mul(&gcm->iv, &gcm->h);+ ctx->iv.b[i] ^= (uint8_t) origlen;+ gf_mul(&ctx->iv, &gcm->h); } - block128_copy(&gcm->civ, &gcm->iv);+ block128_copy(&ctx->civ, &ctx->iv); } -static void aes_gcm_aad(aes_gcm *gcm, uint8_t *input, uint32_t length)+void aes_gcm_init(aes_gcm *gcm, const aes_key *key) {- gcm->length_aad += length;+ block128_zero(&gcm->h);++ memcpy(&gcm->key, key, sizeof(aes_key));++ /* prepare H : encrypt_K(0^128) */+ encrypt_ecb(key, (uint8_t *)&gcm->h, (const uint8_t *)&gcm->h, 1);+}++void aes_gcm_aad(const aes_gcm *gcm, aes_gcm_ctx *ctx, uint8_t *input, uint32_t length)+{+ ctx->length_aad += length; for (; length >= 16; input += 16, length -= 16) {- gcm_ghash_add(gcm, (block128 *) input);+ gcm_ghash_add(gcm, ctx, (block128 *) input); } if (length > 0) { aes_block tmp; block128_zero(&tmp); block128_copy_bytes(&tmp, input, length);- gcm_ghash_add(gcm, &tmp);+ gcm_ghash_add(gcm, ctx, &tmp); } } -static void aes_gcm_encrypt(uint8_t *output, aes_gcm *gcm, uint8_t *input, uint32_t length)+void aes_gcm_enc_finish( uint8_t *output, uint8_t *tag+ , const aes_gcm *gcm+ , uint8_t *iv, uint32_t ivLen+ , uint8_t *input, uint32_t inputLen+ , uint8_t *aad, uint32_t aadLen) {+ aes_gcm_ctx ctx;+ aes_gcm_ctx_init(&ctx, gcm, iv, ivLen);+ aes_gcm_encrypt(output, gcm, &ctx, input, inputLen);+ aes_gcm_aad(gcm, &ctx, aad, aadLen);+ aes_gcm_finish(tag, gcm, &ctx);+}++void aes_gcm_dec_finish( uint8_t *output, uint8_t *tag+ , const aes_gcm *gcm+ , uint8_t *iv, uint32_t ivLen+ , uint8_t *input, uint32_t inputLen+ , uint8_t *aad, uint32_t aadLen)+{+ aes_gcm_ctx ctx;+ aes_gcm_ctx_init(&ctx, gcm, iv, ivLen);+ aes_gcm_decrypt(output, gcm, &ctx, input, inputLen);+ aes_gcm_aad(gcm, &ctx, aad, aadLen);+ aes_gcm_finish(tag, gcm, &ctx);+}++void aes_gcm_encrypt(uint8_t *output, const aes_gcm *gcm, aes_gcm_ctx *ctx, const uint8_t *input, uint32_t length)+{ aes_block out; - gcm->length_input += length;+ ctx->length_input += length; for (; length >= 16; input += 16, output += 16, length -= 16) {- block128_inc_be(&gcm->civ);+ block128_inc_be(&ctx->civ); - encrypt_ecb(&gcm->key, (uint8_t *)&out, (const uint8_t *)&gcm->civ, 1);+ encrypt_ecb(&gcm->key, (uint8_t *)&out, (const uint8_t *)&ctx->civ, 1); block128_xor(&out, (block128 *) input);- gcm_ghash_add(gcm, &out);+ gcm_ghash_add(gcm, ctx, &out); block128_copy((block128 *) output, &out); } if (length > 0) { aes_block tmp; int i; - block128_inc_be(&gcm->civ);+ block128_inc_be(&ctx->civ); /* create e(civ) in out */- encrypt_ecb(&gcm->key, (uint8_t *)&out, (const uint8_t *)&gcm->civ, 1);+ encrypt_ecb(&gcm->key, (uint8_t *)&out, (const uint8_t *)&ctx->civ, 1); /* 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); - gcm_ghash_add(gcm, &tmp);+ gcm_ghash_add(gcm, ctx, &tmp); for (i = 0; i < length; i++) { output[i] = tmp.b[i];@@ -258,16 +300,16 @@ } } -static void aes_gcm_decrypt(uint8_t *output, aes_gcm *gcm, uint8_t *input, uint32_t length)+void aes_gcm_decrypt(uint8_t *output, const aes_gcm *gcm, aes_gcm_ctx *ctx, const uint8_t *input, uint32_t length) { aes_block out; - gcm->length_input += length;+ ctx->length_input += length; for (; length >= 16; input += 16, output += 16, length -= 16) {- block128_inc_be(&gcm->civ);+ block128_inc_be(&ctx->civ); - encrypt_ecb(&gcm->key, (uint8_t *)&out, (const uint8_t *)&gcm->civ, 1);- gcm_ghash_add(gcm, (block128 *) input);+ encrypt_ecb(&gcm->key, (uint8_t *)&out, (const uint8_t *)&ctx->civ, 1);+ gcm_ghash_add(gcm, ctx, (block128 *) input); block128_xor(&out, (block128 *) input); block128_copy((block128 *) output, &out); }@@ -275,13 +317,13 @@ aes_block tmp; int i; - block128_inc_be(&gcm->civ);+ block128_inc_be(&ctx->civ); block128_zero(&tmp); block128_copy_bytes(&tmp, input, length);- gcm_ghash_add(gcm, &tmp);+ gcm_ghash_add(gcm, ctx, &tmp); - encrypt_ecb(&gcm->key, (uint8_t *)&out, (const uint8_t *)&gcm->civ, 1);+ encrypt_ecb(&gcm->key, (uint8_t *)&out, (const uint8_t *)&ctx->civ, 1); block128_xor_bytes(&tmp, out.b, length); for (i = 0; i < length; i++) {@@ -290,21 +332,21 @@ } } -static void aes_gcm_finish(uint8_t *tag, aes_gcm *gcm)+void aes_gcm_finish(uint8_t *tag, const aes_gcm *gcm, aes_gcm_ctx *ctx) { 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);+ lblock.q[0] = cpu_to_be64(ctx->length_aad << 3);+ lblock.q[1] = cpu_to_be64(ctx->length_input << 3);+ gcm_ghash_add(gcm, ctx, &lblock); - encrypt_ecb(&gcm->key, (uint8_t *)&lblock, (const uint8_t*)&gcm->iv, 1);- block128_xor(&gcm->tag, &lblock);+ encrypt_ecb(&gcm->key, (uint8_t *)&lblock, (const uint8_t*)&ctx->iv, 1);+ block128_xor(&ctx->tag, &lblock); for (i = 0; i < 16; i++) {- tag[i] = gcm->tag.b[i];+ tag[i] = ctx->tag.b[i]; } } @@ -314,11 +356,13 @@ , uint8_t *pt, uint32_t ptLen , uint8_t *ct, uint8_t *tag) {+ aes_gcm_ctx ctx; aes_gcm gcm;- aes_gcm_init(&gcm, k, iv, ivLen);- aes_gcm_aad(&gcm, aad, aadLen);- aes_gcm_encrypt(ct, &gcm, pt, ptLen);- aes_gcm_finish(tag, &gcm);+ aes_gcm_init(&gcm, k);+ aes_gcm_ctx_init(&ctx, &gcm, iv, ivLen);+ aes_gcm_aad(&gcm, &ctx, aad, aadLen);+ aes_gcm_encrypt(ct, &gcm, &ctx, pt, ptLen);+ aes_gcm_finish(tag, &gcm, &ctx); } void aes_gcm_full_decrypt( const AESKey *k@@ -328,10 +372,12 @@ , uint8_t *pt, uint8_t *tag) { aes_gcm gcm;- aes_gcm_init(&gcm, k, iv, ivLen);- aes_gcm_aad(&gcm, aad, aadLen);- aes_gcm_decrypt(pt, &gcm, ct, ctLen);- aes_gcm_finish(tag, &gcm);+ aes_gcm_ctx ctx;+ aes_gcm_init(&gcm, k);+ aes_gcm_ctx_init(&ctx, &gcm, iv, ivLen);+ aes_gcm_aad(&gcm, &ctx, aad, aadLen);+ aes_gcm_decrypt(pt, &gcm, &ctx, ct, ctLen);+ aes_gcm_finish(tag, &gcm, &ctx); } @@ -340,7 +386,7 @@ * to speed up the multiplication. * TODO: optimise with tables */-static void gf_mul(block128 *a, block128 *b)+static void gf_mul(block128 *a, const block128 *b) { uint64_t a0, a1, v0, v1; int i, j;
cbits/include/aes.h view
@@ -20,6 +20,25 @@ , uint8_t *aad, uint32_t aadLen , uint8_t *ct, uint32_t ctLen , uint8_t *pt, uint8_t *tag);+void free_gcm(aes_gcm *g);+aes_gcm *allocate_gcm();+void aes_gcm_init(aes_gcm *gcm, const aes_key *key);+void aes_gcm_init_ctx(aes_gcm_ctx *ctx, const aes_gcm *gcm, uint8_t *iv, uint32_t len);+void aes_gcm_encrypt(uint8_t *output, const aes_gcm *gcm, aes_gcm_ctx *ctx, const uint8_t *input, uint32_t length);+void aes_gcm_decrypt(uint8_t *output, const aes_gcm *gcm, aes_gcm_ctx *ctx, const uint8_t *input, uint32_t length);+void aes_gcm_aad(const aes_gcm *gcm, aes_gcm_ctx *ctx, uint8_t *input, uint32_t length);+void aes_gcm_finish(uint8_t *tag, const aes_gcm *gcm, aes_gcm_ctx *ctx);+void aes_gcm_enc_finish( uint8_t *output, uint8_t *tag+ , const aes_gcm *gcm+ , uint8_t *iv, uint32_t ivLen+ , uint8_t *input, uint32_t inputLen+ , uint8_t *aad, uint32_t aadLen);+void aes_gcm_dec_finish( uint8_t *output, uint8_t *tag+ , const aes_gcm *gcm+ , uint8_t *iv, uint32_t ivLen+ , uint8_t *input, uint32_t inputLen+ , uint8_t *aad, uint32_t aadLen);+ void encrypt_ctr( const AESKey *key , const uint8_t *iv /* 16 bytes buffer with the count */ , uint8_t *newIV /* the return buffer for the next IV (or NULL) */
cbits/include/aes_types.h view
@@ -13,13 +13,16 @@ /* size = 4*16+2*8+aes_key=456 = 536 */ typedef struct {- aes_block tag;- aes_block h;+ aes_block h; // init+ aes_key key;+} aes_gcm;++typedef struct { aes_block iv; aes_block civ;- uint64_t length_aad;+ aes_block tag; // finish, aad, encrypt,decrypt uint64_t length_input;- aes_key key;-} aes_gcm;+ uint64_t length_aad;+} aes_gcm_ctx; #endif
cbits/include/block128.h view
@@ -40,7 +40,7 @@ uint8_t b[16]; } block128; -static inline void block128_copy_bytes(block128 *block, uint8_t *src, uint32_t len)+static inline void block128_copy_bytes(block128 *block, const uint8_t *src, uint32_t len) { int i; for (i = 0; i < len; i++) block->b[i] = src[i];@@ -68,7 +68,7 @@ d->q[1] = s1->q[1] ^ s2->q[1]; } -static inline void block128_xor_bytes(block128 *block, uint8_t *src, uint32_t len)+static inline void block128_xor_bytes(block128 *block, const uint8_t *src, uint32_t len) { int i; for (i = 0; i < len; i++) block->b[i] ^= src[i];
cipher-aes128.cabal view
@@ -2,9 +2,11 @@ -- documentation, see http://haskell.org/cabal/users-guide/ name: cipher-aes128-version: 0.4.1+version: 0.5 synopsis: AES128 using AES-NI when available.-description: AES128 with crypto-api instances and a trampoline between Vincent Hanquez's C-based and x86 NI-based AES. Patches welcome to add additional high-performance backends (ARM?)+description: AES128 with crypto-api instances and a trampoline between Vincent Hanquez's+ C-based and x86 NI-based AES. Patches welcome to add additional+ high-performance backends (ARM?) license: BSD3 license-file: LICENSE author: Thomas M. DuBuisson, Vincent Hanquez (See AUTHORS file)