{-# INCLUDE "HsOpenSSL.h" #-}{-# INCLUDE "openssl/aes.h" #-}{-# LINE 1 "OpenSSL/Cipher.hsc" #-}{-# LINE 2 "OpenSSL/Cipher.hsc" #-}{-# LINE 3 "OpenSSL/Cipher.hsc" #-}-- | This module interfaces to some of the OpenSSL ciphers without using-- EVP (see OpenSSL.EVP.Cipher). The EVP ciphers are easier to use,-- however, in some cases you cannot do without using the OpenSSL-- fuctions directly.---- One of these cases (and the motivating example-- for this module) is that the EVP CBC functions try to encode the-- length of the input string in the output (thus hiding the fact that the-- cipher is, in fact, block based and needs padding). This means that the-- EVP CBC functions cannot, in some cases, interface with other users-- which don't use that system (like SSH).moduleOpenSSL.Cipher(Mode(..),AESCtx,newAESCtx,aesCBC,aesCTR)whereimportControl.Monad(when)importData.IORefimportForeignimportForeign.C.TypesimportqualifiedData.ByteStringasBSimportqualifiedData.ByteString.InternalasBSIimportOpenSSL.UtilsdataMode=Encrypt|Decryptderiving(Eq,Show)modeToInt::Numa=>Mode->amodeToIntEncrypt=1modeToIntDecrypt=0dataAES_KEYdataAESCtx=AESCtx(ForeignPtrAES_KEY)-- the key schedule(ForeignPtrCUChar)-- the IV / counter(ForeignPtrCUChar)-- the encrypted counter (CTR mode)(IORefCUInt)-- the number of bytes of the encrypted counter usedModeforeignimportccallunsafe"memcpy"_memcpy::PtrCUChar->PtrCChar->CSize->IO()foreignimportccallunsafe"memset"_memset::PtrCUChar->CChar->CSize->IO()foreignimportccallunsafe"AES_set_encrypt_key"_AES_set_encrypt_key::PtrCChar->CInt->PtrAES_KEY->IOCIntforeignimportccallunsafe"AES_set_decrypt_key"_AES_set_decrypt_key::PtrCChar->CInt->PtrAES_KEY->IOCIntforeignimportccallunsafe"AES_cbc_encrypt"_AES_cbc_encrypt::PtrCChar->PtrWord8->CULong->PtrAES_KEY->PtrCUChar->CInt->IO()foreignimportccallunsafe"AES_ctr128_encrypt"_AES_ctr_encrypt::PtrCChar->PtrWord8->CULong->PtrAES_KEY->PtrCUChar->PtrCUChar->PtrCUInt->IO()foreignimportccallunsafe"&free"_free::FunPtr(Ptra->IO())-- | Construct a new context which holds the key schedule and IV.newAESCtx::Mode-- ^ For CTR mode, this must always be Encrypt->BS.ByteString-- ^ Key: 128, 192 or 256 bits long->BS.ByteString-- ^ IV: 16 bytes long->IOAESCtxnewAESCtxmodekeyiv=doletkeyLen=BS.lengthkey*8when(not$any((==)keyLen)[128,192,256])$fail"Bad AES key length"when(BS.lengthiv/=16)$fail"Bad AES128 iv length"ctx<-mallocForeignPtrBytes((244)){-# LINE 75 "OpenSSL/Cipher.hsc" #-}withForeignPtrctx$\ctxPtr->BS.useAsCStringLenkey(\(ptr,_)->casemodeofEncrypt->_AES_set_encrypt_keyptr(fromIntegralkeyLen)ctxPtr>>=failIf(/=0)Decrypt->_AES_set_decrypt_keyptr(fromIntegralkeyLen)ctxPtr>>=failIf(/=0))ivbytes<-mallocForeignPtrBytes16ecounter<-mallocForeignPtrBytes16nref<-newIORef0withForeignPtrecounter(\ecptr->_memsetecptr016)withForeignPtrivbytes$\ivPtr->BS.useAsCStringLeniv$\(ptr,_)->do_memcpyivPtrptr16return$AESCtxctxivbytesecounternrefmode-- | Encrypt some number of blocks using CBC. This is an IO function because-- the context is destructivly updated.aesCBC::AESCtx-- ^ context->BS.ByteString-- ^ input, must be multiple of block size (16 bytes)->IOBS.ByteStringaesCBC(AESCtxctxiv__mode)input=dowhen(BS.lengthinput`mod`16/=0)$fail"Bad input length to aesCBC"withForeignPtrctx$\ctxPtr->withForeignPtriv$\ivPtr->BS.useAsCStringLeninput$\(ptr,len)->BSI.create(BS.lengthinput)$\out->_AES_cbc_encryptptrout(fromIntegrallen)ctxPtrivPtr$modeToIntmode-- | Encrypt some number of bytes using CTR mode. This is an IO function-- because the context is destructivly updated.aesCTR::AESCtx-- ^ context->BS.ByteString-- ^ input, any number of bytes->IOBS.ByteStringaesCTR(AESCtx____Decrypt)_=fail"the context mode must be Encrypt"aesCTR(AESCtxctxivecounternrefEncrypt)input=dowithForeignPtrctx$\ctxPtr->withForeignPtriv$\ivPtr->withForeignPtrecounter$\ecptr->BS.useAsCStringLeninput$\(ptr,len)->BSI.create(BS.lengthinput)$\out->alloca$\nptr->don<-readIORefnrefpokenptrn_AES_ctr_encryptptrout(fromIntegrallen)ctxPtrivPtrecptrnptrn'<-peeknptrwriteIORefnrefn'