module Crypto.Cipher.AES128.Internal
( AESKey(..), RawKey(..)
, generateKey
, encryptECB
, decryptECB
, encryptGCM
, decryptGCM
, encryptCTR
, decryptCTR
) where
import Foreign.Ptr
import Foreign.ForeignPtr
import Foreign.Storable
import Data.Word
import Data.Bits (shiftL, (.|.))
data AESKeyStruct
type AESKeyPtr = Ptr AESKeyStruct
data RawKey = RKey { lowK,highK :: !Word64 }
data AESKey = AESKey { rawKey :: !RawKey
, expandedKey :: ForeignPtr AESKeyStruct }
foreign import ccall unsafe "aes/aes.h generate_key128"
c_generate_key128 :: AESKeyPtr -> Ptr Word8 -> IO ()
foreign import ccall unsafe "aes/aes.h allocate_key128"
c_allocate_key128 :: IO AESKeyPtr
foreign import ccall unsafe "aes/aes.h &free_key128"
c_free_key128 :: FunPtr (AESKeyPtr -> IO ())
foreign import ccall unsafe "aes/aes.h encrypt_ecb"
c_encrypt_ecb :: AESKeyPtr -> Ptr Word8 -> Ptr Word8 -> Word32 -> IO ()
foreign import ccall unsafe "aes/aes.h decrypt_ecb"
c_decrypt_ecb :: AESKeyPtr -> Ptr Word8 -> Ptr Word8 -> Word32 -> IO ()
foreign import ccall unsafe "aes/aes.h aes_gcm_full_encrypt"
c_encrypt_gcm :: AESKeyPtr
-> Ptr Word8 -> Word32
-> Ptr Word8 -> Word32
-> Ptr Word8 -> Word32
-> Ptr Word8 -> Ptr Word8
-> IO ()
foreign import ccall unsafe "aes/aes.h aes_gcm_full_decrypt"
c_decrypt_gcm :: AESKeyPtr
-> Ptr Word8 -> Word32
-> Ptr Word8 -> Word32
-> Ptr Word8 -> Word32
-> Ptr Word8 -> Ptr Word8
-> IO ()
foreign import ccall unsafe "aes/aes.h encrypt_ctr"
c_encrypt_ctr :: AESKeyPtr
-> Ptr Word8
-> Ptr Word8
-> Ptr Word8
-> Ptr Word8
-> Word32
-> IO ()
c_decrypt_ctr :: AESKeyPtr
-> Ptr Word8
-> Ptr Word8
-> Ptr Word8
-> Ptr Word8
-> Word32
-> IO ()
c_decrypt_ctr = c_encrypt_ctr
blkSzC :: Word32
blkSzC = 16
generateKey :: Ptr Word64
-> IO AESKey
generateKey keyPtr = do
k <- c_allocate_key128
c_generate_key128 k (castPtr keyPtr)
raw <- do
a <- peekLE (castPtr keyPtr)
let keyPtr2 = (castPtr keyPtr) `plusPtr` sizeOf a
b <- peekLE keyPtr2
return (RKey a b)
fmap (AESKey raw) (newForeignPtr c_free_key128 k)
where
peekLE p = do
a1 <- peekElemOff p 0
a2 <- peekElemOff p 1
a3 <- peekElemOff p 2
a4 <- peekElemOff p 3
a5 <- peekElemOff p 4
a6 <- peekElemOff p 5
a7 <- peekElemOff p 6
a8 <- peekElemOff p 7
let a = (a1 `shiftL` 56) .|. (a2 `shiftL` 48) .|. (a3 `shiftL` 40) .|.
(a4 `shiftL` 32) .|. (a5 `shiftL` 24) .|. (a6 `shiftL` 16) .|.
(a7 `shiftL` 8) .|. a8
return a
encryptECB :: AESKey
-> Ptr Word8
-> Ptr Word8
-> Int
-> IO ()
encryptECB (AESKey _ k) dst src blks = withForeignPtr k $ \p -> c_encrypt_ecb p dst src (fromIntegral blks)
decryptECB :: AESKey
-> Ptr Word8
-> Ptr Word8
-> Int
-> IO ()
decryptECB (AESKey _ k) dst src blks
| blks > fromIntegral (maxBound `div` blkSzC :: Word32) = error "Can not decrypt so many blocks at once"
| otherwise = withForeignPtr k $ \p -> c_decrypt_ecb p dst src (fromIntegral blks)
encryptGCM :: AESKey
-> Ptr Word8 -> Int
-> Ptr Word8 -> Int
-> Ptr Word8 -> Int
-> Ptr Word8
-> Ptr Word8
-> IO ()
encryptGCM (AESKey _ k) iv ivLen aad aadLen pt ptLen ct tag = withForeignPtr k $ \p -> do
c_encrypt_gcm p iv (fromIntegral ivLen) aad (fromIntegral aadLen) pt (fromIntegral ptLen) ct tag
decryptGCM :: AESKey
-> Ptr Word8 -> Int
-> Ptr Word8 -> Int
-> Ptr Word8 -> Int
-> Ptr Word8
-> Ptr Word8
-> IO ()
decryptGCM (AESKey _ k) iv ivLen aad aadLen ct ctLen pt tag = withForeignPtr k $ \p -> do
c_decrypt_gcm p iv (fromIntegral ivLen) aad (fromIntegral aadLen) ct (fromIntegral ctLen) pt tag
encryptCTR :: AESKey
-> Ptr Word8
-> Ptr Word8
-> Ptr Word8
-> Ptr Word8
-> Int
-> IO ()
encryptCTR (AESKey _ k) iv niv ct pt len = withForeignPtr k $ \p -> do
c_encrypt_ctr p iv niv ct pt (fromIntegral len)
decryptCTR :: AESKey
-> Ptr Word8
-> Ptr Word8
-> Ptr Word8
-> Ptr Word8
-> Int
-> IO ()
decryptCTR (AESKey _ k) iv niv ct pt len = withForeignPtr k $ \p -> do
c_decrypt_ctr p iv niv ct pt (fromIntegral len)