cipher-aes 0.2.8 → 0.2.11
raw patch · 8 files changed
Files
- Crypto/Cipher/AES.hs +66/−2
- Tests/KATGCM.hs +29/−1
- Tests/Tests.hs +13/−0
- cbits/aes.c +19/−4
- cbits/aes.h +2/−1
- cbits/aes_generic.c +1/−1
- cbits/block128.h +3/−3
- cipher-aes.cabal +4/−4
Crypto/Cipher/AES.hs view
@@ -1,7 +1,9 @@ {-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE ViewPatterns #-} {-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE BangPatterns #-} {-# LANGUAGE CPP #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-} -- | -- Module : Crypto.Cipher.AES -- License : BSD-style@@ -17,6 +19,10 @@ , AES192 , AES256 + -- * IV+ , AESIV+ , aesIV_+ -- * Authenticated encryption block cipher types , AESGCM @@ -26,6 +32,7 @@ -- * misc , genCTR+ , genCounter -- * encryption , encryptECB@@ -46,12 +53,14 @@ import Data.Word import Foreign.Ptr+import Foreign.ForeignPtr import Foreign.C.Types import Foreign.C.String import Data.ByteString.Internal import Data.ByteString.Unsafe import Data.Byteable import qualified Data.ByteString as B+import qualified Data.ByteString.Internal as B (ByteString(PS), mallocByteString, memcpy) import System.IO.Unsafe (unsafePerformIO) import Crypto.Cipher.Types@@ -69,6 +78,16 @@ -- | AES with 256 bit key newtype AES256 = AES256 AES +-- | AES IV is always 16 bytes+newtype AESIV = AESIV ByteString+ deriving (Show,Eq,Byteable)++-- | convert a bytestring to an AESIV+aesIV_ :: ByteString -> AESIV+aesIV_ iv+ | B.length iv /= 16 = error $ "AES error: IV length must be block size (16). Its length is: " ++ (show $ B.length iv)+ | otherwise = AESIV iv+ instance Cipher AES where cipherName _ = "AES" cipherKeySize _ = KeySizeEnum [16,24,32]@@ -165,6 +184,13 @@ ivToPtr :: Byteable iv => iv -> (Ptr Word8 -> IO a) -> IO a ivToPtr iv f = withBytePtr iv (f . castPtr) +ivCopyPtr :: AESIV -> (Ptr Word8 -> IO ()) -> IO AESIV+ivCopyPtr (AESIV iv) f = do+ newIV <- create 16 $ \newPtr -> do+ withBytePtr iv $ \ivPtr -> B.memcpy newPtr ivPtr 16+ withBytePtr newIV $ f+ return $! AESIV newIV+ 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 @@ -216,7 +242,7 @@ {-# NOINLINE encryptCBC #-} encryptCBC :: Byteable iv => AES -- ^ AES Context- -> iv -- ^ Initial vector+ -> iv -- ^ Initial vector of AES block size -> ByteString -- ^ plaintext -> ByteString -- ^ ciphertext encryptCBC = doCBC c_aes_encrypt_cbc@@ -235,22 +261,56 @@ -> ByteString genCTR ctx iv len | len <= 0 = B.empty+ | byteableLength iv /= 16 = error $ "AES error: IV length must be block size (16). Its length is: " ++ (show $ byteableLength iv) | 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 +-- | generate a counter mode pad. this is generally xor-ed to an input+-- to make the standard counter mode block operations.+--+-- if the length requested is not a multiple of the block cipher size,+-- more data will be returned, so that the returned bytestring is+-- a multiple of the block cipher size.+--+-- Similiar to 'genCTR' but also return the next IV for continuation+{-# NOINLINE genCounter #-}+genCounter :: AES+ -> AESIV+ -> Int+ -> (ByteString, AESIV)+genCounter ctx iv len+ | len <= 0 = (B.empty, iv)+ | otherwise = unsafePerformIO $ do+ fptr <- B.mallocByteString outputLength+ newIv <- withForeignPtr fptr $ \o ->+ keyToPtr ctx $ \k ->+ ivCopyPtr iv $ \i -> do+ c_aes_gen_ctr_cont (castPtr o) k i (fromIntegral nbBlocks)+ let !out = B.PS fptr 0 outputLength+ return $! (out `seq` newIv `seq` (out, newIv))+ where+ (nbBlocks',r) = len `quotRem` 16+ nbBlocks = if r == 0 then nbBlocks' else nbBlocks' + 1+ outputLength = nbBlocks * 16++{- TODO: when genCTR has same AESIV requirements for IV, add the following rules:+ - RULES "snd . genCounter" forall ctx iv len . snd (genCounter ctx iv len) = genCTR ctx iv len+ -}+ -- | encrypt using Counter mode (CTR) -- -- in CTR mode encryption and decryption is the same operation. {-# NOINLINE encryptCTR #-} encryptCTR :: Byteable iv => AES -- ^ AES Context- -> iv -- ^ initial vector, usually representing a 128 bit integer+ -> iv -- ^ initial vector of AES block size (usually representing a 128 bit integer) -> ByteString -- ^ plaintext input -> ByteString -- ^ ciphertext output encryptCTR ctx iv input | len <= 0 = B.empty+ | byteableLength iv /= 16 = error $ "AES error: IV length must be block size (16). Its length is: " ++ (show $ byteableLength iv) | 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)@@ -362,6 +422,7 @@ -> AES -> iv -> ByteString -> ByteString doCBC f ctx iv input | len == 0 = B.empty+ | byteableLength iv /= 16 = error $ "AES error: IV length must be block size (16). Its length is: " ++ (show $ byteableLength iv) | r /= 0 = error $ "Encryption error: input length must be a multiple of block size (16). Its length is: " ++ (show len) | otherwise = unsafeCreate len $ \o -> withKeyAndIV ctx iv $ \k v ->@@ -555,6 +616,9 @@ ------------------------------------------------------------------------ foreign import ccall "aes.h aes_gen_ctr" c_aes_gen_ctr :: CString -> Ptr AES -> Ptr Word8 -> CUInt -> IO ()++foreign import ccall unsafe "aes.h aes_gen_ctr_cont"+ c_aes_gen_ctr_cont :: CString -> Ptr AES -> Ptr Word8 -> CUInt -> IO () foreign import ccall "aes.h aes_encrypt_ctr" c_aes_encrypt_ctr :: CString -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ()
Tests/KATGCM.hs view
@@ -58,8 +58,36 @@ , {-tag = -}"\x94\xd1\x47\xc3\xa2\xca\x93\xe9\x66\x93\x1e\x3b\xb3\xbb\x67\x01") ] +vectors_aes256_enc :: [KATGCM]+vectors_aes256_enc =+ [+ ( "\xb5\x2c\x50\x5a\x37\xd7\x8e\xda\x5d\xd3\x4f\x20\xc2\x25\x40\xea\x1b\x58\x96\x3c\xf8\xe5\xbf\x8f\xfa\x85\xf9\xf2\x49\x25\x05\xb4"+ , "\x51\x6c\x33\x92\x9d\xf5\xa3\x28\x4f\xf4\x63\xd7"+ , ""+ , ""+ , ""+ , 16+ , "\xbd\xc1\xac\x88\x4d\x33\x24\x57\xa1\xd2\x66\x4f\x16\x8c\x76\xf0")+ , ( "\x78\xdc\x4e\x0a\xaf\x52\xd9\x35\xc3\xc0\x1e\xea\x57\x42\x8f\x00\xca\x1f\xd4\x75\xf5\xda\x86\xa4\x9c\x8d\xd7\x3d\x68\xc8\xe2\x23"+ , "\xd7\x9c\xf2\x2d\x50\x4c\xc7\x93\xc3\xfb\x6c\x8a"+ , "\xb9\x6b\xaa\x8c\x1c\x75\xa6\x71\xbf\xb2\xd0\x8d\x06\xbe\x5f\x36"+ , ""+ , ""+ , 16+ , "\x3e\x5d\x48\x6a\xa2\xe3\x0b\x22\xe0\x40\xb8\x57\x23\xa0\x6e\x76")+ , ( "\xc3\xf1\x05\x86\xf2\x46\xaa\xca\xdc\xce\x37\x01\x44\x17\x70\xc0\x3c\xfe\xc9\x40\xaf\xe1\x90\x8c\x4c\x53\x7d\xf4\xe0\x1c\x50\xa0"+ , "\x4f\x52\xfa\xa1\xfa\x67\xa0\xe5\xf4\x19\x64\x52"+ , "\x46\xf9\xa2\x2b\x4e\x52\xe1\x52\x65\x13\xa9\x52\xdb\xee\x3b\x91\xf6\x95\x95\x50\x1e\x01\x77\xd5\x0f\xf3\x64\x63\x85\x88\xc0\x8d\x92\xfa\xb8\xc5\x8a\x96\x9b\xdc\xc8\x4c\x46\x8d\x84\x98\xc4\xf0\x63\x92\xb9\x9e\xd5\xe0\xc4\x84\x50\x7f\xc4\x8d\xc1\x8d\x87\xc4\x0e\x2e\xd8\x48\xb4\x31\x50\xbe\x9d\x36\xf1\x4c\xf2\xce\xf1\x31\x0b\xa4\xa7\x45\xad\xcc\x7b\xdc\x41\xf6"+ , "\x79\xd9\x7e\xa3\xa2\xed\xd6\x50\x45\x82\x1e\xa7\x45\xa4\x47\x42"+ , "\x56\x0c\xf7\x16\xe5\x61\x90\xe9\x39\x7c\x2f\x10\x36\x29\xeb\x1f"+ , 16+ , "\xff\x7c\x91\x24\x87\x96\x44\xe8\x05\x55\x68\x7d\x27\x3c\x55\xd8"+ )+ ]+ vectors_encrypt =- [ ("AES128 Enc", vectors_aes128_enc)+ [ ("AES128 Enc", vectors_aes128_enc)+ , ("AES256 Enc", vectors_aes256_enc) ] vectors_decrypt = []
Tests/Tests.hs view
@@ -23,6 +23,13 @@ import qualified KATGCM import qualified KATOCB3 +instance Show AES.AES where+ show _ = "AES"+instance Arbitrary AES.AESIV where+ arbitrary = AES.aesIV_ . B.pack <$> replicateM 16 arbitrary+instance Arbitrary AES.AES where+ arbitrary = AES.initAES . B.pack <$> replicateM 16 arbitrary+ 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 }@@ -62,10 +69,16 @@ { kat_ECB = map toKatECB KATECB.vectors_aes256_enc , kat_CBC = map toKatCBC KATCBC.vectors_aes256_enc , kat_XTS = map toKatXTS KATXTS.vectors_aes256_enc+ , kat_AEAD = map toKatGCM KATGCM.vectors_aes256_enc } main = defaultMain [ testBlockCipher kats128 (undefined :: AES.AES128) , testBlockCipher kats192 (undefined :: AES.AES192) , testBlockCipher kats256 (undefined :: AES.AES256)+ , testProperty "genCtr" $ \(key, iv1) ->+ let (bs1, iv2) = AES.genCounter key iv1 32+ (bs2, iv3) = AES.genCounter key iv2 32+ (bsAll, iv3') = AES.genCounter key iv1 64+ in (B.concat [bs1,bs2] == bsAll && iv3 == iv3') ]
cbits/aes.c view
@@ -169,7 +169,7 @@ #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_INIT(strength) 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@@ -262,7 +262,7 @@ d(output, key, iv, input, nb_blocks); } -void aes_gen_ctr(aes_block *output, aes_key *key, aes_block *iv, uint32_t nb_blocks)+void aes_gen_ctr(aes_block *output, aes_key *key, const aes_block *iv, uint32_t nb_blocks) { aes_block block; @@ -274,6 +274,21 @@ } } +void aes_gen_ctr_cont(aes_block *output, aes_key *key, aes_block *iv, uint32_t nb_blocks)+{+ aes_block block;++ /* preload IV in block */+ block128_copy(&block, iv);++ for ( ; nb_blocks-- > 0; output++, block128_inc_be(&block)) {+ aes_encrypt_block(output, key, &block);+ }++ /* copy back the IV */+ block128_copy(iv, &block);+}+ void aes_encrypt_ctr(uint8_t *output, aes_key *key, aes_block *iv, uint8_t *input, uint32_t len) { ctr_f e = GET_CTR_ENCRYPT(key->strength);@@ -674,8 +689,8 @@ } } -static int ocb_generic_crypt(uint8_t *output, aes_ocb *ocb, aes_key *key,- uint8_t *input, uint32_t length, int encrypt)+static void ocb_generic_crypt(uint8_t *output, aes_ocb *ocb, aes_key *key,+ uint8_t *input, uint32_t length, int encrypt) { block128 tmp, pad; unsigned int i;
cbits/aes.h view
@@ -77,7 +77,8 @@ 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(aes_block *output, aes_key *key, aes_block *iv, uint32_t nb_blocks);+void aes_gen_ctr(aes_block *output, aes_key *key, const aes_block *iv, uint32_t nb_blocks);+void aes_gen_ctr_cont(aes_block *output, aes_key *key, aes_block *iv, 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);
cbits/aes_generic.c view
@@ -89,7 +89,7 @@ }; #define G(a,b,c,d,e,f) { a,b,c,d,e,f }-uint8_t gmtab[256][6] =+static uint8_t gmtab[256][6] = { G(0x00, 0x00, 0x00, 0x00, 0x00, 0x00), G(0x02, 0x03, 0x09, 0x0b, 0x0d, 0x0e), G(0x04, 0x06, 0x12, 0x16, 0x1a, 0x1c), G(0x06, 0x05, 0x1b, 0x1d, 0x17, 0x12),
cbits/block128.h view
@@ -46,7 +46,7 @@ for (i = 0; i < len; i++) block->b[i] = src[i]; } -static inline void block128_copy(block128 *d, block128 *s)+static inline void block128_copy(block128 *d, const block128 *s) { d->q[0] = s->q[0]; d->q[1] = s->q[1]; }@@ -56,13 +56,13 @@ d->q[0] = 0; d->q[1] = 0; } -static inline void block128_xor(block128 *d, block128 *s)+static inline void block128_xor(block128 *d, const block128 *s) { d->q[0] ^= s->q[0]; d->q[1] ^= s->q[1]; } -static inline void block128_vxor(block128 *d, block128 *s1, block128 *s2)+static inline void block128_vxor(block128 *d, const block128 *s1, const block128 *s2) { d->q[0] = s1->q[0] ^ s2->q[0]; d->q[1] = s1->q[1] ^ s2->q[1];
cipher-aes.cabal view
@@ -1,5 +1,5 @@ Name: cipher-aes-Version: 0.2.8+Version: 0.2.11 Description: Fast AES cipher implementation with advanced mode of operations. .@@ -24,7 +24,7 @@ Synopsis: Fast AES cipher implementation with advanced mode of operations Category: Cryptography Build-Type: Simple-Homepage: http://github.com/vincenthz/hs-cipher-aes+Homepage: https://github.com/vincenthz/hs-cipher-aes Cabal-Version: >=1.8 Extra-Source-Files: Tests/*.hs cbits/*.h@@ -46,7 +46,7 @@ cbits/aes.c cbits/gf.c cbits/cpu.c- if flag(support_aesni) && os(linux) && (arch(i386) || arch(x86_64))+ if flag(support_aesni) && (os(linux) || os(freebsd)) && (arch(i386) || arch(x86_64)) CC-options: -mssse3 -maes -mpclmul -DWITH_AESNI C-sources: cbits/aes_x86ni.c @@ -78,4 +78,4 @@ source-repository head type: git- location: git://github.com/vincenthz/hs-cipher-aes+ location: https://github.com/vincenthz/hs-cipher-aes