module Network.TLS.Cipher
( CipherTypeFunctions(..)
, CipherKeyExchangeType(..)
, Cipher(..)
, cipherExchangeNeedMoreData
, cipher_null_null
, cipher_RC4_128_MD5
, cipher_RC4_128_SHA1
, cipher_AES128_SHA1
, cipher_AES256_SHA1
, cipher_AES128_SHA256
, cipher_AES256_SHA256
) where
import Data.Word
import Network.TLS.Struct (Version(..))
import Network.TLS.MAC
import qualified Data.Vector.Unboxed as Vector (fromList, toList)
import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString as B
import qualified Codec.Crypto.AES as AES
import qualified Crypto.Cipher.RC4 as RC4
type Key = B.ByteString
type IV = B.ByteString
data CipherTypeFunctions =
CipherNoneF
| CipherBlockF (Key -> IV -> B.ByteString -> B.ByteString)
(Key -> IV -> B.ByteString -> B.ByteString)
| CipherStreamF (Key -> IV)
(IV -> B.ByteString -> (B.ByteString, IV))
(IV -> B.ByteString -> (B.ByteString, IV))
data CipherKeyExchangeType =
CipherKeyExchangeRSA
| CipherKeyExchangeDHE_RSA
| CipherKeyExchangeECDHE_RSA
| CipherKeyExchangeDHE_DSS
| CipherKeyExchangeDH_DSS
| CipherKeyExchangeDH_RSA
| CipherKeyExchangeECDH_ECDSA
| CipherKeyExchangeECDH_RSA
| CipherKeyExchangeECDHE_ECDSA
data Cipher = Cipher
{ cipherID :: Word16
, cipherName :: String
, cipherDigestSize :: Word8
, cipherKeySize :: Word8
, cipherIVSize :: Word8
, cipherKeyBlockSize :: Word8
, cipherPaddingSize :: Word8
, cipherKeyExchange :: CipherKeyExchangeType
, cipherHMAC :: B.ByteString -> B.ByteString -> B.ByteString
, cipherF :: CipherTypeFunctions
, cipherMinVer :: Maybe Version
}
instance Show Cipher where
show c = cipherName c
cipherExchangeNeedMoreData :: CipherKeyExchangeType -> Bool
cipherExchangeNeedMoreData CipherKeyExchangeRSA = False
cipherExchangeNeedMoreData CipherKeyExchangeDHE_RSA = True
cipherExchangeNeedMoreData CipherKeyExchangeECDHE_RSA = True
cipherExchangeNeedMoreData CipherKeyExchangeDHE_DSS = True
cipherExchangeNeedMoreData CipherKeyExchangeDH_DSS = False
cipherExchangeNeedMoreData CipherKeyExchangeDH_RSA = False
cipherExchangeNeedMoreData CipherKeyExchangeECDH_ECDSA = True
cipherExchangeNeedMoreData CipherKeyExchangeECDH_RSA = True
cipherExchangeNeedMoreData CipherKeyExchangeECDHE_ECDSA = True
repack :: Int -> B.ByteString -> [B.ByteString]
repack bs x =
if B.length x > bs
then
let (c1, c2) = B.splitAt bs x in
B.pack (B.unpack c1) : repack 16 c2
else
[ x ]
lazyToStrict :: L.ByteString -> B.ByteString
lazyToStrict = B.concat . L.toChunks
aes128_cbc_encrypt :: Key -> IV -> B.ByteString -> B.ByteString
aes128_cbc_encrypt key iv d = lazyToStrict $ AES.crypt AES.CBC key iv AES.Encrypt d16
where d16 = L.fromChunks $ repack 16 d
aes128_cbc_decrypt :: Key -> IV -> B.ByteString -> B.ByteString
aes128_cbc_decrypt key iv d = lazyToStrict $ AES.crypt AES.CBC key iv AES.Decrypt d16
where d16 = L.fromChunks $ repack 16 d
aes256_cbc_encrypt :: Key -> IV -> B.ByteString -> B.ByteString
aes256_cbc_encrypt key iv d = lazyToStrict $ AES.crypt AES.CBC key iv AES.Encrypt d16
where d16 = L.fromChunks $ repack 16 d
aes256_cbc_decrypt :: Key -> IV -> B.ByteString -> B.ByteString
aes256_cbc_decrypt key iv d = lazyToStrict $ AES.crypt AES.CBC key iv AES.Decrypt d16
where d16 = L.fromChunks $ repack 32 d
toIV :: RC4.Ctx -> IV
toIV (v, x, y) = B.pack (x : y : Vector.toList v)
toCtx :: IV -> RC4.Ctx
toCtx iv =
case B.unpack iv of
x:y:l -> (Vector.fromList l, x, y)
_ -> (Vector.fromList [], 0, 0)
initF_rc4 :: Key -> IV
initF_rc4 key = toIV $ RC4.initCtx (B.unpack key)
encryptF_rc4 :: IV -> B.ByteString -> (B.ByteString, IV)
encryptF_rc4 iv d = (\(ctx, e) -> (e, toIV ctx)) $ RC4.encrypt (toCtx iv) d
decryptF_rc4 :: IV -> B.ByteString -> (B.ByteString, IV)
decryptF_rc4 iv e = (\(ctx, d) -> (d, toIV ctx)) $ RC4.decrypt (toCtx iv) e
cipher_null_null :: Cipher
cipher_null_null = Cipher
{ cipherID = 0x0
, cipherName = "null-null"
, cipherDigestSize = 0
, cipherKeySize = 0
, cipherIVSize = 0
, cipherKeyBlockSize = 0
, cipherPaddingSize = 0
, cipherHMAC = (\_ _ -> B.empty)
, cipherKeyExchange = CipherKeyExchangeRSA
, cipherF = CipherNoneF
, cipherMinVer = Nothing
}
cipher_RC4_128_MD5 :: Cipher
cipher_RC4_128_MD5 = Cipher
{ cipherID = 0x04
, cipherName = "RSA-rc4-128-md5"
, cipherDigestSize = 16
, cipherKeySize = 16
, cipherIVSize = 0
, cipherKeyBlockSize = 2 * (16 + 16 + 0)
, cipherPaddingSize = 0
, cipherHMAC = hmacMD5
, cipherKeyExchange = CipherKeyExchangeRSA
, cipherF = CipherStreamF initF_rc4 encryptF_rc4 decryptF_rc4
, cipherMinVer = Nothing
}
cipher_RC4_128_SHA1 :: Cipher
cipher_RC4_128_SHA1 = Cipher
{ cipherID = 0x05
, cipherName = "RSA-rc4-128-sha1"
, cipherDigestSize = 20
, cipherKeySize = 16
, cipherIVSize = 0
, cipherKeyBlockSize = 2 * (20 + 16 + 0)
, cipherPaddingSize = 0
, cipherHMAC = hmacSHA1
, cipherKeyExchange = CipherKeyExchangeRSA
, cipherF = CipherStreamF initF_rc4 encryptF_rc4 decryptF_rc4
, cipherMinVer = Nothing
}
cipher_AES128_SHA1 :: Cipher
cipher_AES128_SHA1 = Cipher
{ cipherID = 0x2f
, cipherName = "RSA-aes128-sha1"
, cipherDigestSize = 20
, cipherKeySize = 16
, cipherIVSize = 16
, cipherKeyBlockSize = 2 * (20 + 16 + 16)
, cipherPaddingSize = 16
, cipherHMAC = hmacSHA1
, cipherKeyExchange = CipherKeyExchangeRSA
, cipherF = CipherBlockF aes128_cbc_encrypt aes128_cbc_decrypt
, cipherMinVer = Just SSL3
}
cipher_AES256_SHA1 :: Cipher
cipher_AES256_SHA1 = Cipher
{ cipherID = 0x35
, cipherName = "RSA-aes256-sha1"
, cipherDigestSize = 20
, cipherKeySize = 32
, cipherIVSize = 16
, cipherKeyBlockSize = 2 * (20 + 32 + 16)
, cipherPaddingSize = 16
, cipherHMAC = hmacSHA1
, cipherKeyExchange = CipherKeyExchangeRSA
, cipherF = CipherBlockF aes256_cbc_encrypt aes256_cbc_decrypt
, cipherMinVer = Just SSL3
}
cipher_AES128_SHA256 :: Cipher
cipher_AES128_SHA256 = Cipher
{ cipherID = 0x3c
, cipherName = "RSA-aes128-sha256"
, cipherDigestSize = 32
, cipherKeySize = 16
, cipherIVSize = 16
, cipherKeyBlockSize = 2 * (32 + 16 + 16)
, cipherPaddingSize = 16
, cipherHMAC = hmacSHA256
, cipherKeyExchange = CipherKeyExchangeRSA
, cipherF = CipherBlockF aes128_cbc_encrypt aes128_cbc_decrypt
, cipherMinVer = Just TLS12
}
cipher_AES256_SHA256 :: Cipher
cipher_AES256_SHA256 = Cipher
{ cipherID = 0x3d
, cipherName = "RSA-aes256-sha256"
, cipherDigestSize = 32
, cipherKeySize = 32
, cipherIVSize = 16
, cipherKeyBlockSize = 2 * (32 + 32 + 16)
, cipherPaddingSize = 16
, cipherHMAC = hmacSHA256
, cipherKeyExchange = CipherKeyExchangeRSA
, cipherF = CipherBlockF aes256_cbc_encrypt aes256_cbc_decrypt
, cipherMinVer = Just TLS12
}