module Crypto.Cipher.AES128
( AESKey128, AESKey192, AESKey256
, BlockCipher(..), buildKeyIO, zeroIV
) where
import Crypto.Cipher.AES128.Internal
import Crypto.Classes
import Control.Monad (when)
import Data.Serialize
import Data.Tagged
import Foreign.Ptr
import Foreign.ForeignPtr
import System.IO.Unsafe
import qualified Data.ByteString as B
import qualified Data.ByteString.Internal as B
import qualified Data.ByteString.Unsafe as B
instance Serialize AESKey128 where
put k = do
let RKey128 l h = (rawKey128 k)
putWord64be h
putWord64be l
get = do
b <- getByteString 16
case buildKey b of
Nothing -> fail "Invalid key on 'get'"
Just k -> return k
instance Serialize AESKey192 where
put k = do
let RKey192 a b c = (rawKey192 k)
putWord64be c
putWord64be b
putWord64be a
get = do
b <- getByteString 24
case buildKey b of
Nothing -> fail "Invalid key on 'get'"
Just k -> return k
instance Serialize AESKey256 where
put k = do
let RKey256 a b c d = (rawKey256 k)
putWord64be d
putWord64be c
putWord64be b
putWord64be a
get = do
b <- getByteString 32
case buildKey b of
Nothing -> fail "Invalid key on 'get'"
Just k -> return k
instance BlockCipher AESKey128 where
blockSize = Tagged 128
keyLength = Tagged 128
buildKey bs
| B.length bs >= 16 = unsafePerformIO $
B.unsafeUseAsCString bs (\p -> generateKey128 (castPtr p))
| otherwise = Nothing
encryptBlock k b = unsafePerformIO $ do
B.unsafeUseAsCStringLen b $ \(inP,len) -> do
B.create (B.length b) $ \outP -> do
encryptECB k (castPtr outP) (castPtr inP) (len`div`blkSize)
decryptBlock k b = unsafePerformIO $ do
B.unsafeUseAsCStringLen b $ \(inP,len) -> do
B.create (B.length b) $ \outP -> do
decryptECB k (castPtr outP) (castPtr inP) (len`div`blkSize)
ecb = encryptBlock
unEcb = decryptBlock
ctr k (IV bs) pt = unsafePerformIO $ do
B.unsafeUseAsCStringLen pt $ \(inP, len) -> do
B.unsafeUseAsCStringLen bs $ \(ivP, ivLen) -> do
when (ivLen /= (blockSizeBytes .::. k))
(error "Cipher-AES128: IV wrong length! They type system would have/should have caught this if you didn't use the IV constructor...")
newIVFP <- B.mallocByteString ivLen
ct <- B.create len $ \outP -> withForeignPtr newIVFP $ \newIVP -> do
encryptCTR k (castPtr ivP) (castPtr newIVP) (castPtr outP) (castPtr inP) len
let newIV = B.fromForeignPtr newIVFP 0 ivLen
return (ct,IV newIV)
unCtr = ctr
blkSize :: Int
blkSize = 16
instance BlockCipher AESKey192 where
blockSize = Tagged 128
keyLength = Tagged 192
buildKey bs
| B.length bs >= 16 = unsafePerformIO $
B.unsafeUseAsCString bs (\p -> generateKey192 (castPtr p))
| otherwise = Nothing
encryptBlock k b = unsafePerformIO $ do
B.unsafeUseAsCStringLen b $ \(inP,len) -> do
B.create (B.length b) $ \outP -> do
encryptECB k (castPtr outP) (castPtr inP) (len`div`blkSize)
decryptBlock k b = unsafePerformIO $ do
B.unsafeUseAsCStringLen b $ \(inP,len) -> do
B.create (B.length b) $ \outP -> do
decryptECB k (castPtr outP) (castPtr inP) (len`div`blkSize)
ecb = encryptBlock
unEcb = decryptBlock
ctr k (IV bs) pt = unsafePerformIO $ do
B.unsafeUseAsCStringLen pt $ \(inP, len) -> do
B.unsafeUseAsCStringLen bs $ \(ivP, ivLen) -> do
when (ivLen /= (blockSizeBytes .::. k))
(error "Cipher-AES128: IV wrong length! They type system would have/should have caught this if you didn't use the IV constructor...")
newIVFP <- B.mallocByteString ivLen
ct <- B.create len $ \outP -> withForeignPtr newIVFP $ \newIVP -> do
encryptCTR k (castPtr ivP) (castPtr newIVP) (castPtr outP) (castPtr inP) len
let newIV = B.fromForeignPtr newIVFP 0 ivLen
return (ct,IV newIV)
unCtr = ctr
instance BlockCipher AESKey256 where
blockSize = Tagged 128
keyLength = Tagged 256
buildKey bs
| B.length bs >= 16 = unsafePerformIO $
B.unsafeUseAsCString bs (\p -> generateKey256 (castPtr p))
| otherwise = Nothing
encryptBlock k b = unsafePerformIO $ do
B.unsafeUseAsCStringLen b $ \(inP,len) -> do
B.create (B.length b) $ \outP -> do
encryptECB k (castPtr outP) (castPtr inP) (len`div`blkSize)
decryptBlock k b = unsafePerformIO $ do
B.unsafeUseAsCStringLen b $ \(inP,len) -> do
B.create (B.length b) $ \outP -> do
decryptECB k (castPtr outP) (castPtr inP) (len`div`blkSize)
ecb = encryptBlock
unEcb = decryptBlock
ctr k (IV bs) pt = unsafePerformIO $ do
B.unsafeUseAsCStringLen pt $ \(inP, len) -> do
B.unsafeUseAsCStringLen bs $ \(ivP, ivLen) -> do
when (ivLen /= (blockSizeBytes .::. k))
(error "Cipher-AES128: IV wrong length! They type system would have/should have caught this if you didn't use the IV constructor...")
newIVFP <- B.mallocByteString ivLen
ct <- B.create len $ \outP -> withForeignPtr newIVFP $ \newIVP -> do
encryptCTR k (castPtr ivP) (castPtr newIVP) (castPtr outP) (castPtr inP) len
let newIV = B.fromForeignPtr newIVFP 0 ivLen
return (ct,IV newIV)
unCtr = ctr