1{-# LANGUAGE ForeignFunctionInterface #-}
2{-# LANGUAGE ViewPatterns #-}
3{-# LANGUAGE MultiParamTypeClasses #-}
4{-# LANGUAGE BangPatterns #-}
5{-# LANGUAGE CPP #-}
6{-# LANGUAGE GeneralizedNewtypeDeriving #-}
7-- |
8-- Module      : Crypto.Cipher.AES
9-- License     : BSD-style
10-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
11-- Stability   : stable
12-- Portability : good
13--
14module Crypto.Cipher.AES
15    (
16    -- * block cipher data types
17      AES
18    , AES128
19    , AES192
20    , AES256
21
22    -- * IV
23    , AESIV
24    , aesIV_
25
26    -- * Authenticated encryption block cipher types
27    , AESGCM
28
29    -- * creation
30    , initAES
31    , initKey
32
33    -- * misc
34    , genCTR
35    , genCounter
36
37    -- * encryption
38    , encryptECB
39    , encryptCBC
40    , encryptCTR
41    , encryptXTS
42    , encryptGCM
43    , encryptOCB
44
45    -- * decryption
46    , decryptECB
47    , decryptCBC
48    , decryptCTR
49    , decryptXTS
50    , decryptGCM
51    , decryptOCB
52    ) where
53
54import Data.Word
55import Foreign.Ptr
56import Foreign.ForeignPtr
57import Foreign.C.Types
58import Foreign.C.String
59import Data.ByteString.Internal
60import Data.ByteString.Unsafe
61import Data.Byteable
62import qualified Data.ByteString as B
63import qualified Data.ByteString.Internal as B (ByteString(PS), mallocByteString, memcpy)
64import System.IO.Unsafe (unsafePerformIO)
65
66import Crypto.Cipher.Types
67import Data.SecureMem
68
69-- | AES Context (pre-processed key)
70newtype AES = AES SecureMem
71
72-- | AES with 128 bit key
73newtype AES128 = AES128 AES
74
75-- | AES with 192 bit key
76newtype AES192 = AES192 AES
77
78-- | AES with 256 bit key
79newtype AES256 = AES256 AES
80
81-- | AES IV is always 16 bytes
82newtype AESIV = AESIV ByteString
83    deriving (Show,Eq,Byteable)
84
85-- | convert a bytestring to an AESIV
86aesIV_ :: ByteString -> AESIV
87aesIV_ iv
88    | B.length iv /= 16 = error $ "AES error: IV length must be block size (16). Its length is: " ++ (show $ B.length iv)
89    | otherwise         = AESIV iv
90
91instance Cipher AES where
92    cipherName    _ = "AES"
93    cipherKeySize _ = KeySizeEnum [16,24,32]
94    cipherInit k    = initAES k
95
96instance Cipher AES128 where
97    cipherName    _ = "AES128"
98    cipherKeySize _ = KeySizeFixed 16
99    cipherInit k    = AES128 $ initAES k
100
101instance Cipher AES192 where
102    cipherName    _ = "AES192"
103    cipherKeySize _ = KeySizeFixed 24
104    cipherInit k    = AES192 $ initAES k
105
106instance Cipher AES256 where
107    cipherName    _ = "AES256"
108    cipherKeySize _ = KeySizeFixed 32
109    cipherInit k    = AES256 $ initAES k
110
111instance BlockCipher AES where
112    blockSize _ = 16
113    ecbEncrypt = encryptECB
114    ecbDecrypt = decryptECB
115    cbcEncrypt = encryptCBC
116    cbcDecrypt = decryptCBC
117    ctrCombine = encryptCTR
118    xtsEncrypt = encryptXTS
119    xtsDecrypt = decryptXTS
120    aeadInit AEAD_GCM aes iv = Just $ AEAD aes $ AEADState $ gcmInit aes iv
121    aeadInit AEAD_OCB aes iv = Just $ AEAD aes $ AEADState $ ocbInit aes iv
122    aeadInit _        _    _ = Nothing
123
124instance AEADModeImpl AES AESGCM where
125    aeadStateAppendHeader _ = gcmAppendAAD
126    aeadStateEncrypt = gcmAppendEncrypt
127    aeadStateDecrypt = gcmAppendDecrypt
128    aeadStateFinalize = gcmFinish
129
130instance AEADModeImpl AES AESOCB where
131    aeadStateAppendHeader = ocbAppendAAD
132    aeadStateEncrypt = ocbAppendEncrypt
133    aeadStateDecrypt = ocbAppendDecrypt
134    aeadStateFinalize = ocbFinish
135
136#define INSTANCE_BLOCKCIPHER(CSTR) \
137instance BlockCipher CSTR where \
138    { blockSize _ = 16 \
139    ; ecbEncrypt (CSTR aes) = encryptECB aes \
140    ; ecbDecrypt (CSTR aes) = decryptECB aes \
141    ; cbcEncrypt (CSTR aes) = encryptCBC aes \
142    ; cbcDecrypt (CSTR aes) = decryptCBC aes \
143    ; ctrCombine (CSTR aes) = encryptCTR aes \
144    ; xtsEncrypt (CSTR aes1, CSTR aes2) = encryptXTS (aes1,aes2) \
145    ; xtsDecrypt (CSTR aes1, CSTR aes2) = decryptXTS (aes1,aes2) \
146    ; aeadInit AEAD_GCM cipher@(CSTR aes) iv = Just $ AEAD cipher $ AEADState $ gcmInit aes iv \
147    ; aeadInit AEAD_OCB cipher@(CSTR aes) iv = Just $ AEAD cipher $ AEADState $ ocbInit aes iv \
148    ; aeadInit _        _                  _ = Nothing \
149    }; \
150\
151instance AEADModeImpl CSTR AESGCM where \
152    { aeadStateAppendHeader (CSTR _) gcmState bs = gcmAppendAAD gcmState bs \
153    ; aeadStateEncrypt (CSTR aes) gcmState input = gcmAppendEncrypt aes gcmState input \
154    ; aeadStateDecrypt (CSTR aes) gcmState input = gcmAppendDecrypt aes gcmState input \
155    ; aeadStateFinalize (CSTR aes) gcmState len  = gcmFinish aes gcmState len \
156    }; \
157\
158instance AEADModeImpl CSTR AESOCB where \
159    { aeadStateAppendHeader (CSTR aes) ocbState bs = ocbAppendAAD aes ocbState bs \
160    ; aeadStateEncrypt (CSTR aes) ocbState input = ocbAppendEncrypt aes ocbState input \
161    ; aeadStateDecrypt (CSTR aes) ocbState input = ocbAppendDecrypt aes ocbState input \
162    ; aeadStateFinalize (CSTR aes) ocbState len  = ocbFinish aes ocbState len \
163    }
164
165INSTANCE_BLOCKCIPHER(AES128)
166INSTANCE_BLOCKCIPHER(AES192)
167INSTANCE_BLOCKCIPHER(AES256)
168
169-- | AESGCM State
170newtype AESGCM = AESGCM SecureMem
171
172-- | AESOCB State
173newtype AESOCB = AESOCB SecureMem
174
175sizeGCM :: Int
176sizeGCM = 80
177
178sizeOCB :: Int
179sizeOCB = 160
180
181keyToPtr :: AES -> (Ptr AES -> IO a) -> IO a
182keyToPtr (AES b) f = withSecureMemPtr b (f . castPtr)
183
184ivToPtr :: Byteable iv => iv -> (Ptr Word8 -> IO a) -> IO a
185ivToPtr iv f = withBytePtr iv (f . castPtr)
186
187ivCopyPtr :: AESIV -> (Ptr Word8 -> IO ()) -> IO AESIV
188ivCopyPtr (AESIV iv) f = do
189    newIV <- create 16 $ \newPtr -> do
190                withBytePtr iv $ \ivPtr -> B.memcpy newPtr ivPtr 16
191    withBytePtr newIV $ f
192    return $! AESIV newIV
193
194withKeyAndIV :: Byteable iv => AES -> iv -> (Ptr AES -> Ptr Word8 -> IO a) -> IO a
195withKeyAndIV ctx iv f = keyToPtr ctx $ \kptr -> ivToPtr iv $ \ivp -> f kptr ivp
196
197withKey2AndIV :: Byteable iv => AES -> AES -> iv -> (Ptr AES -> Ptr AES -> Ptr Word8 -> IO a) -> IO a
198withKey2AndIV key1 key2 iv f =
199    keyToPtr key1 $ \kptr1 -> keyToPtr key2 $ \kptr2 -> ivToPtr iv $ \ivp -> f kptr1 kptr2 ivp
200
201withGCMKeyAndCopySt :: AES -> AESGCM -> (Ptr AESGCM -> Ptr AES -> IO a) -> IO (a, AESGCM)
202withGCMKeyAndCopySt aes (AESGCM gcmSt) f =
203    keyToPtr aes $ \aesPtr -> do
204        newSt <- secureMemCopy gcmSt
205        a     <- withSecureMemPtr newSt $ \gcmStPtr -> f (castPtr gcmStPtr) aesPtr
206        return (a, AESGCM newSt)
207
208withNewGCMSt :: AESGCM -> (Ptr AESGCM -> IO ()) -> IO AESGCM
209withNewGCMSt (AESGCM gcmSt) f = withSecureMemCopy gcmSt (f . castPtr) >>= \sm2 -> return (AESGCM sm2)
210
211withOCBKeyAndCopySt :: AES -> AESOCB -> (Ptr AESOCB -> Ptr AES -> IO a) -> IO (a, AESOCB)
212withOCBKeyAndCopySt aes (AESOCB gcmSt) f =
213    keyToPtr aes $ \aesPtr -> do
214        newSt <- secureMemCopy gcmSt
215        a     <- withSecureMemPtr newSt $ \gcmStPtr -> f (castPtr gcmStPtr) aesPtr
216        return (a, AESOCB newSt)
217
218-- | Initialize a new context with a key
219--
220-- Key need to be of length 16, 24 or 32 bytes. any other values will cause undefined behavior
221initAES :: Byteable b => b -> AES
222initAES k
223    | len == 16 = initWithRounds 10
224    | len == 24 = initWithRounds 12
225    | len == 32 = initWithRounds 14
226    | otherwise = error "AES: not a valid key length (valid=16,24,32)"
227  where len = byteableLength k
228        initWithRounds nbR = AES $ unsafeCreateSecureMem (16+2*2*16*nbR) aesInit
229        aesInit ptr = withBytePtr k $ \ikey ->
230            c_aes_init (castPtr ptr) (castPtr ikey) (fromIntegral len)
231
232{-# DEPRECATED initKey "use initAES" #-}
233initKey :: Byteable b => b -> AES
234initKey = initAES
235
236-- | encrypt using Electronic Code Book (ECB)
237{-# NOINLINE encryptECB #-}
238encryptECB :: AES -> ByteString -> ByteString
239encryptECB = doECB c_aes_encrypt_ecb
240
241-- | encrypt using Cipher Block Chaining (CBC)
242{-# NOINLINE encryptCBC #-}
243encryptCBC :: Byteable iv
244           => AES        -- ^ AES Context
245           -> iv         -- ^ Initial vector of AES block size
246           -> ByteString -- ^ plaintext
247           -> ByteString -- ^ ciphertext
248encryptCBC = doCBC c_aes_encrypt_cbc
249
250-- | generate a counter mode pad. this is generally xor-ed to an input
251-- to make the standard counter mode block operations.
252--
253-- if the length requested is not a multiple of the block cipher size,
254-- more data will be returned, so that the returned bytestring is
255-- a multiple of the block cipher size.
256{-# NOINLINE genCTR #-}
257genCTR :: Byteable iv
258       => AES -- ^ Cipher Key.
259       -> iv  -- ^ usually a 128 bit integer.
260       -> Int -- ^ length of bytes required.
261       -> ByteString
262genCTR ctx iv len
263    | len <= 0  = B.empty
264    | byteableLength iv /= 16 = error $ "AES error: IV length must be block size (16). Its length is: " ++ (show $ byteableLength iv)
265    | otherwise = unsafeCreate (nbBlocks * 16) generate
266  where generate o = withKeyAndIV ctx iv $ \k i -> c_aes_gen_ctr (castPtr o) k i (fromIntegral nbBlocks)
267        (nbBlocks',r) = len `quotRem` 16
268        nbBlocks = if r == 0 then nbBlocks' else nbBlocks' + 1
269
270-- | generate a counter mode pad. this is generally xor-ed to an input
271-- to make the standard counter mode block operations.
272--
273-- if the length requested is not a multiple of the block cipher size,
274-- more data will be returned, so that the returned bytestring is
275-- a multiple of the block cipher size.
276--
277-- Similiar to 'genCTR' but also return the next IV for continuation
278{-# NOINLINE genCounter #-}
279genCounter :: AES
280           -> AESIV
281           -> Int
282           -> (ByteString, AESIV)
283genCounter ctx iv len
284    | len <= 0  = (B.empty, iv)
285    | otherwise = unsafePerformIO $ do
286        fptr  <- B.mallocByteString outputLength
287        newIv <- withForeignPtr fptr $ \o ->
288                    keyToPtr ctx $ \k ->
289                    ivCopyPtr iv $ \i -> do
290                        c_aes_gen_ctr_cont (castPtr o) k i (fromIntegral nbBlocks)
291        let !out = B.PS fptr 0 outputLength
292        return $! (out `seq` newIv `seq` (out, newIv))
293  where
294        (nbBlocks',r) = len `quotRem` 16
295        nbBlocks = if r == 0 then nbBlocks' else nbBlocks' + 1
296        outputLength = nbBlocks * 16
297
298{- TODO: when genCTR has same AESIV requirements for IV, add the following rules:
299 - RULES "snd . genCounter" forall ctx iv len .  snd (genCounter ctx iv len) = genCTR ctx iv len
300 -}
301
302-- | encrypt using Counter mode (CTR)
303--
304-- in CTR mode encryption and decryption is the same operation.
305{-# NOINLINE encryptCTR #-}
306encryptCTR :: Byteable iv
307           => AES        -- ^ AES Context
308           -> iv         -- ^ initial vector of AES block size (usually representing a 128 bit integer)
309           -> ByteString -- ^ plaintext input
310           -> ByteString -- ^ ciphertext output
311encryptCTR ctx iv input
312    | len <= 0  = B.empty
313    | byteableLength iv /= 16 = error $ "AES error: IV length must be block size (16). Its length is: " ++ (show $ byteableLength iv)
314    | otherwise = unsafeCreate len doEncrypt
315  where doEncrypt o = withKeyAndIV ctx iv $ \k v -> unsafeUseAsCString input $ \i ->
316                      c_aes_encrypt_ctr (castPtr o) k v i (fromIntegral len)
317        len = B.length input
318
319-- | encrypt using Galois counter mode (GCM)
320-- return the encrypted bytestring and the tag associated
321--
322-- note: encrypted data is identical to CTR mode in GCM, however
323-- a tag is also computed.
324{-# NOINLINE encryptGCM #-}
325encryptGCM :: Byteable iv
326           => AES        -- ^ AES Context
327           -> iv         -- ^ IV initial vector of any size
328           -> ByteString -- ^ data to authenticate (AAD)
329           -> ByteString -- ^ data to encrypt
330           -> (ByteString, AuthTag) -- ^ ciphertext and tag
331encryptGCM = doGCM gcmAppendEncrypt
332
333-- | encrypt using OCB v3
334-- return the encrypted bytestring and the tag associated
335{-# NOINLINE encryptOCB #-}
336encryptOCB :: Byteable iv
337           => AES        -- ^ AES Context
338           -> iv         -- ^ IV initial vector of any size
339           -> ByteString -- ^ data to authenticate (AAD)
340           -> ByteString -- ^ data to encrypt
341           -> (ByteString, AuthTag) -- ^ ciphertext and tag
342encryptOCB = doOCB ocbAppendEncrypt
343
344-- | encrypt using XTS
345--
346-- the first key is the normal block encryption key
347-- the second key is used for the initial block tweak
348{-# NOINLINE encryptXTS #-}
349encryptXTS :: Byteable iv
350           => (AES,AES)  -- ^ AES cipher and tweak context
351           -> iv         -- ^ a 128 bits IV, typically a sector or a block offset in XTS
352           -> Word32     -- ^ number of rounds to skip, also seen a 16 byte offset in the sector or block.
353           -> ByteString -- ^ input to encrypt
354           -> ByteString -- ^ output encrypted
355encryptXTS = doXTS c_aes_encrypt_xts
356
357-- | decrypt using Electronic Code Book (ECB)
358{-# NOINLINE decryptECB #-}
359decryptECB :: AES -> ByteString -> ByteString
360decryptECB = doECB c_aes_decrypt_ecb
361
362-- | decrypt using Cipher block chaining (CBC)
363{-# NOINLINE decryptCBC #-}
364decryptCBC :: Byteable iv => AES -> iv -> ByteString -> ByteString
365decryptCBC = doCBC c_aes_decrypt_cbc
366
367-- | decrypt using Counter mode (CTR).
368--
369-- in CTR mode encryption and decryption is the same operation.
370decryptCTR :: Byteable iv
371           => AES        -- ^ AES Context
372           -> iv         -- ^ initial vector, usually representing a 128 bit integer
373           -> ByteString -- ^ ciphertext input
374           -> ByteString -- ^ plaintext output
375decryptCTR = encryptCTR
376
377-- | decrypt using XTS
378{-# NOINLINE decryptXTS #-}
379decryptXTS :: Byteable iv
380           => (AES,AES)  -- ^ AES cipher and tweak context
381           -> iv         -- ^ a 128 bits IV, typically a sector or a block offset in XTS
382           -> Word32     -- ^ number of rounds to skip, also seen a 16 byte offset in the sector or block.
383           -> ByteString -- ^ input to decrypt
384           -> ByteString -- ^ output decrypted
385decryptXTS = doXTS c_aes_decrypt_xts
386
387-- | decrypt using Galois Counter Mode (GCM)
388{-# NOINLINE decryptGCM #-}
389decryptGCM :: Byteable iv
390           => AES        -- ^ Key
391           -> iv         -- ^ IV initial vector of any size
392           -> ByteString -- ^ data to authenticate (AAD)
393           -> ByteString -- ^ data to decrypt
394           -> (ByteString, AuthTag) -- ^ plaintext and tag
395decryptGCM = doGCM gcmAppendDecrypt
396
397-- | decrypt using Offset Codebook Mode (OCB)
398{-# NOINLINE decryptOCB #-}
399decryptOCB :: Byteable iv
400           => AES        -- ^ Key
401           -> iv         -- ^ IV initial vector of any size
402           -> ByteString -- ^ data to authenticate (AAD)
403           -> ByteString -- ^ data to decrypt
404           -> (ByteString, AuthTag) -- ^ plaintext and tag
405decryptOCB = doOCB ocbAppendDecrypt
406
407{-# INLINE doECB #-}
408doECB :: (Ptr b -> Ptr AES -> CString -> CUInt -> IO ())
409      -> AES -> ByteString -> ByteString
410doECB f ctx input
411    | r /= 0    = error $ "Encryption error: input length must be a multiple of block size (16). Its length is: " ++ (show len)
412    | otherwise = unsafeCreate len $ \o ->
413                  keyToPtr ctx $ \k ->
414                  unsafeUseAsCString input $ \i ->
415                  f (castPtr o) k i (fromIntegral nbBlocks)
416  where (nbBlocks, r) = len `quotRem` 16
417        len           = (B.length input)
418
419{-# INLINE doCBC #-}
420doCBC :: Byteable iv
421      => (Ptr b -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ())
422      -> AES -> iv -> ByteString -> ByteString
423doCBC f ctx iv input
424    | len == 0  = B.empty
425    | byteableLength iv /= 16 = error $ "AES error: IV length must be block size (16). Its length is: " ++ (show $ byteableLength iv)
426    | r /= 0    = error $ "Encryption error: input length must be a multiple of block size (16). Its length is: " ++ (show len)
427    | otherwise = unsafeCreate len $ \o ->
428                  withKeyAndIV ctx iv $ \k v ->
429                  unsafeUseAsCString input $ \i ->
430                  f (castPtr o) k v i (fromIntegral nbBlocks)
431  where (nbBlocks, r) = len `quotRem` 16
432        len           = B.length input
433
434{-# INLINE doXTS #-}
435doXTS :: Byteable iv
436      => (Ptr b -> Ptr AES -> Ptr AES -> Ptr Word8 -> CUInt -> CString -> CUInt -> IO ())
437      -> (AES, AES)
438      -> iv
439      -> Word32
440      -> ByteString
441      -> ByteString
442doXTS f (key1,key2) iv spoint input
443    | len == 0  = B.empty
444    | r /= 0    = error $ "Encryption error: input length must be a multiple of block size (16) for now. Its length is: " ++ (show len)
445    | otherwise = unsafeCreate len $ \o -> withKey2AndIV key1 key2 iv $ \k1 k2 v -> unsafeUseAsCString input $ \i ->
446            f (castPtr o) k1 k2 v (fromIntegral spoint) i (fromIntegral nbBlocks)
447  where (nbBlocks, r) = len `quotRem` 16
448        len           = B.length input
449
450------------------------------------------------------------------------
451-- GCM
452------------------------------------------------------------------------
453
454{-# INLINE doGCM #-}
455doGCM :: Byteable iv
456      => (AES -> AESGCM -> ByteString -> (ByteString, AESGCM))
457      -> AES
458      -> iv
459      -> ByteString
460      -> ByteString
461      -> (ByteString, AuthTag)
462doGCM f ctx iv aad input = (output, tag)
463  where tag             = gcmFinish ctx after 16
464        (output, after) = f ctx afterAAD input
465        afterAAD        = gcmAppendAAD ini aad
466        ini             = gcmInit ctx iv
467
468-- | initialize a gcm context
469{-# NOINLINE gcmInit #-}
470gcmInit :: Byteable iv => AES -> iv -> AESGCM
471gcmInit ctx iv = unsafePerformIO $ do
472    sm <- createSecureMem sizeGCM $ \gcmStPtr ->
473            withKeyAndIV ctx iv $ \k v ->
474            c_aes_gcm_init (castPtr gcmStPtr) k v (fromIntegral $ byteableLength iv)
475    return $ AESGCM sm
476
477-- | append data which is going to just be authentified to the GCM context.
478--
479-- need to happen after initialization and before appending encryption/decryption data.
480{-# NOINLINE gcmAppendAAD #-}
481gcmAppendAAD :: AESGCM -> ByteString -> AESGCM
482gcmAppendAAD gcmSt input = unsafePerformIO doAppend
483  where doAppend =
484            withNewGCMSt gcmSt $ \gcmStPtr ->
485            unsafeUseAsCString input $ \i ->
486            c_aes_gcm_aad gcmStPtr i (fromIntegral $ B.length input)
487
488-- | append data to encrypt and append to the GCM context
489--
490-- bytestring need to be multiple of AES block size, unless it's the last call to this function.
491-- need to happen after AAD appending, or after initialization if no AAD data.
492{-# NOINLINE gcmAppendEncrypt #-}
493gcmAppendEncrypt :: AES -> AESGCM -> ByteString -> (ByteString, AESGCM)
494gcmAppendEncrypt ctx gcm input = unsafePerformIO $ withGCMKeyAndCopySt ctx gcm doEnc
495  where len = B.length input
496        doEnc gcmStPtr aesPtr =
497            create len $ \o ->
498            unsafeUseAsCString input $ \i ->
499            c_aes_gcm_encrypt (castPtr o) gcmStPtr aesPtr i (fromIntegral len)
500
501-- | append data to decrypt and append to the GCM context
502--
503-- bytestring need to be multiple of AES block size, unless it's the last call to this function.
504-- need to happen after AAD appending, or after initialization if no AAD data.
505{-# NOINLINE gcmAppendDecrypt #-}
506gcmAppendDecrypt :: AES -> AESGCM -> ByteString -> (ByteString, AESGCM)
507gcmAppendDecrypt ctx gcm input = unsafePerformIO $ withGCMKeyAndCopySt ctx gcm doDec
508  where len = B.length input
509        doDec gcmStPtr aesPtr =
510            create len $ \o ->
511            unsafeUseAsCString input $ \i ->
512            c_aes_gcm_decrypt (castPtr o) gcmStPtr aesPtr i (fromIntegral len)
513
514-- | Generate the Tag from GCM context
515{-# NOINLINE gcmFinish #-}
516gcmFinish :: AES -> AESGCM -> Int -> AuthTag
517gcmFinish ctx gcm taglen = AuthTag $ B.take taglen computeTag
518  where computeTag = unsafeCreate 16 $ \t ->
519                        withGCMKeyAndCopySt ctx gcm (c_aes_gcm_finish (castPtr t)) >> return ()
520
521------------------------------------------------------------------------
522-- OCB v3
523------------------------------------------------------------------------
524
525{-# INLINE doOCB #-}
526doOCB :: Byteable iv
527      => (AES -> AESOCB -> ByteString -> (ByteString, AESOCB))
528      -> AES
529      -> iv
530      -> ByteString
531      -> ByteString
532      -> (ByteString, AuthTag)
533doOCB f ctx iv aad input = (output, tag)
534  where tag             = ocbFinish ctx after 16
535        (output, after) = f ctx afterAAD input
536        afterAAD        = ocbAppendAAD ctx ini aad
537        ini             = ocbInit ctx iv
538
539-- | initialize an ocb context
540{-# NOINLINE ocbInit #-}
541ocbInit :: Byteable iv => AES -> iv -> AESOCB
542ocbInit ctx iv = unsafePerformIO $ do
543    sm <- createSecureMem sizeOCB $ \ocbStPtr ->
544            withKeyAndIV ctx iv $ \k v ->
545            c_aes_ocb_init (castPtr ocbStPtr) k v (fromIntegral $ byteableLength iv)
546    return $ AESOCB sm
547
548-- | append data which is going to just be authentified to the OCB context.
549--
550-- need to happen after initialization and before appending encryption/decryption data.
551{-# NOINLINE ocbAppendAAD #-}
552ocbAppendAAD :: AES -> AESOCB -> ByteString -> AESOCB
553ocbAppendAAD ctx ocb input = unsafePerformIO (snd `fmap` withOCBKeyAndCopySt ctx ocb doAppend)
554  where doAppend ocbStPtr aesPtr =
555            unsafeUseAsCString input $ \i ->
556            c_aes_ocb_aad ocbStPtr aesPtr i (fromIntegral $ B.length input)
557
558-- | append data to encrypt and append to the OCB context
559--
560-- bytestring need to be multiple of AES block size, unless it's the last call to this function.
561-- need to happen after AAD appending, or after initialization if no AAD data.
562{-# NOINLINE ocbAppendEncrypt #-}
563ocbAppendEncrypt :: AES -> AESOCB -> ByteString -> (ByteString, AESOCB)
564ocbAppendEncrypt ctx ocb input = unsafePerformIO $ withOCBKeyAndCopySt ctx ocb doEnc
565  where len = B.length input
566        doEnc ocbStPtr aesPtr =
567            create len $ \o ->
568            unsafeUseAsCString input $ \i ->
569            c_aes_ocb_encrypt (castPtr o) ocbStPtr aesPtr i (fromIntegral len)
570
571-- | append data to decrypt and append to the OCB context
572--
573-- bytestring need to be multiple of AES block size, unless it's the last call to this function.
574-- need to happen after AAD appending, or after initialization if no AAD data.
575{-# NOINLINE ocbAppendDecrypt #-}
576ocbAppendDecrypt :: AES -> AESOCB -> ByteString -> (ByteString, AESOCB)
577ocbAppendDecrypt ctx ocb input = unsafePerformIO $ withOCBKeyAndCopySt ctx ocb doDec
578  where len = B.length input
579        doDec ocbStPtr aesPtr =
580            create len $ \o ->
581            unsafeUseAsCString input $ \i ->
582            c_aes_ocb_decrypt (castPtr o) ocbStPtr aesPtr i (fromIntegral len)
583
584-- | Generate the Tag from OCB context
585{-# NOINLINE ocbFinish #-}
586ocbFinish :: AES -> AESOCB -> Int -> AuthTag
587ocbFinish ctx ocb taglen = AuthTag $ B.take taglen computeTag
588  where computeTag = unsafeCreate 16 $ \t ->
589                        withOCBKeyAndCopySt ctx ocb (c_aes_ocb_finish (castPtr t)) >> return ()
590
591------------------------------------------------------------------------
592foreign import ccall "aes.h aes_initkey"
593    c_aes_init :: Ptr AES -> CString -> CUInt -> IO ()
594
595------------------------------------------------------------------------
596foreign import ccall "aes.h aes_encrypt_ecb"
597    c_aes_encrypt_ecb :: CString -> Ptr AES -> CString -> CUInt -> IO ()
598
599foreign import ccall "aes.h aes_decrypt_ecb"
600    c_aes_decrypt_ecb :: CString -> Ptr AES -> CString -> CUInt -> IO ()
601
602------------------------------------------------------------------------
603foreign import ccall "aes.h aes_encrypt_cbc"
604    c_aes_encrypt_cbc :: CString -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ()
605
606foreign import ccall "aes.h aes_decrypt_cbc"
607    c_aes_decrypt_cbc :: CString -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ()
608
609------------------------------------------------------------------------
610foreign import ccall "aes.h aes_encrypt_xts"
611    c_aes_encrypt_xts :: CString -> Ptr AES -> Ptr AES -> Ptr Word8 -> CUInt -> CString -> CUInt -> IO ()
612
613foreign import ccall "aes.h aes_decrypt_xts"
614    c_aes_decrypt_xts :: CString -> Ptr AES -> Ptr AES -> Ptr Word8 -> CUInt -> CString -> CUInt -> IO ()
615
616------------------------------------------------------------------------
617foreign import ccall "aes.h aes_gen_ctr"
618    c_aes_gen_ctr :: CString -> Ptr AES -> Ptr Word8 -> CUInt -> IO ()
619
620foreign import ccall unsafe "aes.h aes_gen_ctr_cont"
621    c_aes_gen_ctr_cont :: CString -> Ptr AES -> Ptr Word8 -> CUInt -> IO ()
622
623foreign import ccall "aes.h aes_encrypt_ctr"
624    c_aes_encrypt_ctr :: CString -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ()
625
626------------------------------------------------------------------------
627foreign import ccall "aes.h aes_gcm_init"
628    c_aes_gcm_init :: Ptr AESGCM -> Ptr AES -> Ptr Word8 -> CUInt -> IO ()
629
630foreign import ccall "aes.h aes_gcm_aad"
631    c_aes_gcm_aad :: Ptr AESGCM -> CString -> CUInt -> IO ()
632
633foreign import ccall "aes.h aes_gcm_encrypt"
634    c_aes_gcm_encrypt :: CString -> Ptr AESGCM -> Ptr AES -> CString -> CUInt -> IO ()
635
636foreign import ccall "aes.h aes_gcm_decrypt"
637    c_aes_gcm_decrypt :: CString -> Ptr AESGCM -> Ptr AES -> CString -> CUInt -> IO ()
638
639foreign import ccall "aes.h aes_gcm_finish"
640    c_aes_gcm_finish :: CString -> Ptr AESGCM -> Ptr AES -> IO ()
641
642------------------------------------------------------------------------
643foreign import ccall "aes.h aes_ocb_init"
644    c_aes_ocb_init :: Ptr AESOCB -> Ptr AES -> Ptr Word8 -> CUInt -> IO ()
645
646foreign import ccall "aes.h aes_ocb_aad"
647    c_aes_ocb_aad :: Ptr AESOCB -> Ptr AES -> CString -> CUInt -> IO ()
648
649foreign import ccall "aes.h aes_ocb_encrypt"
650    c_aes_ocb_encrypt :: CString -> Ptr AESOCB -> Ptr AES -> CString -> CUInt -> IO ()
651
652foreign import ccall "aes.h aes_ocb_decrypt"
653    c_aes_ocb_decrypt :: CString -> Ptr AESOCB -> Ptr AES -> CString -> CUInt -> IO ()
654
655foreign import ccall "aes.h aes_ocb_finish"
656    c_aes_ocb_finish :: CString -> Ptr AESOCB -> Ptr AES -> IO ()
657