packages feed

cipher-aes128 0.4.1 → 0.5

raw patch · 7 files changed

+225/−102 lines, 7 files

Files

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)