cipher-aes 0.2.6 → 0.2.7
raw patch · 6 files changed
+417/−5 lines, 6 files
Files
- Crypto/Cipher/AES.hs +147/−0
- Tests/KATOCB3.hs +52/−0
- Tests/Tests.hs +7/−3
- cbits/aes.c +195/−1
- cbits/aes.h +15/−0
- cipher-aes.cabal +1/−1
Crypto/Cipher/AES.hs view
@@ -33,6 +33,7 @@ , encryptCTR , encryptXTS , encryptGCM+ , encryptOCB -- * decryption , decryptECB@@ -40,6 +41,7 @@ , decryptCTR , decryptXTS , decryptGCM+ , decryptOCB ) where import Data.Word@@ -97,6 +99,7 @@ xtsEncrypt = encryptXTS xtsDecrypt = decryptXTS aeadInit AEAD_GCM aes iv = Just $ AEAD aes $ AEADState $ gcmInit aes iv+ aeadInit AEAD_OCB aes iv = Just $ AEAD aes $ AEADState $ ocbInit aes iv aeadInit _ _ _ = Nothing instance AEADModeImpl AES AESGCM where@@ -105,6 +108,12 @@ aeadStateDecrypt = gcmAppendDecrypt aeadStateFinalize = gcmFinish +instance AEADModeImpl AES AESOCB where+ aeadStateAppendHeader = ocbAppendAAD+ aeadStateEncrypt = ocbAppendEncrypt+ aeadStateDecrypt = ocbAppendDecrypt+ aeadStateFinalize = ocbFinish+ #define INSTANCE_BLOCKCIPHER(CSTR) \ instance BlockCipher CSTR where \ { blockSize _ = 16 \@@ -116,6 +125,7 @@ ; xtsEncrypt (CSTR aes1, CSTR aes2) = encryptXTS (aes1,aes2) \ ; xtsDecrypt (CSTR aes1, CSTR aes2) = decryptXTS (aes1,aes2) \ ; aeadInit AEAD_GCM cipher@(CSTR aes) iv = Just $ AEAD cipher $ AEADState $ gcmInit aes iv \+ ; aeadInit AEAD_OCB cipher@(CSTR aes) iv = Just $ AEAD cipher $ AEADState $ ocbInit aes iv \ ; aeadInit _ _ _ = Nothing \ }; \ \@@ -124,6 +134,13 @@ ; aeadStateEncrypt (CSTR aes) gcmState input = gcmAppendEncrypt aes gcmState input \ ; aeadStateDecrypt (CSTR aes) gcmState input = gcmAppendDecrypt aes gcmState input \ ; aeadStateFinalize (CSTR aes) gcmState len = gcmFinish aes gcmState len \+ }; \+\+instance AEADModeImpl CSTR AESOCB where \+ { aeadStateAppendHeader (CSTR aes) ocbState bs = ocbAppendAAD aes ocbState bs \+ ; aeadStateEncrypt (CSTR aes) ocbState input = ocbAppendEncrypt aes ocbState input \+ ; aeadStateDecrypt (CSTR aes) ocbState input = ocbAppendDecrypt aes ocbState input \+ ; aeadStateFinalize (CSTR aes) ocbState len = ocbFinish aes ocbState len \ } INSTANCE_BLOCKCIPHER(AES128)@@ -133,9 +150,15 @@ -- | AESGCM State newtype AESGCM = AESGCM SecureMem +-- | AESOCB State+newtype AESOCB = AESOCB SecureMem+ sizeGCM :: Int sizeGCM = 80 +sizeOCB :: Int+sizeOCB = 96+ keyToPtr :: AES -> (Ptr AES -> IO a) -> IO a keyToPtr (AES b) f = withSecureMemPtr b (f . castPtr) @@ -159,6 +182,13 @@ withNewGCMSt :: AESGCM -> (Ptr AESGCM -> IO ()) -> IO AESGCM withNewGCMSt (AESGCM gcmSt) f = withSecureMemCopy gcmSt (f . castPtr) >>= \sm2 -> return (AESGCM sm2) +withOCBKeyAndCopySt :: AES -> AESOCB -> (Ptr AESOCB -> Ptr AES -> IO a) -> IO (a, AESOCB)+withOCBKeyAndCopySt aes (AESOCB gcmSt) f =+ keyToPtr aes $ \aesPtr -> do+ newSt <- secureMemCopy gcmSt+ a <- withSecureMemPtr newSt $ \gcmStPtr -> f (castPtr gcmStPtr) aesPtr+ return (a, AESOCB newSt)+ -- | Initialize a new context with a key -- -- Key need to be of length 16, 24 or 32 bytes. any other values will cause undefined behavior@@ -240,6 +270,17 @@ -> (ByteString, AuthTag) -- ^ ciphertext and tag encryptGCM = doGCM gcmAppendEncrypt +-- | encrypt using OCB v3+-- return the encrypted bytestring and the tag associated+{-# NOINLINE encryptOCB #-}+encryptOCB :: Byteable iv+ => AES -- ^ AES Context+ -> iv -- ^ IV initial vector of any size+ -> ByteString -- ^ data to authenticate (AAD)+ -> ByteString -- ^ data to encrypt+ -> (ByteString, AuthTag) -- ^ ciphertext and tag+encryptOCB = doOCB ocbAppendEncrypt+ -- | encrypt using XTS -- -- the first key is the normal block encryption key@@ -293,6 +334,16 @@ -> (ByteString, AuthTag) -- ^ plaintext and tag decryptGCM = doGCM gcmAppendDecrypt +-- | decrypt using Offset Codebook Mode (OCB)+{-# NOINLINE decryptOCB #-}+decryptOCB :: Byteable iv+ => AES -- ^ Key+ -> iv -- ^ IV initial vector of any size+ -> ByteString -- ^ data to authenticate (AAD)+ -> ByteString -- ^ data to decrypt+ -> (ByteString, AuthTag) -- ^ plaintext and tag+decryptOCB = doOCB ocbAppendDecrypt+ {-# INLINE doECB #-} doECB :: (Ptr b -> Ptr AES -> CString -> CUInt -> IO ()) -> AES -> ByteString -> ByteString@@ -335,6 +386,10 @@ where (nbBlocks, r) = len `quotRem` 16 len = B.length input +------------------------------------------------------------------------+-- GCM+------------------------------------------------------------------------+ {-# INLINE doGCM #-} doGCM :: Byteable iv => (AES -> AESGCM -> ByteString -> (ByteString, AESGCM))@@ -402,33 +457,109 @@ where computeTag = unsafeCreate 16 $ \t -> withGCMKeyAndCopySt ctx gcm (c_aes_gcm_finish (castPtr t)) >> return () +------------------------------------------------------------------------+-- OCB v3+------------------------------------------------------------------------++{-# INLINE doOCB #-}+doOCB :: Byteable iv+ => (AES -> AESOCB -> ByteString -> (ByteString, AESOCB))+ -> AES+ -> iv+ -> ByteString+ -> ByteString+ -> (ByteString, AuthTag)+doOCB f ctx iv aad input = (output, tag)+ where tag = ocbFinish ctx after 16+ (output, after) = f ctx afterAAD input+ afterAAD = ocbAppendAAD ctx ini aad+ ini = ocbInit ctx iv++-- | initialize an ocb context+{-# NOINLINE ocbInit #-}+ocbInit :: Byteable iv => AES -> iv -> AESOCB+ocbInit ctx iv = unsafePerformIO $ do+ sm <- createSecureMem sizeOCB $ \ocbStPtr ->+ withKeyAndIV ctx iv $ \k v ->+ c_aes_ocb_init (castPtr ocbStPtr) k v (fromIntegral $ byteableLength iv)+ return $ AESOCB sm++-- | append data which is going to just be authentified to the OCB context.+--+-- need to happen after initialization and before appending encryption/decryption data.+{-# NOINLINE ocbAppendAAD #-}+ocbAppendAAD :: AES -> AESOCB -> ByteString -> AESOCB+ocbAppendAAD ctx ocb input = unsafePerformIO (snd `fmap` withOCBKeyAndCopySt ctx ocb doAppend)+ where doAppend ocbStPtr aesPtr =+ unsafeUseAsCString input $ \i ->+ c_aes_ocb_aad ocbStPtr aesPtr i (fromIntegral $ B.length input)++-- | append data to encrypt and append to the OCB context+--+-- bytestring need to be multiple of AES block size, unless it's the last call to this function.+-- need to happen after AAD appending, or after initialization if no AAD data.+{-# NOINLINE ocbAppendEncrypt #-}+ocbAppendEncrypt :: AES -> AESOCB -> ByteString -> (ByteString, AESOCB)+ocbAppendEncrypt ctx ocb input = unsafePerformIO $ withOCBKeyAndCopySt ctx ocb doEnc+ where len = B.length input+ doEnc ocbStPtr aesPtr =+ create len $ \o ->+ unsafeUseAsCString input $ \i ->+ c_aes_ocb_encrypt (castPtr o) ocbStPtr aesPtr i (fromIntegral len)++-- | append data to decrypt and append to the OCB context+--+-- bytestring need to be multiple of AES block size, unless it's the last call to this function.+-- need to happen after AAD appending, or after initialization if no AAD data.+{-# NOINLINE ocbAppendDecrypt #-}+ocbAppendDecrypt :: AES -> AESOCB -> ByteString -> (ByteString, AESOCB)+ocbAppendDecrypt ctx ocb input = unsafePerformIO $ withOCBKeyAndCopySt ctx ocb doDec+ where len = B.length input+ doDec ocbStPtr aesPtr =+ create len $ \o ->+ unsafeUseAsCString input $ \i ->+ c_aes_ocb_decrypt (castPtr o) ocbStPtr aesPtr i (fromIntegral len)++-- | Generate the Tag from OCB context+{-# NOINLINE ocbFinish #-}+ocbFinish :: AES -> AESOCB -> Int -> AuthTag+ocbFinish ctx ocb taglen = AuthTag $ B.take taglen computeTag+ where computeTag = unsafeCreate 16 $ \t ->+ withOCBKeyAndCopySt ctx ocb (c_aes_ocb_finish (castPtr t)) >> return ()++------------------------------------------------------------------------ foreign import ccall "aes.h aes_initkey" c_aes_init :: Ptr AES -> CString -> CUInt -> IO () +------------------------------------------------------------------------ foreign import ccall "aes.h aes_encrypt_ecb" c_aes_encrypt_ecb :: CString -> Ptr AES -> CString -> CUInt -> IO () foreign import ccall "aes.h aes_decrypt_ecb" c_aes_decrypt_ecb :: CString -> Ptr AES -> CString -> CUInt -> IO () +------------------------------------------------------------------------ foreign import ccall "aes.h aes_encrypt_cbc" c_aes_encrypt_cbc :: CString -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO () foreign import ccall "aes.h aes_decrypt_cbc" c_aes_decrypt_cbc :: CString -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO () +------------------------------------------------------------------------ foreign import ccall "aes.h aes_encrypt_xts" c_aes_encrypt_xts :: CString -> Ptr AES -> Ptr AES -> Ptr Word8 -> CUInt -> CString -> CUInt -> IO () foreign import ccall "aes.h aes_decrypt_xts" c_aes_decrypt_xts :: CString -> Ptr AES -> Ptr AES -> Ptr Word8 -> CUInt -> CString -> CUInt -> IO () +------------------------------------------------------------------------ foreign import ccall "aes.h aes_gen_ctr" c_aes_gen_ctr :: 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 () +------------------------------------------------------------------------ foreign import ccall "aes.h aes_gcm_init" c_aes_gcm_init :: Ptr AESGCM -> Ptr AES -> Ptr Word8 -> CUInt -> IO () @@ -443,3 +574,19 @@ foreign import ccall "aes.h aes_gcm_finish" c_aes_gcm_finish :: CString -> Ptr AESGCM -> Ptr AES -> IO ()++------------------------------------------------------------------------+foreign import ccall "aes.h aes_ocb_init"+ c_aes_ocb_init :: Ptr AESOCB -> Ptr AES -> Ptr Word8 -> CUInt -> IO ()++foreign import ccall "aes.h aes_ocb_aad"+ c_aes_ocb_aad :: Ptr AESOCB -> Ptr AES -> CString -> CUInt -> IO ()++foreign import ccall "aes.h aes_ocb_encrypt"+ c_aes_ocb_encrypt :: CString -> Ptr AESOCB -> Ptr AES -> CString -> CUInt -> IO ()++foreign import ccall "aes.h aes_ocb_decrypt"+ c_aes_ocb_decrypt :: CString -> Ptr AESOCB -> Ptr AES -> CString -> CUInt -> IO ()++foreign import ccall "aes.h aes_ocb_finish"+ c_aes_ocb_finish :: CString -> Ptr AESOCB -> Ptr AES -> IO ()
+ Tests/KATOCB3.hs view
@@ -0,0 +1,52 @@+{-# LANGUAGE OverloadedStrings #-}+module KATOCB3 where++import qualified Data.ByteString as B+import Data.ByteString.Char8 ()++-- (key, iv, aad, input, out, taglen, tag)+type KATOCB3 = (B.ByteString, B.ByteString, B.ByteString, B.ByteString, B.ByteString, Int, B.ByteString)++key1 = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"+nonce1 = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b"++vectors_aes128_enc :: [KATOCB3]+vectors_aes128_enc =+ [ ( {-key = -} key1+ , {-iv = -} nonce1+ , {-aad = -}""+ , {-input = -}""+ , {-out = -}""+ , {-taglen = -} 16+ , {-tag = -} "\x19\x7b\x9c\x3c\x44\x1d\x3c\x83\xea\xfb\x2b\xef\x63\x3b\x91\x82")+ , ( key1, nonce1+ , "\x00\x01\x02\x03\x04\x05\x06\x07"+ , "\x00\x01\x02\x03\x04\x05\x06\x07"+ , "\x92\xb6\x57\x13\x0a\x74\xb8\x5a"+ , 16+ , "\x16\xdc\x76\xa4\x6d\x47\xe1\xea\xd5\x37\x20\x9e\x8a\x96\xd1\x4e")+ , ( key1, nonce1+ , "\x00\x01\x02\x03\x04\x05\x06\x07"+ , ""+ , ""+ , 16+ , "\x98\xb9\x15\x52\xc8\xc0\x09\x18\x50\x44\xe3\x0a\x6e\xb2\xfe\x21")+ , ( key1, nonce1+ , ""+ , "\x00\x01\x02\x03\x04\x05\x06\x07"+ , "\x92\xb6\x57\x13\x0a\x74\xb8\x5a"+ , 16+ , "\x97\x1e\xff\xca\xe1\x9a\xd4\x71\x6f\x88\xe8\x7b\x87\x1f\xbe\xed")+ , ( key1, nonce1+ , "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"+ , "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"+ , "\xbe\xa5\xe8\x79\x8d\xbe\x71\x10\x03\x1c\x14\x4d\xa0\xb2\x61\x22"+ , 16+ , "\x77\x6c\x99\x24\xd6\x72\x3a\x1f\xc4\x52\x45\x32\xac\x3e\x5b\xeb")+ ]++vectors_encrypt =+ [ ("AES128 Enc", vectors_aes128_enc)+ ]++vectors_decrypt = []
Tests/Tests.hs view
@@ -21,12 +21,13 @@ import qualified KATCBC import qualified KATXTS import qualified KATGCM+import qualified KATOCB3 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 }-toKatGCM (k,iv,h,p,c,taglen,tag) =- KAT_AEAD { aeadMode = AEAD_GCM+toKatAEAD mode (k,iv,h,p,c,taglen,tag) =+ KAT_AEAD { aeadMode = mode , aeadKey = k , aeadIV = iv , aeadHeader = h@@ -35,6 +36,8 @@ , aeadTaglen = taglen , aeadTag = AuthTag tag }+toKatGCM = toKatAEAD AEAD_GCM+toKatOCB = toKatAEAD AEAD_OCB kats128 = defaultKATs { kat_ECB = map toKatECB KATECB.vectors_aes128_enc@@ -46,7 +49,8 @@ } ] , kat_XTS = map toKatXTS KATXTS.vectors_aes128_enc- , kat_AEAD = map toKatGCM KATGCM.vectors_aes128_enc+ , kat_AEAD = map toKatGCM KATGCM.vectors_aes128_enc +++ map toKatOCB KATOCB3.vectors_aes128_enc } kats192 = defaultKATs
cbits/aes.c view
@@ -49,6 +49,8 @@ uint32_t spoint, aes_block *input, uint32_t nb_blocks); void aes_generic_gcm_encrypt(uint8_t *output, aes_gcm *gcm, aes_key *key, uint8_t *input, uint32_t length); void aes_generic_gcm_decrypt(uint8_t *output, aes_gcm *gcm, aes_key *key, uint8_t *input, uint32_t length);+void aes_generic_ocb_encrypt(uint8_t *output, aes_ocb *ocb, aes_key *key, uint8_t *input, uint32_t length);+void aes_generic_ocb_decrypt(uint8_t *output, aes_ocb *ocb, aes_key *key, uint8_t *input, uint32_t length); enum { /* init */@@ -67,9 +69,12 @@ /* xts */ ENCRYPT_XTS_128, ENCRYPT_XTS_192, ENCRYPT_XTS_256, DECRYPT_XTS_128, DECRYPT_XTS_192, DECRYPT_XTS_256,- /* xts */+ /* gcm */ ENCRYPT_GCM_128, ENCRYPT_GCM_192, ENCRYPT_GCM_256, DECRYPT_GCM_128, DECRYPT_GCM_192, DECRYPT_GCM_256,+ /* ocb */+ ENCRYPT_OCB_128, ENCRYPT_OCB_192, ENCRYPT_OCB_256,+ DECRYPT_OCB_128, DECRYPT_OCB_192, DECRYPT_OCB_256, }; void *branch_table[] = {@@ -116,6 +121,13 @@ [DECRYPT_GCM_128] = aes_generic_gcm_decrypt, [DECRYPT_GCM_192] = aes_generic_gcm_decrypt, [DECRYPT_GCM_256] = aes_generic_gcm_decrypt,+ /* OCB */+ [ENCRYPT_OCB_128] = aes_generic_ocb_encrypt,+ [ENCRYPT_OCB_192] = aes_generic_ocb_encrypt,+ [ENCRYPT_OCB_256] = aes_generic_ocb_encrypt,+ [DECRYPT_OCB_128] = aes_generic_ocb_decrypt,+ [DECRYPT_OCB_192] = aes_generic_ocb_decrypt,+ [DECRYPT_OCB_256] = aes_generic_ocb_decrypt, }; typedef void (*init_f)(aes_key *, uint8_t *, uint8_t);@@ -124,6 +136,7 @@ typedef void (*ctr_f)(uint8_t *output, aes_key *key, aes_block *iv, uint8_t *input, uint32_t length); 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 (*block_f)(aes_block *output, aes_key *key, aes_block *input); #ifdef WITH_AESNI@@ -147,6 +160,10 @@ ((gcm_crypt_f) (branch_table[ENCRYPT_GCM_128 + strength])) #define GET_GCM_DECRYPT(strength) \ ((gcm_crypt_f) (branch_table[DECRYPT_GCM_128 + strength]))+#define GET_OCB_ENCRYPT(strength) \+ ((ocb_crypt_f) (branch_table[ENCRYPT_OCB_128 + strength]))+#define GET_OCB_DECRYPT(strength) \+ ((ocb_crypt_f) (branch_table[DECRYPT_OCB_128 + strength])) #define aes_encrypt_block(o,k,i) \ (((block_f) (branch_table[ENCRYPT_BLOCK_128 + k->strength]))(o,k,i)) #define aes_decrypt_block(o,k,i) \@@ -162,6 +179,8 @@ #define GET_XTS_DECRYPT(strength) aes_generic_decrypt_xts #define GET_GCM_ENCRYPT(strength) aes_generic_gcm_encrypt #define GET_GCM_DECRYPT(strength) aes_generic_gcm_decrypt+#define GET_OCB_ENCRYPT(strength) aes_generic_ocb_encrypt+#define GET_OCB_DECRYPT(strength) aes_generic_ocb_decrypt #define aes_encrypt_block(o,k,i) aes_generic_encrypt_block(o,k,i) #define aes_decrypt_block(o,k,i) aes_generic_decrypt_block(o,k,i) #endif@@ -197,6 +216,11 @@ /* GCM */ branch_table[ENCRYPT_GCM_128] = aes_ni_gcm_encrypt128; branch_table[ENCRYPT_GCM_256] = aes_ni_gcm_encrypt256;+ /* OCB */+ /*+ branch_table[ENCRYPT_OCB_128] = aes_ni_ocb_encrypt128;+ branch_table[ENCRYPT_OCB_256] = aes_ni_ocb_encrypt256;+ */ } #endif @@ -281,6 +305,18 @@ d(output, gcm, key, input, length); } +void 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);+ e(output, ocb, key, input, length);+}++void aes_ocb_decrypt(uint8_t *output, aes_ocb *ocb, aes_key *key, uint8_t *input, uint32_t length)+{+ ocb_crypt_f d = GET_OCB_DECRYPT(key->strength);+ d(output, ocb, key, input, length);+}+ static void gcm_ghash_add(aes_gcm *gcm, block128 *b) { block128_xor(&gcm->tag, b);@@ -354,6 +390,106 @@ } } +static void ocb_block_double(block128 *output, block128 *input)+{+ unsigned int i;+ uint8_t tmp = input->b[0];++ if (output != input) block128_copy(output, input);+ for (i=0; i<15; i++)+ output->b[i] = (input->b[i] << 1) | (input->b[i+1] >> 7);+ output->b[15] = (input->b[15] << 1) ^ ((tmp >> 7) * 0x87);+}++static void ocb_get_L_i(block128 *l, block128 *ldollar, unsigned int i)+{+ /* TODO optimise with a table. */+ ocb_block_double(l, ldollar);+ for ( ; (i&1) == 0; i >>= 1) /* double for each trailing 0 */+ ocb_block_double(l, l);+}++void aes_ocb_init(aes_ocb *ocb, aes_key *key, uint8_t *iv, uint32_t len)+{+ block128 tmp, nonce, ktop;+ unsigned char stretch[24];+ unsigned bottom, byteshift, bitshift, i;++ /* we don't accept more than 15 bytes, any bytes higher will be ignored. */+ if (len > 15) {+ len = 15;+ }++ /* create L*, and L$ */+ block128_zero(&tmp);+ aes_encrypt_block(&ocb->lstar, key, &tmp);+ ocb_block_double(&ocb->ldollar, &ocb->lstar);++ /* create strech from the nonce */+ block128_zero(&nonce);+ memcpy(nonce.b + 4, iv, 12);+ nonce.b[0] = (unsigned char)(((16 * 8) % 128) << 1);+ nonce.b[16-12-1] |= 0x01;+ bottom = nonce.b[15] & 0x3F;+ nonce.b[15] &= 0xC0;+ aes_encrypt_block(&ktop, key, &nonce);+ memcpy(stretch, ktop.b, 16);+ memcpy(tmp.b, ktop.b + 1, 8);+ block128_xor(&tmp, &ktop);+ memcpy(stretch + 16, tmp.b, 8);++ /* initialize the encryption offset from stretch */+ byteshift = bottom / 8;+ bitshift = bottom % 8;+ if (bitshift != 0)+ for (i = 0; i < 16; i++)+ ocb->offset_enc.b[i] = (stretch[i+byteshift] << bitshift)+ | (stretch[i+byteshift+1] >> (8-bitshift));+ else+ for (i = 0; i < 16; i++)+ ocb->offset_enc.b[i] = stretch[i+byteshift];+ /* initialize checksum for aad and encryption, and the aad offset */+ block128_zero(&ocb->sum_aad);+ block128_zero(&ocb->sum_enc);+ block128_zero(&ocb->offset_aad);+}++void aes_ocb_aad(aes_ocb *ocb, aes_key *key, uint8_t *input, uint32_t length)+{+ block128 tmp;+ unsigned int i;++ for (i=1; i<= length/16; i++, input=input+16) {+ ocb_get_L_i(&tmp, &ocb->ldollar, i);+ block128_xor(&ocb->offset_aad, &tmp);++ block128_vxor(&tmp, &ocb->offset_aad, (block128 *) input);+ aes_encrypt_block(&tmp, key, &tmp);+ block128_xor(&ocb->sum_aad, &tmp);+ }++ length = length % 16; /* Bytes in final block */+ if (length > 0) {+ block128_xor(&ocb->offset_aad, &ocb->lstar);+ block128_zero(&tmp);+ block128_copy_bytes(&tmp, input, length);+ tmp.b[length] = 0x80;+ block128_xor(&tmp, &ocb->offset_aad);+ aes_encrypt_block(&tmp, key, &tmp);+ block128_xor(&ocb->sum_aad, &tmp);+ }+}++void aes_ocb_finish(uint8_t *tag, aes_ocb *ocb, aes_key *key)+{+ block128 tmp;++ block128_vxor(&tmp, &ocb->sum_enc, &ocb->offset_enc);+ block128_xor(&tmp, &ocb->ldollar);+ aes_encrypt_block((block128 *) tag, key, &tmp);+ block128_xor((block128 *) tag, &ocb->sum_aad);+}+ void aes_generic_encrypt_ecb(aes_block *output, aes_key *key, aes_block *input, uint32_t nb_blocks) { for ( ; nb_blocks-- > 0; input++, output++) {@@ -525,3 +661,61 @@ } } +static int 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;++ for (i = 1; i <= length/16; i++, input += 16, output += 16) {+ /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */+ ocb_get_L_i(&tmp, &ocb->ldollar, i);+ block128_xor(&ocb->offset_enc, &tmp);++ block128_vxor(&tmp, &ocb->offset_enc, (block128 *) input);+ if (encrypt) {+ aes_encrypt_block(&tmp, key, &tmp);+ block128_vxor((block128 *) output, &ocb->offset_enc, &tmp);+ block128_xor(&ocb->sum_enc, (block128 *) input);+ } else {+ aes_decrypt_block(&tmp, key, &tmp);+ block128_vxor((block128 *) output, &ocb->offset_enc, &tmp);+ block128_xor(&ocb->sum_enc, (block128 *) output);+ }+ }++ /* process the last partial block if any */+ length = length % 16;+ if (length > 0) {+ block128_xor(&ocb->offset_enc, &ocb->lstar);+ aes_encrypt_block(&pad, key, &ocb->offset_enc);++ if (encrypt) {+ block128_zero(&tmp);+ block128_copy_bytes(&tmp, input, length);+ tmp.b[length] = 0x80;+ block128_xor(&ocb->sum_enc, &tmp);+ block128_xor(&pad, &tmp);+ memcpy(output, pad.b, length);+ output += length;+ } else {+ block128_copy(&tmp, &pad);+ block128_copy_bytes(&tmp, input, length);+ block128_xor(&tmp, &pad);+ tmp.b[length] = 0x80;+ memcpy(output, tmp.b, length);+ block128_xor(&ocb->sum_enc, &tmp);+ input += length;+ }+ }+}++void 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);+}++void aes_generic_ocb_decrypt(uint8_t *output, aes_ocb *ocb, aes_key *key, uint8_t *input, uint32_t length)+{+ ocb_generic_crypt(output, ocb, key, input, length, 0);+}
cbits/aes.h view
@@ -55,6 +55,15 @@ uint64_t length_input; } aes_gcm; +typedef struct {+ block128 lstar;+ block128 ldollar;+ block128 offset_aad;+ block128 offset_enc;+ block128 sum_aad;+ block128 sum_enc;+} aes_ocb;+ /* in bytes: either 16,24,32 */ void aes_initkey(aes_key *ctx, uint8_t *key, uint8_t size); @@ -79,5 +88,11 @@ void aes_gcm_encrypt(uint8_t *output, aes_gcm *gcm, aes_key *key, uint8_t *input, uint32_t length); void aes_gcm_decrypt(uint8_t *output, aes_gcm *gcm, aes_key *key, uint8_t *input, uint32_t length); void aes_gcm_finish(uint8_t *tag, aes_gcm *gcm, aes_key *key);++void aes_ocb_init(aes_ocb *ocb, aes_key *key, uint8_t *iv, uint32_t len);+void aes_ocb_aad(aes_ocb *ocb, aes_key *key, uint8_t *input, uint32_t length);+void aes_ocb_encrypt(uint8_t *output, aes_ocb *ocb, aes_key *key, uint8_t *input, uint32_t length);+void aes_ocb_decrypt(uint8_t *output, aes_ocb *ocb, aes_key *key, uint8_t *input, uint32_t length);+void aes_ocb_finish(uint8_t *tag, aes_ocb *ocb, aes_key *key); #endif
cipher-aes.cabal view
@@ -1,5 +1,5 @@ Name: cipher-aes-Version: 0.2.6+Version: 0.2.7 Description: Fast AES cipher implementation with advanced mode of operations. .