From 55bf620365422446f2a2ffd1dd04d1492be95149 Mon Sep 17 00:00:00 2001 From: Baojun Wang Date: Wed, 31 May 2017 19:33:48 -0700 Subject: [PATCH 01/15] add aes ccm support --- Crypto/Cipher/AES.hs | 1 + Crypto/Cipher/AES/Primitive.hs | 116 ++++++++++++++++++ Crypto/Cipher/Types.hs | 2 + Crypto/Cipher/Types/Base.hs | 7 +- cbits/cryptonite_aes.c | 212 +++++++++++++++++++++++++++++++++ cbits/cryptonite_aes.h | 19 +++ 6 files changed, 356 insertions(+), 1 deletion(-) diff --git a/Crypto/Cipher/AES.hs b/Crypto/Cipher/AES.hs index 9b5cecf..5ce10c4 100644 --- a/Crypto/Cipher/AES.hs +++ b/Crypto/Cipher/AES.hs @@ -59,6 +59,7 @@ instance BlockCipher CSTR where \ ; ctrCombine (CSTR aes) (IV iv) = encryptCTR aes (IV iv) \ ; aeadInit AEAD_GCM (CSTR aes) iv = CryptoPassed $ AEAD (gcmMode aes) (gcmInit aes iv) \ ; aeadInit AEAD_OCB (CSTR aes) iv = CryptoPassed $ AEAD (ocbMode aes) (ocbInit aes iv) \ + ; aeadInit (AEAD_CCM n m l) (CSTR aes) iv = CryptoPassed $ AEAD (ccmMode aes) (ccmInit aes iv n m l) \ ; aeadInit _ _ _ = CryptoFailed CryptoError_AEADModeNotSupported \ }; \ instance BlockCipher128 CSTR where \ diff --git a/Crypto/Cipher/AES/Primitive.hs b/Crypto/Cipher/AES/Primitive.hs index 3536b6d..f139c17 100644 --- a/Crypto/Cipher/AES/Primitive.hs +++ b/Crypto/Cipher/AES/Primitive.hs @@ -44,6 +44,10 @@ module Crypto.Cipher.AES.Primitive -- * Incremental OCB , ocbMode , ocbInit + + -- * CCM + , ccmMode + , ccmInit ) where import Data.Word @@ -73,6 +77,7 @@ instance BlockCipher AES where ctrCombine = encryptCTR aeadInit AEAD_GCM aes iv = CryptoPassed $ AEAD (gcmMode aes) (gcmInit aes iv) aeadInit AEAD_OCB aes iv = CryptoPassed $ AEAD (ocbMode aes) (ocbInit aes iv) + aeadInit (AEAD_CCM n m l) aes iv = CryptoPassed $ AEAD (ccmMode aes) (ccmInit aes iv n m l) aeadInit _ _ _ = CryptoFailed CryptoError_AEADModeNotSupported instance BlockCipher128 AES where xtsEncrypt = encryptXTS @@ -96,6 +101,14 @@ ocbMode aes = AEADModeImpl , aeadImplFinalize = ocbFinish aes } +-- | Create an AES AEAD implementation for GCM +ccmMode :: AES -> AEADModeImpl AESCCM +ccmMode aes = AEADModeImpl + { aeadImplAppendHeader = ccmAppendAAD + , aeadImplEncrypt = ccmEncrypt aes + , aeadImplDecrypt = ccmDecrypt aes + , aeadImplFinalize = ccmFinish aes + } -- | AES Context (pre-processed key) newtype AES = AES ScrubbedBytes @@ -109,12 +122,19 @@ newtype AESGCM = AESGCM ScrubbedBytes newtype AESOCB = AESOCB ScrubbedBytes deriving (NFData) +-- | AESCCM State +newtype AESCCM = AESCCM ScrubbedBytes + deriving (NFData) + sizeGCM :: Int sizeGCM = 80 sizeOCB :: Int sizeOCB = 160 +sizeCCM :: Int +sizeCCM = 544 + keyToPtr :: AES -> (Ptr AES -> IO a) -> IO a keyToPtr (AES b) f = withByteArray b (f . castPtr) @@ -152,6 +172,16 @@ withOCBKeyAndCopySt aes (AESOCB gcmSt) f = a <- withByteArray newSt $ \gcmStPtr -> f (castPtr gcmStPtr) aesPtr return (a, AESOCB newSt) +withCCMKeyAndCopySt :: AES -> AESCCM -> (Ptr AESCCM -> Ptr AES -> IO a) -> IO (a, AESCCM) +withCCMKeyAndCopySt aes (AESCCM ccmSt) f = + keyToPtr aes $ \aesPtr -> do + newSt <- B.copy ccmSt (\_ -> return ()) + a <- withByteArray newSt $ \ccmStPtr -> f (castPtr ccmStPtr) aesPtr + return (a, AESCCM newSt) + +withNewCCMSt :: AESCCM -> (Ptr AESCCM -> IO ()) -> IO AESCCM +withNewCCMSt (AESCCM ccmSt) f = B.copy ccmSt (f . castPtr) >>= \sm2 -> return (AESCCM sm2) + -- | Initialize a new context with a key -- -- Key needs to be of length 16, 24 or 32 bytes. Any other values will return failure @@ -447,6 +477,78 @@ ocbFinish ctx ocb taglen = AuthTag $ B.take taglen computeTag where computeTag = B.allocAndFreeze 16 $ \t -> withOCBKeyAndCopySt ctx ocb (c_aes_ocb_finish (castPtr t)) >> return () +ccmGetM :: CCM_M -> Int +ccmGetL :: CCM_L -> Int +ccmGetM m = case m of + CCM_M4 -> 4 + CCM_M6 -> 6 + CCM_M8 -> 8 + CCM_M10 -> 10 + CCM_M12 -> 12 + CCM_M14 -> 14 + CCM_M16 -> 16 + +ccmGetL l = case l of + CCM_L2 -> 2 + CCM_L3 -> 3 + CCM_L4 -> 4 + +-- | initialize a ccm context +{-# NOINLINE ccmInit #-} +ccmInit :: ByteArrayAccess iv => AES -> iv -> Int -> CCM_M -> CCM_L -> AESCCM +ccmInit ctx iv n m l = unsafeDoIO $ do + sm <- B.alloc sizeCCM $ \ccmStPtr -> + withKeyAndIV ctx iv $ \k v -> + c_aes_ccm_init (castPtr ccmStPtr) k v (fromIntegral $ B.length iv) (fromIntegral n) (fromIntegral (ccmGetM m)) (fromIntegral (ccmGetL l)) + return $ AESCCM sm + +-- | append data which is only going to be authenticated to the CCM context. +-- +-- needs to happen after initialization and before appending encryption/decryption data. +{-# NOINLINE ccmAppendAAD #-} +ccmAppendAAD :: ByteArrayAccess aad => AESCCM -> aad -> AESCCM +ccmAppendAAD ccmSt input = unsafeDoIO doAppend + where doAppend = + withNewCCMSt ccmSt $ \ccmStPtr -> + withByteArray input $ \i -> + c_aes_ccm_aad ccmStPtr i (fromIntegral $ B.length input) + +doCTR :: (ByteArray ba, BlockCipher cipher) => cipher -> ba -> ba -> ba +doCTR ctx iv0 input = ctrCombine ctx (ivAdd (IV (B.convert iv0 :: B.Bytes)) 1) input + +-- | append data to encrypt and append to the CCM context +-- +-- the bytearray needs to be a multiple of AES block size, unless it's the last call to this function. +-- needs to happen after AAD appending, or after initialization if no AAD data. +{-# NOINLINE ccmEncrypt #-} +ccmEncrypt :: ByteArray ba => AES -> AESCCM -> ba -> (ba, AESCCM) +ccmEncrypt ctx ccm input = unsafeDoIO $ (withCCMKeyAndCopySt ctx ccm cbcmacAndIv >>= \(iv0, cc) -> return (doCTR ctx iv0 input, cc)) + where len = B.length input + cbcmacAndIv ccmStPtr aesPtr = + B.alloc 16 $ \o -> + withByteArray input $ \i -> + c_aes_ccm_encrypt (castPtr o) ccmStPtr aesPtr i (fromIntegral len) + +-- | append data to decrypt and append to the CCM context +-- +-- the bytearray needs to be a multiple of AES block size, unless it's the last call to this function. +-- needs to happen after AAD appending, or after initialization if no AAD data. +{-# NOINLINE ccmDecrypt #-} +ccmDecrypt :: ByteArray ba => AES -> AESCCM -> ba -> (ba, AESCCM) +ccmDecrypt ctx ccm input = unsafeDoIO $ withCCMKeyAndCopySt ctx ccm doDec + where len = B.length input + doDec ccmStPtr aesPtr = + B.alloc len $ \o -> + withByteArray input $ \i -> + c_aes_ccm_decrypt (castPtr o) ccmStPtr aesPtr i (fromIntegral len) + +-- | Generate the Tag from CCM context +{-# NOINLINE ccmFinish #-} +ccmFinish :: AES -> AESCCM -> Int -> AuthTag +ccmFinish ctx ccm taglen = AuthTag $ B.take taglen computeTag + where computeTag = B.allocAndFreeze 16 $ \t -> + withCCMKeyAndCopySt ctx ccm (c_aes_ccm_finish (castPtr t)) >> return () + ------------------------------------------------------------------------ foreign import ccall "cryptonite_aes.h cryptonite_aes_initkey" c_aes_init :: Ptr AES -> CString -> CUInt -> IO () @@ -508,3 +610,17 @@ foreign import ccall "cryptonite_aes.h cryptonite_aes_ocb_decrypt" foreign import ccall "cryptonite_aes.h cryptonite_aes_ocb_finish" c_aes_ocb_finish :: CString -> Ptr AESOCB -> Ptr AES -> IO () +foreign import ccall "cryptonite_aes.h cryptonite_aes_ccm_init" + c_aes_ccm_init :: Ptr AESCCM -> Ptr AES -> Ptr Word8 -> CUInt -> CULong -> CInt -> CInt -> IO () + +foreign import ccall "cryptonite_aes.h cryptonite_aes_ccm_aad" + c_aes_ccm_aad :: Ptr AESCCM -> CString -> CUInt -> IO () + +foreign import ccall "cryptonite_aes.h cryptonite_aes_ccm_encrypt" + c_aes_ccm_encrypt :: CString -> Ptr AESCCM -> Ptr AES -> CString -> CUInt -> IO () + +foreign import ccall "cryptonite_aes.h cryptonite_aes_ccm_decrypt" + c_aes_ccm_decrypt :: CString -> Ptr AESCCM -> Ptr AES -> CString -> CUInt -> IO () + +foreign import ccall "cryptonite_aes.h cryptonite_aes_ccm_finish" + c_aes_ccm_finish :: CString -> Ptr AESCCM -> Ptr AES -> IO () diff --git a/Crypto/Cipher/Types.hs b/Crypto/Cipher/Types.hs index 8ab88c0..ab5dd37 100644 --- a/Crypto/Cipher/Types.hs +++ b/Crypto/Cipher/Types.hs @@ -21,6 +21,8 @@ module Crypto.Cipher.Types -- , cfb8Decrypt -- * AEAD functions , AEADMode(..) + , CCM_M(..) + , CCM_L(..) , module Crypto.Cipher.Types.AEAD -- * Initial Vector type and constructor , IV diff --git a/Crypto/Cipher/Types/Base.hs b/Crypto/Cipher/Types/Base.hs index e2c1652..03a20f8 100644 --- a/Crypto/Cipher/Types/Base.hs +++ b/Crypto/Cipher/Types/Base.hs @@ -14,6 +14,8 @@ module Crypto.Cipher.Types.Base , Cipher(..) , AuthTag(..) , AEADMode(..) + , CCM_M(..) + , CCM_L(..) , DataUnitOffset ) where @@ -39,10 +41,13 @@ newtype AuthTag = AuthTag { unAuthTag :: Bytes } instance Eq AuthTag where (AuthTag a) == (AuthTag b) = B.constEq a b +data CCM_M = CCM_M4 | CCM_M6 | CCM_M8 | CCM_M10 | CCM_M12 | CCM_M14 | CCM_M16 deriving (Show, Eq) +data CCM_L = CCM_L2 | CCM_L3 | CCM_L4 deriving (Show, Eq) + -- | AEAD Mode data AEADMode = AEAD_OCB -- OCB3 - | AEAD_CCM + | AEAD_CCM Int CCM_M CCM_L | AEAD_EAX | AEAD_CWC | AEAD_GCM diff --git a/cbits/cryptonite_aes.c b/cbits/cryptonite_aes.c index a6be9c5..df6186d 100644 --- a/cbits/cryptonite_aes.c +++ b/cbits/cryptonite_aes.c @@ -52,6 +52,8 @@ void cryptonite_aes_generic_gcm_encrypt(uint8_t *output, aes_gcm *gcm, aes_key * void cryptonite_aes_generic_gcm_decrypt(uint8_t *output, aes_gcm *gcm, aes_key *key, uint8_t *input, uint32_t length); void cryptonite_aes_generic_ocb_encrypt(uint8_t *output, aes_ocb *ocb, aes_key *key, uint8_t *input, uint32_t length); void cryptonite_aes_generic_ocb_decrypt(uint8_t *output, aes_ocb *ocb, aes_key *key, uint8_t *input, uint32_t length); +void cryptonite_aes_generic_ccm_encrypt(uint8_t *output, aes_ccm *ccm, aes_key *key, uint8_t *input, uint32_t length); +void cryptonite_aes_generic_ccm_decrypt(uint8_t *output, aes_ccm *ccm, aes_key *key, uint8_t *input, uint32_t length); enum { /* init */ @@ -76,6 +78,9 @@ enum { /* ocb */ ENCRYPT_OCB_128, ENCRYPT_OCB_192, ENCRYPT_OCB_256, DECRYPT_OCB_128, DECRYPT_OCB_192, DECRYPT_OCB_256, + /* ccm */ + ENCRYPT_CCM_128, ENCRYPT_CCM_192, ENCRYPT_CCM_256, + DECRYPT_CCM_128, DECRYPT_CCM_192, DECRYPT_CCM_256, }; void *cryptonite_aes_branch_table[] = { @@ -129,6 +134,13 @@ void *cryptonite_aes_branch_table[] = { [DECRYPT_OCB_128] = cryptonite_aes_generic_ocb_decrypt, [DECRYPT_OCB_192] = cryptonite_aes_generic_ocb_decrypt, [DECRYPT_OCB_256] = cryptonite_aes_generic_ocb_decrypt, + /* CCM */ + [ENCRYPT_CCM_128] = cryptonite_aes_generic_ccm_encrypt, + [ENCRYPT_CCM_192] = cryptonite_aes_generic_ccm_encrypt, + [ENCRYPT_CCM_256] = cryptonite_aes_generic_ccm_encrypt, + [DECRYPT_CCM_128] = cryptonite_aes_generic_ccm_decrypt, + [DECRYPT_CCM_192] = cryptonite_aes_generic_ccm_decrypt, + [DECRYPT_CCM_256] = cryptonite_aes_generic_ccm_decrypt, }; typedef void (*init_f)(aes_key *, uint8_t *, uint8_t); @@ -138,6 +150,7 @@ typedef void (*ctr_f)(uint8_t *output, aes_key *key, aes_block *iv, uint8_t *inp 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 (*ocb_crypt_f)(uint8_t *output, aes_ocb *ocb, aes_key *key, uint8_t *input, uint32_t length); +typedef void (*ccm_crypt_f)(uint8_t *output, aes_ccm *ccm, 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 @@ -165,6 +178,10 @@ typedef void (*block_f)(aes_block *output, aes_key *key, aes_block *input); ((ocb_crypt_f) (cryptonite_aes_branch_table[ENCRYPT_OCB_128 + strength])) #define GET_OCB_DECRYPT(strength) \ ((ocb_crypt_f) (cryptonite_aes_branch_table[DECRYPT_OCB_128 + strength])) +#define GET_CCM_ENCRYPT(strength) \ + ((ccm_crypt_f) (cryptonite_aes_branch_table[ENCRYPT_CCM_128 + strength])) +#define GET_CCM_DECRYPT(strength) \ + ((ccm_crypt_f) (cryptonite_aes_branch_table[DECRYPT_CCM_128 + strength])) #define cryptonite_aes_encrypt_block(o,k,i) \ (((block_f) (cryptonite_aes_branch_table[ENCRYPT_BLOCK_128 + k->strength]))(o,k,i)) #define cryptonite_aes_decrypt_block(o,k,i) \ @@ -182,6 +199,8 @@ typedef void (*block_f)(aes_block *output, aes_key *key, aes_block *input); #define GET_GCM_DECRYPT(strength) cryptonite_aes_generic_gcm_decrypt #define GET_OCB_ENCRYPT(strength) cryptonite_aes_generic_ocb_encrypt #define GET_OCB_DECRYPT(strength) cryptonite_aes_generic_ocb_decrypt +#define GET_CCM_ENCRYPT(strength) cryptonite_aes_generic_ccm_encrypt +#define GET_CCM_DECRYPT(strength) cryptonite_aes_generic_ccm_decrypt #define cryptonite_aes_encrypt_block(o,k,i) cryptonite_aes_generic_encrypt_block(o,k,i) #define cryptonite_aes_decrypt_block(o,k,i) cryptonite_aes_generic_decrypt_block(o,k,i) #endif @@ -321,6 +340,18 @@ void cryptonite_aes_gcm_decrypt(uint8_t *output, aes_gcm *gcm, aes_key *key, uin d(output, gcm, key, input, length); } +void cryptonite_aes_ccm_encrypt(uint8_t *output, aes_ccm *ccm, aes_key *key, uint8_t *input, uint32_t length) +{ + ccm_crypt_f e = GET_CCM_ENCRYPT(key->strength); + e(output, ccm, key, input, length); +} + +void cryptonite_aes_ccm_decrypt(uint8_t *output, aes_ccm *ccm, aes_key *key, uint8_t *input, uint32_t length) +{ + ccm_crypt_f d = GET_CCM_DECRYPT(key->strength); + d(output, ccm, key, input, length); +} + void cryptonite_aes_ocb_encrypt(uint8_t *output, aes_ocb *ocb, aes_key *key, uint8_t *input, uint32_t length) { ocb_crypt_f e = GET_OCB_ENCRYPT(key->strength); @@ -406,6 +437,156 @@ void cryptonite_aes_gcm_finish(uint8_t *tag, aes_gcm *gcm, aes_key *key) } } +static inline int ccm_b0_flags(int has_adata, int m, int l) +{ + return 8*m + l + (has_adata? 64: 0); +} + +/* depends on input size */ +static void ccm_encode_b0(block128* output, aes_ccm* ccm, int has_adata) +{ + int last = 15; + int m = ccm->length_M; + int l = ccm->length_L; + uint64_t msg_len = ccm->length_input; + + block128_zero(output); + block128_copy(output, &ccm->nonce); + output->b[0] = ccm_b0_flags(has_adata, (m-2)/2, l-1); + while (msg_len > 0) { + output->b[last--] = msg_len & 0xff; + msg_len >>= 8; + } +} + +/* encode adata length */ +static int ccm_encode_la(block128* output, uint64_t la) +{ + if (la < ( (1 << 16) - (1 << 8)) ) { + output->b[0] = (la >> 8) & 0xff; + output->b[1] = la & 0xff; + return 2; + } else if (la < (1ull << 32)) { + output->b[0] = 0xff; + output->b[1] = 0xfe; + output->b[2] = (la >> 24) & 0xff; + output->b[3] = (la >> 16) & 0xff; + output->b[4] = (la >> 8) & 0xff; + output->b[5] = la & 0xff; + return 6; + } else { + output->b[0] = 0xff; + output->b[1] = 0xff; + output->b[2] = (la >> 56) & 0xff; + output->b[3] = (la >> 48) & 0xff; + output->b[4] = (la >> 40) & 0xff; + output->b[5] = (la >> 32) & 0xff; + output->b[6] = (la >> 24) & 0xff; + output->b[7] = (la >> 16) & 0xff; + output->b[8] = (la >> 8) & 0xff; + output->b[9] = la & 0xff; + return 10; + } +} + +static void ccm_encode_ctr(block128* out, aes_ccm* ccm, unsigned int cnt) +{ + int last = 15; + block128_copy(out, &ccm->nonce); + out->b[0] = ccm->length_L - 1; + + while (cnt > 0) { + out->b[last--] = cnt & 0xff; + cnt >>= 8; + } +} + +static void ccm_cbcmac_add(aes_ccm* ccm, aes_key* key, block128* bi) +{ + block128_xor(&ccm->xi, bi); + cryptonite_aes_generic_encrypt_block(&ccm->xi, key, &ccm->xi); +} + +/* even though it is possible to support message size as large as 2^64, we support up to 2^32 only */ +void cryptonite_aes_ccm_init(aes_ccm *ccm, aes_key *key, uint8_t *nonce, uint32_t nonce_len, uint64_t input_size, int m, int l) +{ + memset(ccm, 0, sizeof(aes_ccm)); + + if (l < 2 || l > 4) return; + if (m != 4 && m != 6 && m != 8 && m != 10 + && m != 12 && m != 14 && m != 16) return; + + if (nonce_len != 15 - l) { + nonce_len = 15 - l; + } + + if (l <= 4) { + if (input_size >= (1ull << (8*l))) return; + } + + ccm->length_L = l; + ccm->length_M = m; + ccm->length_input = input_size; + + memcpy(&ccm->nonce.b[1], nonce, 15 - l); + memcpy(&ccm->aad_key, key, sizeof(aes_key)); + + ccm_encode_b0(&ccm->b0, ccm, 1); /* assume aad is present */ + ccm_encode_ctr(&ccm->iv, ccm, 0); + + cryptonite_aes_encrypt_block(&ccm->xi, key, &ccm->b0); +} + +/* even though l(a) can be as large as 2^64, we only handle aad up to 2 ^ 32 for practical reasons. + Also we don't support incremental aad add, because the 1st encoded adata has length information + */ +void cryptonite_aes_ccm_aad(aes_ccm *ccm, uint8_t *input, uint32_t length) +{ + block128 tmp; + aes_key* key = &ccm->aad_key; + + ccm->length_aad = length; + int len_len; + + block128_zero(&tmp); + len_len = ccm_encode_la(&tmp, length); + + if (length < 16 - len_len) { + memcpy(&tmp.b[len_len], input, length); + length = 0; + } else { + memcpy(&tmp.b[len_len], input, 16 - len_len); + input += 16 - len_len; + length -= 16 - len_len; + } + + ccm_cbcmac_add(ccm, key, &tmp); + + for (; length >= 16; input += 16, length -= 16) { + block128_copy(&tmp, (block128*)input); + ccm_cbcmac_add(ccm, key, &tmp); + + } + if (length > 0) { + block128_zero(&tmp); + block128_copy_bytes(&tmp, input, length); + ccm_cbcmac_add(ccm, key, &tmp); + } + + memset(&ccm->aad_key, 0, sizeof(aes_key)); +} + +void cryptonite_aes_ccm_finish(uint8_t *tag, aes_ccm *ccm, aes_key *key) +{ + block128 iv, s0; + block128 u; + + ccm_encode_ctr(&iv, ccm, 0); + cryptonite_aes_encrypt_block(&s0, key, &iv); + block128_vxor(&u, &ccm->xi, &s0); + memcpy(tag, u.b, ccm->length_M); +} + static inline void ocb_block_double(block128 *d, block128 *s) { unsigned int i; @@ -739,6 +920,37 @@ static void ocb_generic_crypt(uint8_t *output, aes_ocb *ocb, aes_key *key, } } +void cryptonite_aes_generic_ccm_encrypt(uint8_t *output, aes_ccm *ccm, aes_key *key, uint8_t *input, uint32_t length) +{ + block128 tmp; + + /* when aad is absent, reset b0 block */ + if (ccm->length_aad == 0) { + ccm_encode_b0(&ccm->b0, ccm, 0); /* assume aad is present */ + cryptonite_aes_encrypt_block(&ccm->xi, key, &ccm->b0); + } + + if (length != ccm->length_input) { + return; + } + + for (;length >= 16; input += 16, length -= 16) { + block128_copy(&tmp, (block128*)input); + ccm_cbcmac_add(ccm, key, &tmp); + } + if (length > 0) { + block128_zero(&tmp); + block128_copy_bytes(&tmp, input, length); + ccm_cbcmac_add(ccm, key, &tmp); + } + block128_copy((block128*)output, &ccm->iv); +} + +void cryptonite_aes_generic_ccm_decrypt(uint8_t *output, aes_ccm *ccm, aes_key *key, uint8_t *input, uint32_t length) +{ + cryptonite_aes_generic_ccm_encrypt(output, ccm, key, input, length); +} + void cryptonite_aes_generic_ocb_encrypt(uint8_t *output, aes_ocb *ocb, aes_key *key, uint8_t *input, uint32_t length) { ocb_generic_crypt(output, ocb, key, input, length, 1); diff --git a/cbits/cryptonite_aes.h b/cbits/cryptonite_aes.h index 733e0a3..70fbd47 100644 --- a/cbits/cryptonite_aes.h +++ b/cbits/cryptonite_aes.h @@ -55,6 +55,19 @@ typedef struct { uint64_t length_input; } aes_gcm; +/* size = 544 */ +typedef struct { + aes_block iv; /* iv with counter = 0 block */ + aes_block xi; /* X_i: cbc mac */ + aes_block b0; /* block b0 */ + aes_block nonce; + aes_key aad_key; + uint64_t length_aad; + uint64_t length_input; + int length_M; + int length_L; +} aes_ccm; + typedef struct { block128 offset_aad; block128 offset_enc; @@ -97,4 +110,10 @@ void cryptonite_aes_ocb_encrypt(uint8_t *output, aes_ocb *ocb, aes_key *key, uin void cryptonite_aes_ocb_decrypt(uint8_t *output, aes_ocb *ocb, aes_key *key, uint8_t *input, uint32_t length); void cryptonite_aes_ocb_finish(uint8_t *tag, aes_ocb *ocb, aes_key *key); +void cryptonite_aes_ccm_init(aes_ccm *ccm, aes_key *key, uint8_t *nonce, uint32_t len, uint64_t msg_size, int m, int l); +void cryptonite_aes_ccm_aad(aes_ccm *ccm, uint8_t *input, uint32_t length); +void cryptonite_aes_ccm_encrypt(uint8_t *output, aes_ccm *ccm, aes_key *key, uint8_t *input, uint32_t length); +void cryptonite_aes_ccm_decrypt(uint8_t *output, aes_ccm *ccm, aes_key *key, uint8_t *input, uint32_t length); +void cryptonite_aes_ccm_finish(uint8_t *tag, aes_ccm *ccm, aes_key *key); + #endif From 1e04890d733667c433f0ac818ffd18754e0b7752 Mon Sep 17 00:00:00 2001 From: Baojun Wang Date: Thu, 1 Jun 2017 10:25:09 -0700 Subject: [PATCH 02/15] Add ccm decrypt --- Crypto/Cipher/AES/Primitive.hs | 7 +------ tests/BlockCipher.hs | 10 +++++++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Crypto/Cipher/AES/Primitive.hs b/Crypto/Cipher/AES/Primitive.hs index f139c17..6c684b1 100644 --- a/Crypto/Cipher/AES/Primitive.hs +++ b/Crypto/Cipher/AES/Primitive.hs @@ -535,12 +535,7 @@ ccmEncrypt ctx ccm input = unsafeDoIO $ (withCCMKeyAndCopySt ctx ccm cbcmacAndIv -- needs to happen after AAD appending, or after initialization if no AAD data. {-# NOINLINE ccmDecrypt #-} ccmDecrypt :: ByteArray ba => AES -> AESCCM -> ba -> (ba, AESCCM) -ccmDecrypt ctx ccm input = unsafeDoIO $ withCCMKeyAndCopySt ctx ccm doDec - where len = B.length input - doDec ccmStPtr aesPtr = - B.alloc len $ \o -> - withByteArray input $ \i -> - c_aes_ccm_decrypt (castPtr o) ccmStPtr aesPtr i (fromIntegral len) +ccmDecrypt = ccmEncrypt -- | Generate the Tag from CCM context {-# NOINLINE ccmFinish #-} diff --git a/tests/BlockCipher.hs b/tests/BlockCipher.hs index 3243f70..988c053 100644 --- a/tests/BlockCipher.hs +++ b/tests/BlockCipher.hs @@ -16,7 +16,7 @@ import Imports import Data.Maybe import Crypto.Error import Crypto.Cipher.Types -import Data.ByteArray as B hiding (pack, null) +import Data.ByteArray as B hiding (pack, null, length) import qualified Data.ByteString as B hiding (all) ------------------------------------------------------------------------ @@ -389,7 +389,7 @@ testBlockCipherModes cipher = testBlockCipherAEAD :: BlockCipher a => a -> [TestTree] testBlockCipherAEAD cipher = [ testProperty "OCB" (aeadProp AEAD_OCB) - , testProperty "CCM" (aeadProp AEAD_CCM) + , testProperty "CCM" (aeadProp (AEAD_CCM 0 CCM_M16 CCM_L2)) , testProperty "EAX" (aeadProp AEAD_EAX) , testProperty "CWC" (aeadProp AEAD_CWC) , testProperty "GCM" (aeadProp AEAD_GCM) @@ -398,7 +398,7 @@ testBlockCipherAEAD cipher = toTests :: BlockCipher a => a -> (AEADMode -> AEADUnit a -> Bool) toTests _ = testProperty_AEAD testProperty_AEAD mode (AEADUnit key testIV (unPlaintext -> aad) (unPlaintext -> plaintext)) = withCtx key $ \ctx -> - case aeadInit mode ctx testIV of + case aeadInit mode' ctx testIV of CryptoPassed iniAead -> let aead = aeadAppendHeader iniAead aad (eText, aeadE) = aeadEncrypt aead plaintext @@ -409,6 +409,10 @@ testBlockCipherAEAD cipher = CryptoFailed err | err == CryptoError_AEADModeNotSupported -> True | otherwise -> error ("testProperty_AEAD: " ++ show err) + where mode' = updateCcmInputSize mode (B.length plaintext) + updateCcmInputSize aeadmode k = case aeadmode of + AEAD_CCM _ m l -> AEAD_CCM k m l + aeadOther -> aeadOther withCtx :: Cipher c => Key c -> (c -> a) -> a withCtx (Key key) f = From 48770bf79f446ae088102edd6e0266dac2beb469 Mon Sep 17 00:00:00 2001 From: Baojun Wang Date: Thu, 1 Jun 2017 15:16:24 -0700 Subject: [PATCH 03/15] fix aes ccm decryption cbcmac mis-match --- Crypto/Cipher/AES/Primitive.hs | 35 ++++++++--------- cbits/cryptonite_aes.c | 71 ++++++++++++++++++++-------------- cbits/cryptonite_aes.h | 17 ++++---- 3 files changed, 67 insertions(+), 56 deletions(-) diff --git a/Crypto/Cipher/AES/Primitive.hs b/Crypto/Cipher/AES/Primitive.hs index 6c684b1..2e4f2ac 100644 --- a/Crypto/Cipher/AES/Primitive.hs +++ b/Crypto/Cipher/AES/Primitive.hs @@ -104,7 +104,7 @@ ocbMode aes = AEADModeImpl -- | Create an AES AEAD implementation for GCM ccmMode :: AES -> AEADModeImpl AESCCM ccmMode aes = AEADModeImpl - { aeadImplAppendHeader = ccmAppendAAD + { aeadImplAppendHeader = ccmAppendAAD aes , aeadImplEncrypt = ccmEncrypt aes , aeadImplDecrypt = ccmDecrypt aes , aeadImplFinalize = ccmFinish aes @@ -133,7 +133,7 @@ sizeOCB :: Int sizeOCB = 160 sizeCCM :: Int -sizeCCM = 544 +sizeCCM = 80 keyToPtr :: AES -> (Ptr AES -> IO a) -> IO a keyToPtr (AES b) f = withByteArray b (f . castPtr) @@ -179,9 +179,6 @@ withCCMKeyAndCopySt aes (AESCCM ccmSt) f = a <- withByteArray newSt $ \ccmStPtr -> f (castPtr ccmStPtr) aesPtr return (a, AESCCM newSt) -withNewCCMSt :: AESCCM -> (Ptr AESCCM -> IO ()) -> IO AESCCM -withNewCCMSt (AESCCM ccmSt) f = B.copy ccmSt (f . castPtr) >>= \sm2 -> return (AESCCM sm2) - -- | Initialize a new context with a key -- -- Key needs to be of length 16, 24 or 32 bytes. Any other values will return failure @@ -506,15 +503,10 @@ ccmInit ctx iv n m l = unsafeDoIO $ do -- -- needs to happen after initialization and before appending encryption/decryption data. {-# NOINLINE ccmAppendAAD #-} -ccmAppendAAD :: ByteArrayAccess aad => AESCCM -> aad -> AESCCM -ccmAppendAAD ccmSt input = unsafeDoIO doAppend - where doAppend = - withNewCCMSt ccmSt $ \ccmStPtr -> - withByteArray input $ \i -> - c_aes_ccm_aad ccmStPtr i (fromIntegral $ B.length input) - -doCTR :: (ByteArray ba, BlockCipher cipher) => cipher -> ba -> ba -> ba -doCTR ctx iv0 input = ctrCombine ctx (ivAdd (IV (B.convert iv0 :: B.Bytes)) 1) input +ccmAppendAAD :: ByteArrayAccess aad => AES -> AESCCM -> aad -> AESCCM +ccmAppendAAD ctx ccm input = unsafeDoIO $ snd <$> withCCMKeyAndCopySt ctx ccm doAppend + where doAppend ccmStPtr aesPtr = + withByteArray input $ \i -> c_aes_ccm_aad ccmStPtr aesPtr i (fromIntegral $ B.length input) -- | append data to encrypt and append to the CCM context -- @@ -522,10 +514,10 @@ doCTR ctx iv0 input = ctrCombine ctx (ivAdd (IV (B.convert iv0 :: B.Bytes)) 1) i -- needs to happen after AAD appending, or after initialization if no AAD data. {-# NOINLINE ccmEncrypt #-} ccmEncrypt :: ByteArray ba => AES -> AESCCM -> ba -> (ba, AESCCM) -ccmEncrypt ctx ccm input = unsafeDoIO $ (withCCMKeyAndCopySt ctx ccm cbcmacAndIv >>= \(iv0, cc) -> return (doCTR ctx iv0 input, cc)) +ccmEncrypt ctx ccm input = unsafeDoIO $ withCCMKeyAndCopySt ctx ccm cbcmacAndIv where len = B.length input cbcmacAndIv ccmStPtr aesPtr = - B.alloc 16 $ \o -> + B.alloc len $ \o -> withByteArray input $ \i -> c_aes_ccm_encrypt (castPtr o) ccmStPtr aesPtr i (fromIntegral len) @@ -535,7 +527,12 @@ ccmEncrypt ctx ccm input = unsafeDoIO $ (withCCMKeyAndCopySt ctx ccm cbcmacAndIv -- needs to happen after AAD appending, or after initialization if no AAD data. {-# NOINLINE ccmDecrypt #-} ccmDecrypt :: ByteArray ba => AES -> AESCCM -> ba -> (ba, AESCCM) -ccmDecrypt = ccmEncrypt +ccmDecrypt ctx ccm input = unsafeDoIO $ withCCMKeyAndCopySt ctx ccm cbcmacAndIv + where len = B.length input + cbcmacAndIv ccmStPtr aesPtr = + B.alloc len $ \o -> + withByteArray input $ \i -> + c_aes_ccm_decrypt (castPtr o) ccmStPtr aesPtr i (fromIntegral len) -- | Generate the Tag from CCM context {-# NOINLINE ccmFinish #-} @@ -606,10 +603,10 @@ foreign import ccall "cryptonite_aes.h cryptonite_aes_ocb_finish" c_aes_ocb_finish :: CString -> Ptr AESOCB -> Ptr AES -> IO () foreign import ccall "cryptonite_aes.h cryptonite_aes_ccm_init" - c_aes_ccm_init :: Ptr AESCCM -> Ptr AES -> Ptr Word8 -> CUInt -> CULong -> CInt -> CInt -> IO () + c_aes_ccm_init :: Ptr AESCCM -> Ptr AES -> Ptr Word8 -> CUInt -> CUInt -> CInt -> CInt -> IO () foreign import ccall "cryptonite_aes.h cryptonite_aes_ccm_aad" - c_aes_ccm_aad :: Ptr AESCCM -> CString -> CUInt -> IO () + c_aes_ccm_aad :: Ptr AESCCM -> Ptr AES -> CString -> CUInt -> IO () foreign import ccall "cryptonite_aes.h cryptonite_aes_ccm_encrypt" c_aes_ccm_encrypt :: CString -> Ptr AESCCM -> Ptr AES -> CString -> CUInt -> IO () diff --git a/cbits/cryptonite_aes.c b/cbits/cryptonite_aes.c index df6186d..1888566 100644 --- a/cbits/cryptonite_aes.c +++ b/cbits/cryptonite_aes.c @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -448,7 +449,7 @@ static void ccm_encode_b0(block128* output, aes_ccm* ccm, int has_adata) int last = 15; int m = ccm->length_M; int l = ccm->length_L; - uint64_t msg_len = ccm->length_input; + unsigned msg_len = ccm->length_input; block128_zero(output); block128_copy(output, &ccm->nonce); @@ -460,7 +461,7 @@ static void ccm_encode_b0(block128* output, aes_ccm* ccm, int has_adata) } /* encode adata length */ -static int ccm_encode_la(block128* output, uint64_t la) +static int ccm_encode_la(block128* output, unsigned la) { if (la < ( (1 << 16) - (1 << 8)) ) { output->b[0] = (la >> 8) & 0xff; @@ -474,18 +475,6 @@ static int ccm_encode_la(block128* output, uint64_t la) output->b[4] = (la >> 8) & 0xff; output->b[5] = la & 0xff; return 6; - } else { - output->b[0] = 0xff; - output->b[1] = 0xff; - output->b[2] = (la >> 56) & 0xff; - output->b[3] = (la >> 48) & 0xff; - output->b[4] = (la >> 40) & 0xff; - output->b[5] = (la >> 32) & 0xff; - output->b[6] = (la >> 24) & 0xff; - output->b[7] = (la >> 16) & 0xff; - output->b[8] = (la >> 8) & 0xff; - output->b[9] = la & 0xff; - return 10; } } @@ -508,7 +497,7 @@ static void ccm_cbcmac_add(aes_ccm* ccm, aes_key* key, block128* bi) } /* even though it is possible to support message size as large as 2^64, we support up to 2^32 only */ -void cryptonite_aes_ccm_init(aes_ccm *ccm, aes_key *key, uint8_t *nonce, uint32_t nonce_len, uint64_t input_size, int m, int l) +void cryptonite_aes_ccm_init(aes_ccm *ccm, aes_key *key, uint8_t *nonce, uint32_t nonce_len, uint32_t input_size, int m, int l) { memset(ccm, 0, sizeof(aes_ccm)); @@ -529,22 +518,19 @@ void cryptonite_aes_ccm_init(aes_ccm *ccm, aes_key *key, uint8_t *nonce, uint32_ ccm->length_input = input_size; memcpy(&ccm->nonce.b[1], nonce, 15 - l); - memcpy(&ccm->aad_key, key, sizeof(aes_key)); ccm_encode_b0(&ccm->b0, ccm, 1); /* assume aad is present */ - ccm_encode_ctr(&ccm->iv, ccm, 0); - cryptonite_aes_encrypt_block(&ccm->xi, key, &ccm->b0); } /* even though l(a) can be as large as 2^64, we only handle aad up to 2 ^ 32 for practical reasons. Also we don't support incremental aad add, because the 1st encoded adata has length information */ -void cryptonite_aes_ccm_aad(aes_ccm *ccm, uint8_t *input, uint32_t length) +void cryptonite_aes_ccm_aad(aes_ccm *ccm, aes_key *key, uint8_t *input, uint32_t length) { block128 tmp; - aes_key* key = &ccm->aad_key; + assert (ccm->length_aad == 0); ccm->length_aad = length; int len_len; @@ -572,19 +558,17 @@ void cryptonite_aes_ccm_aad(aes_ccm *ccm, uint8_t *input, uint32_t length) block128_copy_bytes(&tmp, input, length); ccm_cbcmac_add(ccm, key, &tmp); } - - memset(&ccm->aad_key, 0, sizeof(aes_key)); + block128_copy(&ccm->header_cbcmac, &ccm->xi); } void cryptonite_aes_ccm_finish(uint8_t *tag, aes_ccm *ccm, aes_key *key) { block128 iv, s0; - block128 u; + block128_zero(&iv); ccm_encode_ctr(&iv, ccm, 0); cryptonite_aes_encrypt_block(&s0, key, &iv); - block128_vxor(&u, &ccm->xi, &s0); - memcpy(tag, u.b, ccm->length_M); + block128_vxor((block128*)tag, &ccm->xi, &s0); } static inline void ocb_block_double(block128 *d, block128 *s) @@ -922,18 +906,23 @@ static void ocb_generic_crypt(uint8_t *output, aes_ocb *ocb, aes_key *key, void cryptonite_aes_generic_ccm_encrypt(uint8_t *output, aes_ccm *ccm, aes_key *key, uint8_t *input, uint32_t length) { - block128 tmp; + block128 tmp, ctr; /* when aad is absent, reset b0 block */ if (ccm->length_aad == 0) { ccm_encode_b0(&ccm->b0, ccm, 0); /* assume aad is present */ cryptonite_aes_encrypt_block(&ccm->xi, key, &ccm->b0); + block128_copy(&ccm->header_cbcmac, &ccm->xi); } + assert (length == ccm->length_input); if (length != ccm->length_input) { return; } + ccm_encode_ctr(&ctr, ccm, 1); + cryptonite_aes_encrypt_ctr(output, key, &ctr, input, length); + for (;length >= 16; input += 16, length -= 16) { block128_copy(&tmp, (block128*)input); ccm_cbcmac_add(ccm, key, &tmp); @@ -943,12 +932,38 @@ void cryptonite_aes_generic_ccm_encrypt(uint8_t *output, aes_ccm *ccm, aes_key * block128_copy_bytes(&tmp, input, length); ccm_cbcmac_add(ccm, key, &tmp); } - block128_copy((block128*)output, &ccm->iv); } void cryptonite_aes_generic_ccm_decrypt(uint8_t *output, aes_ccm *ccm, aes_key *key, uint8_t *input, uint32_t length) { - cryptonite_aes_generic_ccm_encrypt(output, ccm, key, input, length); + block128 tmp, ctr; + + /* when aad is absent, reset b0 block */ + if (ccm->length_aad == 0) { + ccm_encode_b0(&ccm->b0, ccm, 0); /* assume aad is present */ + cryptonite_aes_encrypt_block(&ccm->xi, key, &ccm->b0); + block128_copy(&ccm->header_cbcmac, &ccm->xi); + } + + assert (length == ccm->length_input); + if (length != ccm->length_input) { + return; + } + + ccm_encode_ctr(&ctr, ccm, 1); + cryptonite_aes_encrypt_ctr(output, key, &ctr, input, length); + block128_copy(&ccm->xi, &ccm->header_cbcmac); + input = output; + + for (;length >= 16; input += 16, length -= 16) { + block128_copy(&tmp, (block128*)input); + ccm_cbcmac_add(ccm, key, &tmp); + } + if (length > 0) { + block128_zero(&tmp); + block128_copy_bytes(&tmp, input, length); + ccm_cbcmac_add(ccm, key, &tmp); + } } void cryptonite_aes_generic_ocb_encrypt(uint8_t *output, aes_ocb *ocb, aes_key *key, uint8_t *input, uint32_t length) diff --git a/cbits/cryptonite_aes.h b/cbits/cryptonite_aes.h index 70fbd47..0838a03 100644 --- a/cbits/cryptonite_aes.h +++ b/cbits/cryptonite_aes.h @@ -55,15 +55,14 @@ typedef struct { uint64_t length_input; } aes_gcm; -/* size = 544 */ +/* size = 80 */ typedef struct { - aes_block iv; /* iv with counter = 0 block */ - aes_block xi; /* X_i: cbc mac */ - aes_block b0; /* block b0 */ + aes_block xi; + aes_block header_cbcmac; + aes_block b0; aes_block nonce; - aes_key aad_key; - uint64_t length_aad; - uint64_t length_input; + unsigned length_aad; + unsigned length_input; int length_M; int length_L; } aes_ccm; @@ -110,8 +109,8 @@ void cryptonite_aes_ocb_encrypt(uint8_t *output, aes_ocb *ocb, aes_key *key, uin void cryptonite_aes_ocb_decrypt(uint8_t *output, aes_ocb *ocb, aes_key *key, uint8_t *input, uint32_t length); void cryptonite_aes_ocb_finish(uint8_t *tag, aes_ocb *ocb, aes_key *key); -void cryptonite_aes_ccm_init(aes_ccm *ccm, aes_key *key, uint8_t *nonce, uint32_t len, uint64_t msg_size, int m, int l); -void cryptonite_aes_ccm_aad(aes_ccm *ccm, uint8_t *input, uint32_t length); +void cryptonite_aes_ccm_init(aes_ccm *ccm, aes_key *key, uint8_t *nonce, uint32_t len, uint32_t msg_size, int m, int l); +void cryptonite_aes_ccm_aad(aes_ccm *ccm, aes_key *key, uint8_t *input, uint32_t length); void cryptonite_aes_ccm_encrypt(uint8_t *output, aes_ccm *ccm, aes_key *key, uint8_t *input, uint32_t length); void cryptonite_aes_ccm_decrypt(uint8_t *output, aes_ccm *ccm, aes_key *key, uint8_t *input, uint32_t length); void cryptonite_aes_ccm_finish(uint8_t *tag, aes_ccm *ccm, aes_key *key); From fefe5d75e3eb9c736837a158d158820b00cd9ce8 Mon Sep 17 00:00:00 2001 From: Baojun Wang Date: Thu, 18 Jan 2018 11:40:38 -0800 Subject: [PATCH 04/15] flavor condition checks instead of asserts --- cbits/cryptonite_aes.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/cbits/cryptonite_aes.c b/cbits/cryptonite_aes.c index 1888566..3af46d6 100644 --- a/cbits/cryptonite_aes.c +++ b/cbits/cryptonite_aes.c @@ -30,7 +30,6 @@ #include #include -#include #include #include @@ -530,7 +529,8 @@ void cryptonite_aes_ccm_aad(aes_ccm *ccm, aes_key *key, uint8_t *input, uint32_t { block128 tmp; - assert (ccm->length_aad == 0); + if (ccm->length_aad == 0) return; + ccm->length_aad = length; int len_len; @@ -915,7 +915,6 @@ void cryptonite_aes_generic_ccm_encrypt(uint8_t *output, aes_ccm *ccm, aes_key * block128_copy(&ccm->header_cbcmac, &ccm->xi); } - assert (length == ccm->length_input); if (length != ccm->length_input) { return; } @@ -938,6 +937,10 @@ void cryptonite_aes_generic_ccm_decrypt(uint8_t *output, aes_ccm *ccm, aes_key * { block128 tmp, ctr; + if (length != ccm->length_input) { + return; + } + /* when aad is absent, reset b0 block */ if (ccm->length_aad == 0) { ccm_encode_b0(&ccm->b0, ccm, 0); /* assume aad is present */ @@ -945,11 +948,6 @@ void cryptonite_aes_generic_ccm_decrypt(uint8_t *output, aes_ccm *ccm, aes_key * block128_copy(&ccm->header_cbcmac, &ccm->xi); } - assert (length == ccm->length_input); - if (length != ccm->length_input) { - return; - } - ccm_encode_ctr(&ctr, ccm, 1); cryptonite_aes_encrypt_ctr(output, key, &ctr, input, length); block128_copy(&ccm->xi, &ccm->header_cbcmac); From 035693240d06c7b2000b4e3d065943f36a245838 Mon Sep 17 00:00:00 2001 From: Baojun Wang Date: Thu, 18 Jan 2018 18:04:21 -0800 Subject: [PATCH 05/15] fix wrong condition check in cryptonite_aes_ccm_aad --- cbits/cryptonite_aes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cbits/cryptonite_aes.c b/cbits/cryptonite_aes.c index 3af46d6..58963d9 100644 --- a/cbits/cryptonite_aes.c +++ b/cbits/cryptonite_aes.c @@ -529,7 +529,7 @@ void cryptonite_aes_ccm_aad(aes_ccm *ccm, aes_key *key, uint8_t *input, uint32_t { block128 tmp; - if (ccm->length_aad == 0) return; + if (ccm->length_aad != 0) return; ccm->length_aad = length; int len_len; From e01ef4386e9e3044da8e64feea4bf90c25ab5474 Mon Sep 17 00:00:00 2001 From: Baojun Wang Date: Fri, 19 Jan 2018 10:03:02 -0800 Subject: [PATCH 06/15] Add AESCCM test vectors for testing --- cbits/cryptonite_aes.c | 6 +++--- cbits/cryptonite_aes.h | 8 ++++---- cryptonite.cabal | 1 + tests/BlockCipher.hs | 22 +++++++++++++--------- tests/KAT_AES.hs | 22 ++++++++++++++++++++-- 5 files changed, 41 insertions(+), 18 deletions(-) diff --git a/cbits/cryptonite_aes.c b/cbits/cryptonite_aes.c index 58963d9..0cf55b0 100644 --- a/cbits/cryptonite_aes.c +++ b/cbits/cryptonite_aes.c @@ -460,13 +460,13 @@ static void ccm_encode_b0(block128* output, aes_ccm* ccm, int has_adata) } /* encode adata length */ -static int ccm_encode_la(block128* output, unsigned la) +static int ccm_encode_la(block128* output, uint32_t la) { if (la < ( (1 << 16) - (1 << 8)) ) { output->b[0] = (la >> 8) & 0xff; output->b[1] = la & 0xff; return 2; - } else if (la < (1ull << 32)) { + } else { output->b[0] = 0xff; output->b[1] = 0xfe; output->b[2] = (la >> 24) & 0xff; @@ -504,7 +504,7 @@ void cryptonite_aes_ccm_init(aes_ccm *ccm, aes_key *key, uint8_t *nonce, uint32_ if (m != 4 && m != 6 && m != 8 && m != 10 && m != 12 && m != 14 && m != 16) return; - if (nonce_len != 15 - l) { + if (nonce_len > 15 - l) { nonce_len = 15 - l; } diff --git a/cbits/cryptonite_aes.h b/cbits/cryptonite_aes.h index 0838a03..9ac20b3 100644 --- a/cbits/cryptonite_aes.h +++ b/cbits/cryptonite_aes.h @@ -61,10 +61,10 @@ typedef struct { aes_block header_cbcmac; aes_block b0; aes_block nonce; - unsigned length_aad; - unsigned length_input; - int length_M; - int length_L; + uint32_t length_aad; + uint32_t length_input; + uint32_t length_M; + uint32_t length_L; } aes_ccm; typedef struct { diff --git a/cryptonite.cabal b/cryptonite.cabal index b7c2a51..233fc4e 100644 --- a/cryptonite.cabal +++ b/cryptonite.cabal @@ -377,6 +377,7 @@ Test-Suite test-cryptonite KAT_AES.KATCBC KAT_AES.KATECB KAT_AES.KATGCM + KAT_AES.KATCCM KAT_AES.KATOCB3 KAT_AES.KATXTS KAT_AES diff --git a/tests/BlockCipher.hs b/tests/BlockCipher.hs index 988c053..44b571b 100644 --- a/tests/BlockCipher.hs +++ b/tests/BlockCipher.hs @@ -161,7 +161,7 @@ testKATs kats cipher = testGroup "KAT" ++ maybeGroup makeCFBTest "CFB" (kat_CFB kats) ++ maybeGroup makeCTRTest "CTR" (kat_CTR kats) -- ++ maybeGroup makeXTSTest "XTS" (kat_XTS kats) - -- ++ maybeGroup makeAEADTest "AEAD" (kat_AEAD kats) + ++ maybeGroup makeAEADTest "AEAD" (kat_AEAD kats) ) where makeECBTest i d = [ testCase ("E" ++ i) (ecbEncrypt ctx (ecbPlaintext d) @?= ecbCiphertext d) @@ -191,25 +191,24 @@ testKATs kats cipher = testGroup "KAT" [ testCase ("E" ++ i) (xtsEncrypt ctx iv 0 (xtsPlaintext d) @?= xtsCiphertext d) , testCase ("D" ++ i) (xtsDecrypt ctx iv 0 (xtsCiphertext d) @?= xtsPlaintext d) ] - where ctx1 = cipherInit (cipherMakeKey cipher $ xtsKey1 d) - ctx2 = cipherInit (cipherMakeKey cipher $ xtsKey2 d) + where ctx1 = cipherInitNoErr (cipherMakeKey cipher $ xtsKey1 d) + ctx2 = cipherInitNoErr (cipherMakeKey cipher $ xtsKey2 d) ctx = (ctx1, ctx2) iv = cipherMakeIV cipher $ xtsIV d +-} makeAEADTest i d = - [ testCase ("AE" ++ i) (etag @?= aeadTag d) - , testCase ("AD" ++ i) (dtag @?= aeadTag d) + [ testCase ("AE" ++ i) (etag @?= AuthTag (B.convert (aeadTag d))) + , testCase ("AD" ++ i) (dtag @?= AuthTag (B.convert (aeadTag d))) , testCase ("E" ++ i) (ebs @?= aeadCiphertext d) , testCase ("D" ++ i) (dbs @?= aeadPlaintext d) ] - where ctx = cipherInit (cipherMakeKey cipher $ aeadKey d) - aead = maybe (error $ "cipher doesn't support aead mode: " ++ show (aeadMode d)) id - $ aeadInit (aeadMode d) ctx (aeadIV d) + where ctx = cipherInitNoErr (cipherMakeKey cipher $ aeadKey d) + aead = aeadInitNoErr (aeadMode d) ctx (aeadIV d) aeadHeaded = aeadAppendHeader aead (aeadHeader d) (ebs,aeadEFinal) = aeadEncrypt aeadHeaded (aeadPlaintext d) (dbs,aeadDFinal) = aeadDecrypt aeadHeaded (aeadCiphertext d) etag = aeadFinalize aeadEFinal (aeadTaglen d) dtag = aeadFinalize aeadDFinal (aeadTaglen d) --} cipherInitNoErr :: BlockCipher c => Key c -> c cipherInitNoErr (Key k) = @@ -217,6 +216,11 @@ testKATs kats cipher = testGroup "KAT" CryptoPassed a -> a CryptoFailed e -> error (show e) + aeadInitNoErr :: (ByteArrayAccess iv, BlockCipher cipher) => AEADMode -> cipher -> iv -> AEAD cipher + aeadInitNoErr mode ct iv = + case aeadInit mode ct iv of + CryptoPassed a -> a + CryptoFailed _ -> error $ "cipher does'nt support aead mode: " ++ show mode ------------------------------------------------------------------------ -- Properties ------------------------------------------------------------------------ diff --git a/tests/KAT_AES.hs b/tests/KAT_AES.hs index e9a06ab..a6c8182 100644 --- a/tests/KAT_AES.hs +++ b/tests/KAT_AES.hs @@ -3,13 +3,15 @@ module KAT_AES (tests) where import Imports import BlockCipher +import Data.Maybe import Crypto.Cipher.Types import qualified Crypto.Cipher.AES as AES - +import qualified Data.ByteString as B import qualified KAT_AES.KATECB as KATECB import qualified KAT_AES.KATCBC as KATCBC import qualified KAT_AES.KATXTS as KATXTS import qualified KAT_AES.KATGCM as KATGCM +import qualified KAT_AES.KATCCM as KATCCM import qualified KAT_AES.KATOCB3 as KATOCB3 {- @@ -37,6 +39,21 @@ toKatAEAD mode (k,iv,h,p,c,taglen,tag) = toKatGCM = toKatAEAD AEAD_GCM toKatOCB = toKatAEAD AEAD_OCB +toKatCCM (k,iv,h,i,o,m) = + KAT_AEAD { aeadMode = AEAD_CCM (B.length i) (ccmMVal m) CCM_L2 + , aeadKey = k + , aeadIV = iv + , aeadHeader = h + , aeadPlaintext = i + , aeadCiphertext = ct + , aeadTaglen = m + , aeadTag = at + } + where ccmMVal x = fromMaybe CCM_M16 (lookup x [ (4, CCM_M4), (6, CCM_M6), (8, CCM_M8), (10, CCM_M10), + (12, CCM_M12), (14, CCM_M14), (16, CCM_M16) ]) + ctWithTag = B.drop (B.length h) o + (ct, at) = B.splitAt (B.length ctWithTag - m) ctWithTag + kats128 = defaultKATs { kat_ECB = map toKatECB KATECB.vectors_aes128_enc , kat_CBC = map toKatCBC KATCBC.vectors_aes128_enc @@ -48,7 +65,8 @@ kats128 = defaultKATs ] , kat_XTS = map toKatXTS KATXTS.vectors_aes128_enc , kat_AEAD = map toKatGCM KATGCM.vectors_aes128_enc ++ - map toKatOCB KATOCB3.vectors_aes128_enc + map toKatOCB KATOCB3.vectors_aes128_enc ++ + map toKatCCM KATCCM.vectors_aes128_enc } kats192 = defaultKATs From 6fef094e909824699417febf8c7ea9d653a380f5 Mon Sep 17 00:00:00 2001 From: Baojun Wang Date: Fri, 19 Jan 2018 10:38:57 -0800 Subject: [PATCH 07/15] Add KATCCM test file --- tests/KAT_AES/KATCCM.hs | 164 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 tests/KAT_AES/KATCCM.hs diff --git a/tests/KAT_AES/KATCCM.hs b/tests/KAT_AES/KATCCM.hs new file mode 100644 index 0000000..fc1b173 --- /dev/null +++ b/tests/KAT_AES/KATCCM.hs @@ -0,0 +1,164 @@ +{-# LANGUAGE OverloadedStrings #-} +module KAT_AES.KATCCM where + +import qualified Data.ByteString as B +import Data.ByteString.Char8 () +import Data.ByteString.Builder + +import Numeric +import Data.List (zipWith4) +import Data.Semigroup +import System.IO(stdout) +import Data.Char (ord) +import Data.Bits +import Data.Word + +-- (key, iv, header, in, out+atag, taglen) +type KATCCM = (B.ByteString, B.ByteString, B.ByteString, B.ByteString, B.ByteString, Int) + +vectors_aes128_enc :: [KATCCM] +vectors_aes128_enc = [ + ( {- key = -} "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + , {- iv = -} "\x00\x00\x00\x03\x02\x01\x00\xa0\xa1\xa2\xa3\xa4\xa5" + , {- hdr = -} "\x00\x01\x02\x03\x04\x05\x06\x07" + , {- in = -} "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e" + , {- out = -} "\x00\x01\x02\x03\x04\x05\x06\x07\x58\x8c\x97\x9a\x61\xc6\x63\xd2\xf0\x66\xd0\xc2\xc0\xf9\x89\x80\x6d\x5f\x6b\x61\xda\xc3\x84\x17\xe8\xd1\x2c\xfd\xf9\x26\xe0" + , {- M = -} 8) + , ( {- key = -} "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + , {- iv = -} "\x00\x00\x00\x04\x03\x02\x01\xa0\xa1\xa2\xa3\xa4\xa5" + , {- hdr = -} "\x00\x01\x02\x03\x04\x05\x06\x07" + , {- in = -} "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + , {- out = -} "\x00\x01\x02\x03\x04\x05\x06\x07\x72\xc9\x1a\x36\xe1\x35\xf8\xcf\x29\x1c\xa8\x94\x08\x5c\x87\xe3\xcc\x15\xc4\x39\xc9\xe4\x3a\x3b\xa0\x91\xd5\x6e\x10\x40\x09\x16" + , {- M = -} 8) + , ( {- key = -} "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + , {- iv = -} "\x00\x00\x00\x05\x04\x03\x02\xa0\xa1\xa2\xa3\xa4\xa5" + , {- hdr = -} "\x00\x01\x02\x03\x04\x05\x06\x07" + , {- in = -} "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20" + , {- out = -} "\x00\x01\x02\x03\x04\x05\x06\x07\x51\xb1\xe5\xf4\x4a\x19\x7d\x1d\xa4\x6b\x0f\x8e\x2d\x28\x2a\xe8\x71\xe8\x38\xbb\x64\xda\x85\x96\x57\x4a\xda\xa7\x6f\xbd\x9f\xb0\xc5" + , {- M = -} 8) + , ( {- key = -} "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + , {- iv = -} "\x00\x00\x00\x06\x05\x04\x03\xa0\xa1\xa2\xa3\xa4\xa5" + , {- hdr = -} "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b" + , {- in = -} "\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e" + , {- out = -} "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\xa2\x8c\x68\x65\x93\x9a\x9a\x79\xfa\xaa\x5c\x4c\x2a\x9d\x4a\x91\xcd\xac\x8c\x96\xc8\x61\xb9\xc9\xe6\x1e\xf1" + , {- M = -} 8) + , ( {- key = -} "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + , {- iv = -} "\x00\x00\x00\x07\x06\x05\x04\xa0\xa1\xa2\xa3\xa4\xa5" + , {- hdr = -} "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b" + , {- in = -} "\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + , {- out = -} "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\xdc\xf1\xfb\x7b\x5d\x9e\x23\xfb\x9d\x4e\x13\x12\x53\x65\x8a\xd8\x6e\xbd\xca\x3e\x51\xe8\x3f\x07\x7d\x9c\x2d\x93" + , {- M = -} 8) + , ( {- key = -} "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + , {- iv = -} "\x00\x00\x00\x08\x07\x06\x05\xa0\xa1\xa2\xa3\xa4\xa5" + , {- hdr = -} "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b" + , {- in = -} "\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20" + , {- out = -} "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x6f\xc1\xb0\x11\xf0\x06\x56\x8b\x51\x71\xa4\x2d\x95\x3d\x46\x9b\x25\x70\xa4\xbd\x87\x40\x5a\x04\x43\xac\x91\xcb\x94" + , {- M = -} 8) + , ( {- key = -} "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + , {- iv = -} "\x00\x00\x00\x09\x08\x07\x06\xa0\xa1\xa2\xa3\xa4\xa5" + , {- hdr = -} "\x00\x01\x02\x03\x04\x05\x06\x07" + , {- in = -} "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e" + , {- out = -} "\x00\x01\x02\x03\x04\x05\x06\x07\x01\x35\xd1\xb2\xc9\x5f\x41\xd5\xd1\xd4\xfe\xc1\x85\xd1\x66\xb8\x09\x4e\x99\x9d\xfe\xd9\x6c\x04\x8c\x56\x60\x2c\x97\xac\xbb\x74\x90" + , {- M = -} 10) + , ( {- key = -} "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + , {- iv = -} "\x00\x00\x00\x0a\x09\x08\x07\xa0\xa1\xa2\xa3\xa4\xa5" + , {- hdr = -} "\x00\x01\x02\x03\x04\x05\x06\x07" + , {- in = -} "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + , {- out = -} "\x00\x01\x02\x03\x04\x05\x06\x07\x7b\x75\x39\x9a\xc0\x83\x1d\xd2\xf0\xbb\xd7\x58\x79\xa2\xfd\x8f\x6c\xae\x6b\x6c\xd9\xb7\xdb\x24\xc1\x7b\x44\x33\xf4\x34\x96\x3f\x34\xb4" + , {- M = -} 10) + , ( {- key = -} "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + , {- iv = -} "\x00\x00\x00\x0b\x0a\x09\x08\xa0\xa1\xa2\xa3\xa4\xa5" + , {- hdr = -} "\x00\x01\x02\x03\x04\x05\x06\x07" + , {- in = -} "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20" + , {- out = -} "\x00\x01\x02\x03\x04\x05\x06\x07\x82\x53\x1a\x60\xcc\x24\x94\x5a\x4b\x82\x79\x18\x1a\xb5\xc8\x4d\xf2\x1c\xe7\xf9\xb7\x3f\x42\xe1\x97\xea\x9c\x07\xe5\x6b\x5e\xb1\x7e\x5f\x4e" + , {- M = -} 10) + , ( {- key = -} "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + , {- iv = -} "\x00\x00\x00\x0c\x0b\x0a\x09\xa0\xa1\xa2\xa3\xa4\xa5" + , {- hdr = -} "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b" + , {- in = -} "\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e" + , {- out = -} "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x07\x34\x25\x94\x15\x77\x85\x15\x2b\x07\x40\x98\x33\x0a\xbb\x14\x1b\x94\x7b\x56\x6a\xa9\x40\x6b\x4d\x99\x99\x88\xdd" + , {- M = -} 10) + , ( {- key = -} "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + , {- iv = -} "\x00\x00\x00\x0d\x0c\x0b\x0a\xa0\xa1\xa2\xa3\xa4\xa5" + , {- hdr = -} "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b" + , {- in = -} "\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + , {- out = -} "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x67\x6b\xb2\x03\x80\xb0\xe3\x01\xe8\xab\x79\x59\x0a\x39\x6d\xa7\x8b\x83\x49\x34\xf5\x3a\xa2\xe9\x10\x7a\x8b\x6c\x02\x2c" + , {- M = -} 10) + , ( {- key = -} "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + , {- iv = -} "\x00\x00\x00\x0e\x0d\x0c\x0b\xa0\xa1\xa2\xa3\xa4\xa5" + , {- hdr = -} "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b" + , {- in = -} "\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20" + , {- out = -} "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\xc0\xff\xa0\xd6\xf0\x5b\xdb\x67\xf2\x4d\x43\xa4\x33\x8d\x2a\xa4\xbe\xd7\xb2\x0e\x43\xcd\x1a\xa3\x16\x62\xe7\xad\x65\xd6\xdb" + , {- M = -} 10) + , ( {- key = -} "\xd7\x82\x8d\x13\xb2\xb0\xbd\xc3\x25\xa7\x62\x36\xdf\x93\xcc\x6b" + , {- iv = -} "\x00\x41\x2b\x4e\xa9\xcd\xbe\x3c\x96\x96\x76\x6c\xfa" + , {- hdr = -} "\x0b\xe1\xa8\x8b\xac\xe0\x18\xb1" + , {- in = -} "\x08\xe8\xcf\x97\xd8\x20\xea\x25\x84\x60\xe9\x6a\xd9\xcf\x52\x89\x05\x4d\x89\x5c\xea\xc4\x7c" + , {- out = -} "\x0b\xe1\xa8\x8b\xac\xe0\x18\xb1\x4c\xb9\x7f\x86\xa2\xa4\x68\x9a\x87\x79\x47\xab\x80\x91\xef\x53\x86\xa6\xff\xbd\xd0\x80\xf8\xe7\x8c\xf7\xcb\x0c\xdd\xd7\xb3" + , {- M = -} 8) + , ( {- key = -} "\xd7\x82\x8d\x13\xb2\xb0\xbd\xc3\x25\xa7\x62\x36\xdf\x93\xcc\x6b" + , {- iv = -} "\x00\x33\x56\x8e\xf7\xb2\x63\x3c\x96\x96\x76\x6c\xfa" + , {- hdr = -} "\x63\x01\x8f\x76\xdc\x8a\x1b\xcb" + , {- in = -} "\x90\x20\xea\x6f\x91\xbd\xd8\x5a\xfa\x00\x39\xba\x4b\xaf\xf9\xbf\xb7\x9c\x70\x28\x94\x9c\xd0\xec" + , {- out = -} "\x63\x01\x8f\x76\xdc\x8a\x1b\xcb\x4c\xcb\x1e\x7c\xa9\x81\xbe\xfa\xa0\x72\x6c\x55\xd3\x78\x06\x12\x98\xc8\x5c\x92\x81\x4a\xbc\x33\xc5\x2e\xe8\x1d\x7d\x77\xc0\x8a" + , {- M = -} 8) + , ( {- key = -} "\xd7\x82\x8d\x13\xb2\xb0\xbd\xc3\x25\xa7\x62\x36\xdf\x93\xcc\x6b" + , {- iv = -} "\x00\x10\x3f\xe4\x13\x36\x71\x3c\x96\x96\x76\x6c\xfa" + , {- hdr = -} "\xaa\x6c\xfa\x36\xca\xe8\x6b\x40" + , {- in = -} "\xb9\x16\xe0\xea\xcc\x1c\x00\xd7\xdc\xec\x68\xec\x0b\x3b\xbb\x1a\x02\xde\x8a\x2d\x1a\xa3\x46\x13\x2e" + , {- out = -} "\xaa\x6c\xfa\x36\xca\xe8\x6b\x40\xb1\xd2\x3a\x22\x20\xdd\xc0\xac\x90\x0d\x9a\xa0\x3c\x61\xfc\xf4\xa5\x59\xa4\x41\x77\x67\x08\x97\x08\xa7\x76\x79\x6e\xdb\x72\x35\x06" + , {- M = -} 8) + , ( {- key = -} "\xd7\x82\x8d\x13\xb2\xb0\xbd\xc3\x25\xa7\x62\x36\xdf\x93\xcc\x6b" + , {- iv = -} "\x00\x76\x4c\x63\xb8\x05\x8e\x3c\x96\x96\x76\x6c\xfa" + , {- hdr = -} "\xd0\xd0\x73\x5c\x53\x1e\x1b\xec\xf0\x49\xc2\x44" + , {- in = -} "\x12\xda\xac\x56\x30\xef\xa5\x39\x6f\x77\x0c\xe1\xa6\x6b\x21\xf7\xb2\x10\x1c" + , {- out = -} "\xd0\xd0\x73\x5c\x53\x1e\x1b\xec\xf0\x49\xc2\x44\x14\xd2\x53\xc3\x96\x7b\x70\x60\x9b\x7c\xbb\x7c\x49\x91\x60\x28\x32\x45\x26\x9a\x6f\x49\x97\x5b\xca\xde\xaf" + , {- M = -} 8) + , ( {- key = -} "\xd7\x82\x8d\x13\xb2\xb0\xbd\xc3\x25\xa7\x62\x36\xdf\x93\xcc\x6b" + , {- iv = -} "\x00\xf8\xb6\x78\x09\x4e\x3b\x3c\x96\x96\x76\x6c\xfa" + , {- hdr = -} "\x77\xb6\x0f\x01\x1c\x03\xe1\x52\x58\x99\xbc\xae" + , {- in = -} "\xe8\x8b\x6a\x46\xc7\x8d\x63\xe5\x2e\xb8\xc5\x46\xef\xb5\xde\x6f\x75\xe9\xcc\x0d" + , {- out = -} "\x77\xb6\x0f\x01\x1c\x03\xe1\x52\x58\x99\xbc\xae\x55\x45\xff\x1a\x08\x5e\xe2\xef\xbf\x52\xb2\xe0\x4b\xee\x1e\x23\x36\xc7\x3e\x3f\x76\x2c\x0c\x77\x44\xfe\x7e\x3c" + , {- M = -} 8) + , ( {- key = -} "\xd7\x82\x8d\x13\xb2\xb0\xbd\xc3\x25\xa7\x62\x36\xdf\x93\xcc\x6b" + , {- iv = -} "\x00\xd5\x60\x91\x2d\x3f\x70\x3c\x96\x96\x76\x6c\xfa" + , {- hdr = -} "\xcd\x90\x44\xd2\xb7\x1f\xdb\x81\x20\xea\x60\xc0" + , {- in = -} "\x64\x35\xac\xba\xfb\x11\xa8\x2e\x2f\x07\x1d\x7c\xa4\xa5\xeb\xd9\x3a\x80\x3b\xa8\x7f" + , {- out = -} "\xcd\x90\x44\xd2\xb7\x1f\xdb\x81\x20\xea\x60\xc0\x00\x97\x69\xec\xab\xdf\x48\x62\x55\x94\xc5\x92\x51\xe6\x03\x57\x22\x67\x5e\x04\xc8\x47\x09\x9e\x5a\xe0\x70\x45\x51" + , {- M = -} 8) + , ( {- key = -} "\xd7\x82\x8d\x13\xb2\xb0\xbd\xc3\x25\xa7\x62\x36\xdf\x93\xcc\x6b" + , {- iv = -} "\x00\x42\xff\xf8\xf1\x95\x1c\x3c\x96\x96\x76\x6c\xfa" + , {- hdr = -} "\xd8\x5b\xc7\xe6\x9f\x94\x4f\xb8" + , {- in = -} "\x8a\x19\xb9\x50\xbc\xf7\x1a\x01\x8e\x5e\x67\x01\xc9\x17\x87\x65\x98\x09\xd6\x7d\xbe\xdd\x18" + , {- out = -} "\xd8\x5b\xc7\xe6\x9f\x94\x4f\xb8\xbc\x21\x8d\xaa\x94\x74\x27\xb6\xdb\x38\x6a\x99\xac\x1a\xef\x23\xad\xe0\xb5\x29\x39\xcb\x6a\x63\x7c\xf9\xbe\xc2\x40\x88\x97\xc6\xba" + , {- M = -} 10) + , ( {- key = -} "\xd7\x82\x8d\x13\xb2\xb0\xbd\xc3\x25\xa7\x62\x36\xdf\x93\xcc\x6b" + , {- iv = -} "\x00\x92\x0f\x40\xe5\x6c\xdc\x3c\x96\x96\x76\x6c\xfa" + , {- hdr = -} "\x74\xa0\xeb\xc9\x06\x9f\x5b\x37" + , {- in = -} "\x17\x61\x43\x3c\x37\xc5\xa3\x5f\xc1\xf3\x9f\x40\x63\x02\xeb\x90\x7c\x61\x63\xbe\x38\xc9\x84\x37" + , {- out = -} "\x74\xa0\xeb\xc9\x06\x9f\x5b\x37\x58\x10\xe6\xfd\x25\x87\x40\x22\xe8\x03\x61\xa4\x78\xe3\xe9\xcf\x48\x4a\xb0\x4f\x44\x7e\xff\xf6\xf0\xa4\x77\xcc\x2f\xc9\xbf\x54\x89\x44" + , {- M = -} 10) + , ( {- key = -} "\xd7\x82\x8d\x13\xb2\xb0\xbd\xc3\x25\xa7\x62\x36\xdf\x93\xcc\x6b" + , {- iv = -} "\x00\x27\xca\x0c\x71\x20\xbc\x3c\x96\x96\x76\x6c\xfa" + , {- hdr = -} "\x44\xa3\xaa\x3a\xae\x64\x75\xca" + , {- in = -} "\xa4\x34\xa8\xe5\x85\x00\xc6\xe4\x15\x30\x53\x88\x62\xd6\x86\xea\x9e\x81\x30\x1b\x5a\xe4\x22\x6b\xfa" + , {- out = -} "\x44\xa3\xaa\x3a\xae\x64\x75\xca\xf2\xbe\xed\x7b\xc5\x09\x8e\x83\xfe\xb5\xb3\x16\x08\xf8\xe2\x9c\x38\x81\x9a\x89\xc8\xe7\x76\xf1\x54\x4d\x41\x51\xa4\xed\x3a\x8b\x87\xb9\xce" + , {- M = -} 10) + , ( {- key = -} "\xd7\x82\x8d\x13\xb2\xb0\xbd\xc3\x25\xa7\x62\x36\xdf\x93\xcc\x6b" + , {- iv = -} "\x00\x5b\x8c\xcb\xcd\x9a\xf8\x3c\x96\x96\x76\x6c\xfa" + , {- hdr = -} "\xec\x46\xbb\x63\xb0\x25\x20\xc3\x3c\x49\xfd\x70" + , {- in = -} "\xb9\x6b\x49\xe2\x1d\x62\x17\x41\x63\x28\x75\xdb\x7f\x6c\x92\x43\xd2\xd7\xc2" + , {- out = -} "\xec\x46\xbb\x63\xb0\x25\x20\xc3\x3c\x49\xfd\x70\x31\xd7\x50\xa0\x9d\xa3\xed\x7f\xdd\xd4\x9a\x20\x32\xaa\xbf\x17\xec\x8e\xbf\x7d\x22\xc8\x08\x8c\x66\x6b\xe5\xc1\x97" + , {- M = -} 10) + , ( {- key = -} "\xd7\x82\x8d\x13\xb2\xb0\xbd\xc3\x25\xa7\x62\x36\xdf\x93\xcc\x6b" + , {- iv = -} "\x00\x3e\xbe\x94\x04\x4b\x9a\x3c\x96\x96\x76\x6c\xfa" + , {- hdr = -} "\x47\xa6\x5a\xc7\x8b\x3d\x59\x42\x27\xe8\x5e\x71" + , {- in = -} "\xe2\xfc\xfb\xb8\x80\x44\x2c\x73\x1b\xf9\x51\x67\xc8\xff\xd7\x89\x5e\x33\x70\x76" + , {- out = -} "\x47\xa6\x5a\xc7\x8b\x3d\x59\x42\x27\xe8\x5e\x71\xe8\x82\xf1\xdb\xd3\x8c\xe3\xed\xa7\xc2\x3f\x04\xdd\x65\x07\x1e\xb4\x13\x42\xac\xdf\x7e\x00\xdc\xce\xc7\xae\x52\x98\x7d" + , {- M = -} 10) + , ( {- key = -} "\xd7\x82\x8d\x13\xb2\xb0\xbd\xc3\x25\xa7\x62\x36\xdf\x93\xcc\x6b" + , {- iv = -} "\x00\x8d\x49\x3b\x30\xae\x8b\x3c\x96\x96\x76\x6c\xfa" + , {- hdr = -} "\x6e\x37\xa6\xef\x54\x6d\x95\x5d\x34\xab\x60\x59" + , {- in = -} "\xab\xf2\x1c\x0b\x02\xfe\xb8\x8f\x85\x6d\xf4\xa3\x73\x81\xbc\xe3\xcc\x12\x85\x17\xd4" + , {- out = -} "\x6e\x37\xa6\xef\x54\x6d\x95\x5d\x34\xab\x60\x59\xf3\x29\x05\xb8\x8a\x64\x1b\x04\xb9\xc9\xff\xb5\x8c\xc3\x90\x90\x0f\x3d\xa1\x2a\xb1\x6d\xce\x9e\x82\xef\xa1\x6d\xa6\x20\x59" + , {- M = -} 10) ] From ccc7c3e7a61b9b7617ce267c79bf36e5e4402b4b Mon Sep 17 00:00:00 2001 From: Baojun Wang Date: Fri, 19 Jan 2018 11:19:45 -0800 Subject: [PATCH 08/15] kill unused imports --- tests/KAT_AES/KATCCM.hs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tests/KAT_AES/KATCCM.hs b/tests/KAT_AES/KATCCM.hs index fc1b173..e9b2a1a 100644 --- a/tests/KAT_AES/KATCCM.hs +++ b/tests/KAT_AES/KATCCM.hs @@ -2,16 +2,6 @@ module KAT_AES.KATCCM where import qualified Data.ByteString as B -import Data.ByteString.Char8 () -import Data.ByteString.Builder - -import Numeric -import Data.List (zipWith4) -import Data.Semigroup -import System.IO(stdout) -import Data.Char (ord) -import Data.Bits -import Data.Word -- (key, iv, header, in, out+atag, taglen) type KATCCM = (B.ByteString, B.ByteString, B.ByteString, B.ByteString, B.ByteString, Int) From d5f8348a4bc6ca787d62f11a792f36fac291e3ab Mon Sep 17 00:00:00 2001 From: Baojun Wang Date: Mon, 22 Jan 2018 12:23:58 -0800 Subject: [PATCH 09/15] use nonce_len for memcpy --- cbits/cryptonite_aes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cbits/cryptonite_aes.c b/cbits/cryptonite_aes.c index 0cf55b0..7e0b723 100644 --- a/cbits/cryptonite_aes.c +++ b/cbits/cryptonite_aes.c @@ -516,7 +516,7 @@ void cryptonite_aes_ccm_init(aes_ccm *ccm, aes_key *key, uint8_t *nonce, uint32_ ccm->length_M = m; ccm->length_input = input_size; - memcpy(&ccm->nonce.b[1], nonce, 15 - l); + memcpy(&ccm->nonce.b[1], nonce, nonce_len); ccm_encode_b0(&ccm->b0, ccm, 1); /* assume aad is present */ cryptonite_aes_encrypt_block(&ccm->xi, key, &ccm->b0); From f6d9fb0cf1980e71a5787e57b1fa02591d05fce1 Mon Sep 17 00:00:00 2001 From: Baojun Wang Date: Mon, 22 Jan 2018 12:24:22 -0800 Subject: [PATCH 10/15] aeadInit (ccm) returns CryptoError_IvSizeInvalid when iv size is wrong --- Crypto/Cipher/AES.hs | 9 ++++++++- tests/BlockCipher.hs | 12 ++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Crypto/Cipher/AES.hs b/Crypto/Cipher/AES.hs index 5ce10c4..5e2c76c 100644 --- a/Crypto/Cipher/AES.hs +++ b/Crypto/Cipher/AES.hs @@ -48,6 +48,13 @@ instance Cipher AES256 where cipherKeySize _ = KeySizeFixed 32 cipherInit k = AES256 <$> (initAES =<< validateKeySize (undefined :: AES256) k) +aeadInitCcm :: ByteArrayAccess iv => Int -> CCM_M -> CCM_L -> AES -> iv -> CryptoFailable (AEAD cihper) +aeadInitCcm n m l aes iv = if BA.length iv /= 15 - ln then CryptoFailed CryptoError_IvSizeInvalid else CryptoPassed $ AEAD (ccmMode aes) (ccmInit aes iv n m l) + where + ln = case l of + CCM_L2 -> 2 + CCM_L3 -> 3 + CCM_L4 -> 4 #define INSTANCE_BLOCKCIPHER(CSTR) \ instance BlockCipher CSTR where \ @@ -59,7 +66,7 @@ instance BlockCipher CSTR where \ ; ctrCombine (CSTR aes) (IV iv) = encryptCTR aes (IV iv) \ ; aeadInit AEAD_GCM (CSTR aes) iv = CryptoPassed $ AEAD (gcmMode aes) (gcmInit aes iv) \ ; aeadInit AEAD_OCB (CSTR aes) iv = CryptoPassed $ AEAD (ocbMode aes) (ocbInit aes iv) \ - ; aeadInit (AEAD_CCM n m l) (CSTR aes) iv = CryptoPassed $ AEAD (ccmMode aes) (ccmInit aes iv n m l) \ + ; aeadInit (AEAD_CCM n m l) (CSTR aes) iv = aeadInitCcm n m l aes iv \ ; aeadInit _ _ _ = CryptoFailed CryptoError_AEADModeNotSupported \ }; \ instance BlockCipher128 CSTR where \ diff --git a/tests/BlockCipher.hs b/tests/BlockCipher.hs index 44b571b..6e8f8af 100644 --- a/tests/BlockCipher.hs +++ b/tests/BlockCipher.hs @@ -17,7 +17,7 @@ import Data.Maybe import Crypto.Error import Crypto.Cipher.Types import Data.ByteArray as B hiding (pack, null, length) -import qualified Data.ByteString as B hiding (all) +import qualified Data.ByteString as B hiding (all, take, replicate) ------------------------------------------------------------------------ -- KAT @@ -402,7 +402,7 @@ testBlockCipherAEAD cipher = toTests :: BlockCipher a => a -> (AEADMode -> AEADUnit a -> Bool) toTests _ = testProperty_AEAD testProperty_AEAD mode (AEADUnit key testIV (unPlaintext -> aad) (unPlaintext -> plaintext)) = withCtx key $ \ctx -> - case aeadInit mode' ctx testIV of + case aeadInit mode' ctx iv' of CryptoPassed iniAead -> let aead = aeadAppendHeader iniAead aad (eText, aeadE) = aeadEncrypt aead plaintext @@ -413,10 +413,10 @@ testBlockCipherAEAD cipher = CryptoFailed err | err == CryptoError_AEADModeNotSupported -> True | otherwise -> error ("testProperty_AEAD: " ++ show err) - where mode' = updateCcmInputSize mode (B.length plaintext) - updateCcmInputSize aeadmode k = case aeadmode of - AEAD_CCM _ m l -> AEAD_CCM k m l - aeadOther -> aeadOther + where (mode', iv') = updateCcmInputSize mode (B.length plaintext) testIV + updateCcmInputSize aeadmode k iv = case aeadmode of + AEAD_CCM _ m l -> (AEAD_CCM k m l, B.take 13 (iv <> (B.replicate 15 0))) + aeadOther -> (aeadOther, iv) withCtx :: Cipher c => Key c -> (c -> a) -> a withCtx (Key key) f = From 1e57f41e1d4e47c654412f07f69ee946bcabfcf9 Mon Sep 17 00:00:00 2001 From: Baojun Wang Date: Thu, 1 Feb 2018 11:16:13 -0800 Subject: [PATCH 11/15] check AESCCM IV length in ccmInit instead of aeadInit --- Crypto/Cipher/AES.hs | 10 +--------- Crypto/Cipher/AES/Primitive.hs | 15 ++++++++------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/Crypto/Cipher/AES.hs b/Crypto/Cipher/AES.hs index 5e2c76c..61b81cf 100644 --- a/Crypto/Cipher/AES.hs +++ b/Crypto/Cipher/AES.hs @@ -48,14 +48,6 @@ instance Cipher AES256 where cipherKeySize _ = KeySizeFixed 32 cipherInit k = AES256 <$> (initAES =<< validateKeySize (undefined :: AES256) k) -aeadInitCcm :: ByteArrayAccess iv => Int -> CCM_M -> CCM_L -> AES -> iv -> CryptoFailable (AEAD cihper) -aeadInitCcm n m l aes iv = if BA.length iv /= 15 - ln then CryptoFailed CryptoError_IvSizeInvalid else CryptoPassed $ AEAD (ccmMode aes) (ccmInit aes iv n m l) - where - ln = case l of - CCM_L2 -> 2 - CCM_L3 -> 3 - CCM_L4 -> 4 - #define INSTANCE_BLOCKCIPHER(CSTR) \ instance BlockCipher CSTR where \ { blockSize _ = 16 \ @@ -66,7 +58,7 @@ instance BlockCipher CSTR where \ ; ctrCombine (CSTR aes) (IV iv) = encryptCTR aes (IV iv) \ ; aeadInit AEAD_GCM (CSTR aes) iv = CryptoPassed $ AEAD (gcmMode aes) (gcmInit aes iv) \ ; aeadInit AEAD_OCB (CSTR aes) iv = CryptoPassed $ AEAD (ocbMode aes) (ocbInit aes iv) \ - ; aeadInit (AEAD_CCM n m l) (CSTR aes) iv = aeadInitCcm n m l aes iv \ + ; aeadInit (AEAD_CCM n m l) (CSTR aes) iv = AEAD (ccmMode aes) <$> ccmInit aes iv n m l \ ; aeadInit _ _ _ = CryptoFailed CryptoError_AEADModeNotSupported \ }; \ instance BlockCipher128 CSTR where \ diff --git a/Crypto/Cipher/AES/Primitive.hs b/Crypto/Cipher/AES/Primitive.hs index 2e4f2ac..5169366 100644 --- a/Crypto/Cipher/AES/Primitive.hs +++ b/Crypto/Cipher/AES/Primitive.hs @@ -77,7 +77,7 @@ instance BlockCipher AES where ctrCombine = encryptCTR aeadInit AEAD_GCM aes iv = CryptoPassed $ AEAD (gcmMode aes) (gcmInit aes iv) aeadInit AEAD_OCB aes iv = CryptoPassed $ AEAD (ocbMode aes) (ocbInit aes iv) - aeadInit (AEAD_CCM n m l) aes iv = CryptoPassed $ AEAD (ccmMode aes) (ccmInit aes iv n m l) + aeadInit (AEAD_CCM n m l) aes iv = AEAD (ccmMode aes) <$> ccmInit aes iv n m l aeadInit _ _ _ = CryptoFailed CryptoError_AEADModeNotSupported instance BlockCipher128 AES where xtsEncrypt = encryptXTS @@ -492,12 +492,13 @@ ccmGetL l = case l of -- | initialize a ccm context {-# NOINLINE ccmInit #-} -ccmInit :: ByteArrayAccess iv => AES -> iv -> Int -> CCM_M -> CCM_L -> AESCCM -ccmInit ctx iv n m l = unsafeDoIO $ do - sm <- B.alloc sizeCCM $ \ccmStPtr -> - withKeyAndIV ctx iv $ \k v -> - c_aes_ccm_init (castPtr ccmStPtr) k v (fromIntegral $ B.length iv) (fromIntegral n) (fromIntegral (ccmGetM m)) (fromIntegral (ccmGetL l)) - return $ AESCCM sm +ccmInit :: ByteArrayAccess iv => AES -> iv -> Int -> CCM_M -> CCM_L -> CryptoFailable AESCCM +ccmInit ctx iv n m l = if 15 - ccmGetL l /= B.length iv then CryptoFailed CryptoError_IvSizeInvalid + else unsafeDoIO $ do + sm <- B.alloc sizeCCM $ \ccmStPtr -> + withKeyAndIV ctx iv $ \k v -> + c_aes_ccm_init (castPtr ccmStPtr) k v (fromIntegral $ B.length iv) (fromIntegral n) (fromIntegral (ccmGetM m)) (fromIntegral (ccmGetL l)) + return $ CryptoPassed (AESCCM sm) -- | append data which is only going to be authenticated to the CCM context. -- From 4926cbb143997ada1a32b5f6e5a497d4f0ffa52d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Ch=C3=A9ron?= Date: Sun, 21 Jan 2018 17:18:56 +0100 Subject: [PATCH 12/15] Improve types and indentation, fix typo --- Crypto/Cipher/AES.hs | 1 + Crypto/Cipher/AES/Primitive.hs | 3 ++- cbits/cryptonite_aes.c | 14 +++++++------- cbits/cryptonite_aes.h | 6 +++--- tests/BlockCipher.hs | 2 +- tests/KAT_AES.hs | 7 +++++-- tests/KAT_AES/KATCCM.hs | 7 ++++--- 7 files changed, 23 insertions(+), 17 deletions(-) diff --git a/Crypto/Cipher/AES.hs b/Crypto/Cipher/AES.hs index 61b81cf..97a1801 100644 --- a/Crypto/Cipher/AES.hs +++ b/Crypto/Cipher/AES.hs @@ -48,6 +48,7 @@ instance Cipher AES256 where cipherKeySize _ = KeySizeFixed 32 cipherInit k = AES256 <$> (initAES =<< validateKeySize (undefined :: AES256) k) + #define INSTANCE_BLOCKCIPHER(CSTR) \ instance BlockCipher CSTR where \ { blockSize _ = 16 \ diff --git a/Crypto/Cipher/AES/Primitive.hs b/Crypto/Cipher/AES/Primitive.hs index 5169366..26aeb61 100644 --- a/Crypto/Cipher/AES/Primitive.hs +++ b/Crypto/Cipher/AES/Primitive.hs @@ -101,7 +101,7 @@ ocbMode aes = AEADModeImpl , aeadImplFinalize = ocbFinish aes } --- | Create an AES AEAD implementation for GCM +-- | Create an AES AEAD implementation for CCM ccmMode :: AES -> AEADModeImpl AESCCM ccmMode aes = AEADModeImpl { aeadImplAppendHeader = ccmAppendAAD aes @@ -110,6 +110,7 @@ ccmMode aes = AEADModeImpl , aeadImplFinalize = ccmFinish aes } + -- | AES Context (pre-processed key) newtype AES = AES ScrubbedBytes deriving (NFData) diff --git a/cbits/cryptonite_aes.c b/cbits/cryptonite_aes.c index 7e0b723..6fdc1e0 100644 --- a/cbits/cryptonite_aes.c +++ b/cbits/cryptonite_aes.c @@ -437,18 +437,18 @@ void cryptonite_aes_gcm_finish(uint8_t *tag, aes_gcm *gcm, aes_key *key) } } -static inline int ccm_b0_flags(int has_adata, int m, int l) +static inline uint8_t ccm_b0_flags(uint32_t has_adata, uint32_t m, uint32_t l) { return 8*m + l + (has_adata? 64: 0); } /* depends on input size */ -static void ccm_encode_b0(block128* output, aes_ccm* ccm, int has_adata) +static void ccm_encode_b0(block128* output, aes_ccm* ccm, uint32_t has_adata) { int last = 15; - int m = ccm->length_M; - int l = ccm->length_L; - unsigned msg_len = ccm->length_input; + uint32_t m = ccm->length_M; + uint32_t l = ccm->length_L; + uint32_t msg_len = ccm->length_input; block128_zero(output); block128_copy(output, &ccm->nonce); @@ -530,7 +530,7 @@ void cryptonite_aes_ccm_aad(aes_ccm *ccm, aes_key *key, uint8_t *input, uint32_t block128 tmp; if (ccm->length_aad != 0) return; - + ccm->length_aad = length; int len_len; @@ -940,7 +940,7 @@ void cryptonite_aes_generic_ccm_decrypt(uint8_t *output, aes_ccm *ccm, aes_key * if (length != ccm->length_input) { return; } - + /* when aad is absent, reset b0 block */ if (ccm->length_aad == 0) { ccm_encode_b0(&ccm->b0, ccm, 0); /* assume aad is present */ diff --git a/cbits/cryptonite_aes.h b/cbits/cryptonite_aes.h index 9ac20b3..05e147d 100644 --- a/cbits/cryptonite_aes.h +++ b/cbits/cryptonite_aes.h @@ -55,7 +55,7 @@ typedef struct { uint64_t length_input; } aes_gcm; -/* size = 80 */ +/* size = 4*16+4*4= 80 */ typedef struct { aes_block xi; aes_block header_cbcmac; @@ -63,8 +63,8 @@ typedef struct { aes_block nonce; uint32_t length_aad; uint32_t length_input; - uint32_t length_M; - uint32_t length_L; + uint32_t length_M; + uint32_t length_L; } aes_ccm; typedef struct { diff --git a/tests/BlockCipher.hs b/tests/BlockCipher.hs index 6e8f8af..2fc1248 100644 --- a/tests/BlockCipher.hs +++ b/tests/BlockCipher.hs @@ -220,7 +220,7 @@ testKATs kats cipher = testGroup "KAT" aeadInitNoErr mode ct iv = case aeadInit mode ct iv of CryptoPassed a -> a - CryptoFailed _ -> error $ "cipher does'nt support aead mode: " ++ show mode + CryptoFailed _ -> error $ "cipher doesn't support aead mode: " ++ show mode ------------------------------------------------------------------------ -- Properties ------------------------------------------------------------------------ diff --git a/tests/KAT_AES.hs b/tests/KAT_AES.hs index a6c8182..cf098a3 100644 --- a/tests/KAT_AES.hs +++ b/tests/KAT_AES.hs @@ -7,6 +7,7 @@ import Data.Maybe import Crypto.Cipher.Types import qualified Crypto.Cipher.AES as AES import qualified Data.ByteString as B + import qualified KAT_AES.KATECB as KATECB import qualified KAT_AES.KATCBC as KATCBC import qualified KAT_AES.KATXTS as KATXTS @@ -49,8 +50,10 @@ toKatCCM (k,iv,h,i,o,m) = , aeadTaglen = m , aeadTag = at } - where ccmMVal x = fromMaybe CCM_M16 (lookup x [ (4, CCM_M4), (6, CCM_M6), (8, CCM_M8), (10, CCM_M10), - (12, CCM_M12), (14, CCM_M14), (16, CCM_M16) ]) + where ccmMVal x = fromMaybe (error $ "unsupported CCM tag length: " ++ show x) $ + lookup x [ (4, CCM_M4), (6, CCM_M6), (8, CCM_M8), (10, CCM_M10) + , (12, CCM_M12), (14, CCM_M14), (16, CCM_M16) + ] ctWithTag = B.drop (B.length h) o (ct, at) = B.splitAt (B.length ctWithTag - m) ctWithTag diff --git a/tests/KAT_AES/KATCCM.hs b/tests/KAT_AES/KATCCM.hs index e9b2a1a..4f3c197 100644 --- a/tests/KAT_AES/KATCCM.hs +++ b/tests/KAT_AES/KATCCM.hs @@ -7,8 +7,8 @@ import qualified Data.ByteString as B type KATCCM = (B.ByteString, B.ByteString, B.ByteString, B.ByteString, B.ByteString, Int) vectors_aes128_enc :: [KATCCM] -vectors_aes128_enc = [ - ( {- key = -} "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" +vectors_aes128_enc = + [ ( {- key = -} "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" , {- iv = -} "\x00\x00\x00\x03\x02\x01\x00\xa0\xa1\xa2\xa3\xa4\xa5" , {- hdr = -} "\x00\x01\x02\x03\x04\x05\x06\x07" , {- in = -} "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e" @@ -151,4 +151,5 @@ vectors_aes128_enc = [ , {- hdr = -} "\x6e\x37\xa6\xef\x54\x6d\x95\x5d\x34\xab\x60\x59" , {- in = -} "\xab\xf2\x1c\x0b\x02\xfe\xb8\x8f\x85\x6d\xf4\xa3\x73\x81\xbc\xe3\xcc\x12\x85\x17\xd4" , {- out = -} "\x6e\x37\xa6\xef\x54\x6d\x95\x5d\x34\xab\x60\x59\xf3\x29\x05\xb8\x8a\x64\x1b\x04\xb9\xc9\xff\xb5\x8c\xc3\x90\x90\x0f\x3d\xa1\x2a\xb1\x6d\xce\x9e\x82\xef\xa1\x6d\xa6\x20\x59" - , {- M = -} 10) ] + , {- M = -} 10) + ] From 325c87febf7112e3a3da098ad053822f59ca945f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Ch=C3=A9ron?= Date: Sun, 4 Feb 2018 14:34:40 +0100 Subject: [PATCH 13/15] Use pattern matching --- Crypto/Cipher/AES/Primitive.hs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Crypto/Cipher/AES/Primitive.hs b/Crypto/Cipher/AES/Primitive.hs index 26aeb61..8241013 100644 --- a/Crypto/Cipher/AES/Primitive.hs +++ b/Crypto/Cipher/AES/Primitive.hs @@ -494,12 +494,16 @@ ccmGetL l = case l of -- | initialize a ccm context {-# NOINLINE ccmInit #-} ccmInit :: ByteArrayAccess iv => AES -> iv -> Int -> CCM_M -> CCM_L -> CryptoFailable AESCCM -ccmInit ctx iv n m l = if 15 - ccmGetL l /= B.length iv then CryptoFailed CryptoError_IvSizeInvalid - else unsafeDoIO $ do - sm <- B.alloc sizeCCM $ \ccmStPtr -> - withKeyAndIV ctx iv $ \k v -> - c_aes_ccm_init (castPtr ccmStPtr) k v (fromIntegral $ B.length iv) (fromIntegral n) (fromIntegral (ccmGetM m)) (fromIntegral (ccmGetL l)) - return $ CryptoPassed (AESCCM sm) +ccmInit ctx iv n m l + | 15 - li /= B.length iv = CryptoFailed CryptoError_IvSizeInvalid + | otherwise = unsafeDoIO $ do + sm <- B.alloc sizeCCM $ \ccmStPtr -> + withKeyAndIV ctx iv $ \k v -> + c_aes_ccm_init (castPtr ccmStPtr) k v (fromIntegral $ B.length iv) (fromIntegral n) (fromIntegral mi) (fromIntegral li) + return $ CryptoPassed (AESCCM sm) + where + mi = ccmGetM m + li = ccmGetL l -- | append data which is only going to be authenticated to the CCM context. -- From 1490f080a56b62ec2fdcbddffc908fb3d22fd9f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Ch=C3=A9ron?= Date: Sun, 4 Feb 2018 14:36:03 +0100 Subject: [PATCH 14/15] Use aligned block128 functions Applies similar changes to what was done in #175. --- cbits/cryptonite_aes.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cbits/cryptonite_aes.c b/cbits/cryptonite_aes.c index 6fdc1e0..0b017fc 100644 --- a/cbits/cryptonite_aes.c +++ b/cbits/cryptonite_aes.c @@ -451,7 +451,7 @@ static void ccm_encode_b0(block128* output, aes_ccm* ccm, uint32_t has_adata) uint32_t msg_len = ccm->length_input; block128_zero(output); - block128_copy(output, &ccm->nonce); + block128_copy_aligned(output, &ccm->nonce); output->b[0] = ccm_b0_flags(has_adata, (m-2)/2, l-1); while (msg_len > 0) { output->b[last--] = msg_len & 0xff; @@ -480,7 +480,7 @@ static int ccm_encode_la(block128* output, uint32_t la) static void ccm_encode_ctr(block128* out, aes_ccm* ccm, unsigned int cnt) { int last = 15; - block128_copy(out, &ccm->nonce); + block128_copy_aligned(out, &ccm->nonce); out->b[0] = ccm->length_L - 1; while (cnt > 0) { @@ -491,7 +491,7 @@ static void ccm_encode_ctr(block128* out, aes_ccm* ccm, unsigned int cnt) static void ccm_cbcmac_add(aes_ccm* ccm, aes_key* key, block128* bi) { - block128_xor(&ccm->xi, bi); + block128_xor_aligned(&ccm->xi, bi); cryptonite_aes_generic_encrypt_block(&ccm->xi, key, &ccm->xi); } @@ -558,7 +558,7 @@ void cryptonite_aes_ccm_aad(aes_ccm *ccm, aes_key *key, uint8_t *input, uint32_t block128_copy_bytes(&tmp, input, length); ccm_cbcmac_add(ccm, key, &tmp); } - block128_copy(&ccm->header_cbcmac, &ccm->xi); + block128_copy_aligned(&ccm->header_cbcmac, &ccm->xi); } void cryptonite_aes_ccm_finish(uint8_t *tag, aes_ccm *ccm, aes_key *key) @@ -912,7 +912,7 @@ void cryptonite_aes_generic_ccm_encrypt(uint8_t *output, aes_ccm *ccm, aes_key * if (ccm->length_aad == 0) { ccm_encode_b0(&ccm->b0, ccm, 0); /* assume aad is present */ cryptonite_aes_encrypt_block(&ccm->xi, key, &ccm->b0); - block128_copy(&ccm->header_cbcmac, &ccm->xi); + block128_copy_aligned(&ccm->header_cbcmac, &ccm->xi); } if (length != ccm->length_input) { @@ -945,12 +945,12 @@ void cryptonite_aes_generic_ccm_decrypt(uint8_t *output, aes_ccm *ccm, aes_key * if (ccm->length_aad == 0) { ccm_encode_b0(&ccm->b0, ccm, 0); /* assume aad is present */ cryptonite_aes_encrypt_block(&ccm->xi, key, &ccm->b0); - block128_copy(&ccm->header_cbcmac, &ccm->xi); + block128_copy_aligned(&ccm->header_cbcmac, &ccm->xi); } ccm_encode_ctr(&ctr, ccm, 1); cryptonite_aes_encrypt_ctr(output, key, &ctr, input, length); - block128_copy(&ccm->xi, &ccm->header_cbcmac); + block128_copy_aligned(&ccm->xi, &ccm->header_cbcmac); input = output; for (;length >= 16; input += 16, length -= 16) { From 07be32728eadd8e6e692a6d9d31a47a286bfb806 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Ch=C3=A9ron?= Date: Sun, 4 Feb 2018 15:27:45 +0100 Subject: [PATCH 15/15] Avoid warning with tasty-quickcheck-0.9.2 --- tests/KAT_HMAC.hs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/KAT_HMAC.hs b/tests/KAT_HMAC.hs index 90b222f..74cc157 100644 --- a/tests/KAT_HMAC.hs +++ b/tests/KAT_HMAC.hs @@ -132,17 +132,17 @@ instance HashAlgorithm a => Arbitrary (MacIncrementalList a) where macIncrementalTests :: [TestTree] macIncrementalTests = - [ testProperties MD5 - , testProperties SHA1 - , testProperties SHA256 - , testProperties SHA3_224 - , testProperties SHA3_256 - , testProperties SHA3_384 - , testProperties SHA3_512 + [ testIncrProperties MD5 + , testIncrProperties SHA1 + , testIncrProperties SHA256 + , testIncrProperties SHA3_224 + , testIncrProperties SHA3_256 + , testIncrProperties SHA3_384 + , testIncrProperties SHA3_512 ] where - --testProperties :: HashAlgorithm a => a -> [Property] - testProperties a = testGroup (show a) + --testIncrProperties :: HashAlgorithm a => a -> [Property] + testIncrProperties a = testGroup (show a) [ testProperty "list-one" (prop_inc0 a) , testProperty "list-multi" (prop_inc1 a) ]