{-# LANGUAGE CPP, MultiParamTypeClasses, FlexibleInstances, FlexibleContexts #-}
module Crypto.Nettle.Ciphers (
AES
, AES128
, AES192
, AES256
, ARCTWO
, arctwoInitEKB
, arctwoInitGutmann
, BLOWFISH
, Camellia
, Camellia128
, Camellia192
, Camellia256
, CAST128
, DES
, DES_EDE3
, TWOFISH
, SERPENT
, StreamNonceCipher(..)
, streamSetNonceWord64
, ARCFOUR
, CHACHA
, SALSA20
, ESTREAM_SALSA20
) where
import Crypto.Cipher.Types
import Crypto.Nettle.CCM
import Data.SecureMem
import qualified Data.ByteString as B
import Data.Word (Word64)
import Data.Bits
import Data.Tagged
import Crypto.Nettle.Ciphers.Internal
import Crypto.Nettle.Ciphers.ForeignImports
import Nettle.Utils
{-# ANN module "HLint: ignore Use camelCase" #-}
#define INSTANCE_CIPHER(Typ) \
instance Cipher Typ where \
{ cipherInit = nettle_cipherInit \
; cipherName = witness nc_cipherName \
; cipherKeySize = witness nc_cipherKeySize \
}
#define INSTANCE_BLOCKCIPHER(Typ) \
INSTANCE_CIPHER(Typ); \
instance BlockCipher Typ where \
{ blockSize = witness nbc_blockSize \
; ecbEncrypt = nettle_ecbEncrypt \
; ecbDecrypt = nettle_ecbDecrypt \
; cbcEncrypt = nettle_cbcEncrypt \
; cbcDecrypt = nettle_cbcDecrypt \
; cfbEncrypt = nettle_cfbEncrypt \
; cfbDecrypt = nettle_cfbDecrypt \
; ctrCombine = nettle_ctrCombine \
; aeadInit AEAD_GCM = nettle_gcm_aeadInit \
; aeadInit AEAD_CCM = ccmInitTLS \
; aeadInit _ = \_ _ -> Nothing \
} ; \
instance AEADModeImpl Typ NettleGCM where \
{ aeadStateAppendHeader = nettle_gcm_aeadStateAppendHeader \
; aeadStateEncrypt = nettle_gcm_aeadStateEncrypt \
; aeadStateDecrypt = nettle_gcm_aeadStateDecrypt \
; aeadStateFinalize = nettle_gcm_aeadStateFinalize \
}
#define INSTANCE_STREAMCIPHER(Typ) \
INSTANCE_CIPHER(Typ); \
instance StreamCipher Typ where \
{ streamCombine = nettle_streamCombine \
}
#define INSTANCE_STREAMNONCECIPHER(Typ) \
INSTANCE_STREAMCIPHER(Typ); \
instance StreamNonceCipher Typ where \
{ streamSetNonce = nettle_streamSetNonce \
; streamNonceSize = witness nsc_nonceSize \
}
#define INSTANCE_BLOCKEDSTREAMCIPHER(Typ) \
INSTANCE_CIPHER(Typ); \
instance StreamCipher Typ where \
{ streamCombine = nettle_blockedStreamCombine \
}
#define INSTANCE_BLOCKEDSTREAMNONCECIPHER(Typ) \
INSTANCE_BLOCKEDSTREAMCIPHER(Typ); \
instance StreamNonceCipher Typ where \
{ streamSetNonce = nettle_blockedStreamSetNonce \
; streamNonceSize = witness nbsc_nonceSize \
}
newtype AES = AES SecureMem
instance NettleCipher AES where
nc_cipherInit = Tagged c_hs_aes_init
nc_cipherName = Tagged "AES"
nc_cipherKeySize = Tagged $ KeySizeEnum [16,24,32]
nc_ctx_size = Tagged c_hs_aes_ctx_size
nc_ctx (AES c) = c
nc_Ctx = AES
instance NettleBlockCipher AES where
nbc_blockSize = Tagged 16
nbc_ecb_encrypt = Tagged c_hs_aes_encrypt
nbc_ecb_decrypt = Tagged c_hs_aes_decrypt
nbc_fun_encrypt = Tagged p_hs_aes_encrypt
nbc_fun_decrypt = Tagged p_hs_aes_decrypt
INSTANCE_BLOCKCIPHER(AES)
newtype AES128 = AES128 SecureMem
instance NettleCipher AES128 where
nc_cipherInit = Tagged (\ctx _ key -> c_hs_aes128_init ctx key)
nc_cipherName = Tagged "AES-128"
nc_cipherKeySize = Tagged $ KeySizeFixed 16
nc_ctx_size = Tagged c_hs_aes128_ctx_size
nc_ctx (AES128 c) = c
nc_Ctx = AES128
instance NettleBlockCipher AES128 where
nbc_blockSize = Tagged 16
nbc_encrypt_ctx_offset = Tagged c_hs_aes128_ctx_encrypt
nbc_decrypt_ctx_offset = Tagged c_hs_aes128_ctx_decrypt
nbc_ecb_encrypt = Tagged c_aes128_encrypt
nbc_ecb_decrypt = Tagged c_aes128_decrypt
nbc_fun_encrypt = Tagged p_aes128_encrypt
nbc_fun_decrypt = Tagged p_aes128_decrypt
INSTANCE_BLOCKCIPHER(AES128)
newtype AES192 = AES192 SecureMem
instance NettleCipher AES192 where
nc_cipherInit = Tagged (\ctx _ key -> c_hs_aes192_init ctx key)
nc_cipherName = Tagged "AES-192"
nc_cipherKeySize = Tagged $ KeySizeFixed 24
nc_ctx_size = Tagged c_hs_aes192_ctx_size
nc_ctx (AES192 c) = c
nc_Ctx = AES192
instance NettleBlockCipher AES192 where
nbc_blockSize = Tagged 16
nbc_encrypt_ctx_offset = Tagged c_hs_aes192_ctx_encrypt
nbc_decrypt_ctx_offset = Tagged c_hs_aes192_ctx_decrypt
nbc_ecb_encrypt = Tagged c_aes192_encrypt
nbc_ecb_decrypt = Tagged c_aes192_decrypt
nbc_fun_encrypt = Tagged p_aes192_encrypt
nbc_fun_decrypt = Tagged p_aes192_decrypt
INSTANCE_BLOCKCIPHER(AES192)
newtype AES256 = AES256 SecureMem
instance NettleCipher AES256 where
nc_cipherInit = Tagged (\ctx _ key -> c_hs_aes256_init ctx key)
nc_cipherName = Tagged "AES-256"
nc_cipherKeySize = Tagged $ KeySizeFixed 32
nc_ctx_size = Tagged c_hs_aes256_ctx_size
nc_ctx (AES256 c) = c
nc_Ctx = AES256
instance NettleBlockCipher AES256 where
nbc_blockSize = Tagged 16
nbc_encrypt_ctx_offset = Tagged c_hs_aes256_ctx_encrypt
nbc_decrypt_ctx_offset = Tagged c_hs_aes256_ctx_decrypt
nbc_ecb_encrypt = Tagged c_aes256_encrypt
nbc_ecb_decrypt = Tagged c_aes256_decrypt
nbc_fun_encrypt = Tagged p_aes256_encrypt
nbc_fun_decrypt = Tagged p_aes256_decrypt
INSTANCE_BLOCKCIPHER(AES256)
newtype ARCTWO = ARCTWO SecureMem
instance NettleCipher ARCTWO where
nc_cipherInit = Tagged c_arctwo_set_key
nc_cipherName = Tagged "ARCTWO"
nc_cipherKeySize = Tagged $ KeySizeRange 1 128
nc_ctx_size = Tagged c_arctwo_ctx_size
nc_ctx (ARCTWO c) = c
nc_Ctx = ARCTWO
instance NettleBlockCipher ARCTWO where
nbc_blockSize = Tagged 8
nbc_ecb_encrypt = Tagged c_arctwo_encrypt
nbc_ecb_decrypt = Tagged c_arctwo_decrypt
nbc_fun_encrypt = Tagged p_arctwo_encrypt
nbc_fun_decrypt = Tagged p_arctwo_decrypt
INSTANCE_BLOCKCIPHER(ARCTWO)
arctwoInitEKB :: Key ARCTWO -> Word -> ARCTWO
arctwoInitEKB k ekb = nettle_cipherInit' initfun k where
initfun ctxptr ksize ptr = c_arctwo_set_key_ekb ctxptr ksize ptr ekb
arctwoInitGutmann :: Key ARCTWO -> ARCTWO
arctwoInitGutmann = nettle_cipherInit' c_arctwo_set_key_gutmann
newtype BLOWFISH = BLOWFISH SecureMem
instance NettleCipher BLOWFISH where
nc_cipherInit = Tagged c_blowfish_set_key
nc_cipherName = Tagged "BLOWFISH"
nc_cipherKeySize = Tagged $ KeySizeRange 1 128
nc_ctx_size = Tagged c_blowfish_ctx_size
nc_ctx (BLOWFISH c) = c
nc_Ctx = BLOWFISH
instance NettleBlockCipher BLOWFISH where
nbc_blockSize = Tagged 8
nbc_ecb_encrypt = Tagged c_blowfish_encrypt
nbc_ecb_decrypt = Tagged c_blowfish_decrypt
nbc_fun_encrypt = Tagged p_blowfish_encrypt
nbc_fun_decrypt = Tagged p_blowfish_decrypt
INSTANCE_BLOCKCIPHER(BLOWFISH)
newtype Camellia = Camellia SecureMem
instance NettleCipher Camellia where
nc_cipherInit = Tagged c_hs_camellia_init
nc_cipherName = Tagged "Camellia"
nc_cipherKeySize = Tagged $ KeySizeEnum [16,24,32]
nc_ctx_size = Tagged c_hs_camellia_ctx_size
nc_ctx (Camellia c) = c
nc_Ctx = Camellia
instance NettleBlockCipher Camellia where
nbc_blockSize = Tagged 16
nbc_ecb_encrypt = Tagged c_hs_camellia_encrypt
nbc_ecb_decrypt = Tagged c_hs_camellia_decrypt
nbc_fun_encrypt = Tagged p_hs_camellia_encrypt
nbc_fun_decrypt = Tagged p_hs_camellia_decrypt
INSTANCE_BLOCKCIPHER(Camellia)
newtype Camellia128 = Camellia128 SecureMem
instance NettleCipher Camellia128 where
nc_cipherInit = Tagged (\ctx _ key -> c_hs_camellia128_init ctx key)
nc_cipherName = Tagged "Camellia-128"
nc_cipherKeySize = Tagged $ KeySizeFixed 16
nc_ctx_size = Tagged c_hs_camellia128_ctx_size
nc_ctx (Camellia128 c) = c
nc_Ctx = Camellia128
instance NettleBlockCipher Camellia128 where
nbc_blockSize = Tagged 16
nbc_encrypt_ctx_offset = Tagged c_hs_camellia128_ctx_encrypt
nbc_decrypt_ctx_offset = Tagged c_hs_camellia128_ctx_decrypt
nbc_ecb_encrypt = Tagged c_camellia128_crypt
nbc_ecb_decrypt = Tagged c_camellia128_crypt
nbc_fun_encrypt = Tagged p_camellia128_crypt
nbc_fun_decrypt = Tagged p_camellia128_crypt
INSTANCE_BLOCKCIPHER(Camellia128)
newtype Camellia192 = Camellia192 SecureMem
instance NettleCipher Camellia192 where
nc_cipherInit = Tagged (\ctx _ key -> c_hs_camellia192_init ctx key)
nc_cipherName = Tagged "Camellia-192"
nc_cipherKeySize = Tagged $ KeySizeFixed 24
nc_ctx_size = Tagged c_hs_camellia192_ctx_size
nc_ctx (Camellia192 c) = c
nc_Ctx = Camellia192
instance NettleBlockCipher Camellia192 where
nbc_blockSize = Tagged 16
nbc_encrypt_ctx_offset = Tagged c_hs_camellia192_ctx_encrypt
nbc_decrypt_ctx_offset = Tagged c_hs_camellia192_ctx_decrypt
nbc_ecb_encrypt = Tagged c_camellia192_crypt
nbc_ecb_decrypt = Tagged c_camellia192_crypt
nbc_fun_encrypt = Tagged p_camellia192_crypt
nbc_fun_decrypt = Tagged p_camellia192_crypt
INSTANCE_BLOCKCIPHER(Camellia192)
newtype Camellia256 = Camellia256 SecureMem
instance NettleCipher Camellia256 where
nc_cipherInit = Tagged (\ctx _ key -> c_hs_camellia256_init ctx key)
nc_cipherName = Tagged "Camellia-256"
nc_cipherKeySize = Tagged $ KeySizeFixed 32
nc_ctx_size = Tagged c_hs_camellia256_ctx_size
nc_ctx (Camellia256 c) = c
nc_Ctx = Camellia256
instance NettleBlockCipher Camellia256 where
nbc_blockSize = Tagged 16
nbc_encrypt_ctx_offset = Tagged c_hs_camellia256_ctx_encrypt
nbc_decrypt_ctx_offset = Tagged c_hs_camellia256_ctx_decrypt
nbc_ecb_encrypt = Tagged c_camellia256_crypt
nbc_ecb_decrypt = Tagged c_camellia256_crypt
nbc_fun_encrypt = Tagged p_camellia256_crypt
nbc_fun_decrypt = Tagged p_camellia256_crypt
INSTANCE_BLOCKCIPHER(Camellia256)
newtype CAST128 = CAST128 SecureMem
instance NettleCipher CAST128 where
nc_cipherInit = Tagged c_cast5_set_key
nc_cipherName = Tagged "CAST-128"
nc_cipherKeySize = Tagged $ KeySizeRange 5 16
nc_ctx_size = Tagged c_cast128_ctx_size
nc_ctx (CAST128 c) = c
nc_Ctx = CAST128
instance NettleBlockCipher CAST128 where
nbc_blockSize = Tagged 8
nbc_ecb_encrypt = Tagged c_cast128_encrypt
nbc_ecb_decrypt = Tagged c_cast128_decrypt
nbc_fun_encrypt = Tagged p_cast128_encrypt
nbc_fun_decrypt = Tagged p_cast128_decrypt
INSTANCE_BLOCKCIPHER(CAST128)
newtype DES = DES SecureMem
instance NettleCipher DES where
nc_cipherInit = Tagged $ \ctxptr _ -> c_des_set_key ctxptr
nc_cipherName = Tagged "DES"
nc_cipherKeySize = Tagged $ KeySizeFixed 8
nc_ctx_size = Tagged c_des_ctx_size
nc_ctx (DES c) = c
nc_Ctx = DES
instance NettleBlockCipher DES where
nbc_blockSize = Tagged 8
nbc_ecb_encrypt = Tagged c_des_encrypt
nbc_ecb_decrypt = Tagged c_des_decrypt
nbc_fun_encrypt = Tagged p_des_encrypt
nbc_fun_decrypt = Tagged p_des_decrypt
INSTANCE_BLOCKCIPHER(DES)
newtype DES_EDE3 = DES_EDE3 SecureMem
instance NettleCipher DES_EDE3 where
nc_cipherInit = Tagged $ \ctxptr _ -> c_des3_set_key ctxptr
nc_cipherName = Tagged "DES-EDE3"
nc_cipherKeySize = Tagged $ KeySizeFixed 24
nc_ctx_size = Tagged c_des3_ctx_size
nc_ctx (DES_EDE3 c) = c
nc_Ctx = DES_EDE3
instance NettleBlockCipher DES_EDE3 where
nbc_blockSize = Tagged 8
nbc_ecb_encrypt = Tagged c_des3_encrypt
nbc_ecb_decrypt = Tagged c_des3_decrypt
nbc_fun_encrypt = Tagged p_des3_encrypt
nbc_fun_decrypt = Tagged p_des3_decrypt
INSTANCE_BLOCKCIPHER(DES_EDE3)
newtype SERPENT = SERPENT SecureMem
instance NettleCipher SERPENT where
nc_cipherInit = Tagged c_serpent_set_key
nc_cipherName = Tagged "SERPENT"
nc_cipherKeySize = Tagged $ KeySizeRange 16 32
nc_ctx_size = Tagged c_serpent_ctx_size
nc_ctx (SERPENT c) = c
nc_Ctx = SERPENT
instance NettleBlockCipher SERPENT where
nbc_blockSize = Tagged 16
nbc_ecb_encrypt = Tagged c_serpent_encrypt
nbc_ecb_decrypt = Tagged c_serpent_decrypt
nbc_fun_encrypt = Tagged p_serpent_encrypt
nbc_fun_decrypt = Tagged p_serpent_decrypt
INSTANCE_BLOCKCIPHER(SERPENT)
newtype TWOFISH = TWOFISH SecureMem
instance NettleCipher TWOFISH where
nc_cipherInit = Tagged c_twofish_set_key
nc_cipherName = Tagged "TWOFISH"
nc_cipherKeySize = Tagged $ KeySizeEnum [16,24,32]
nc_ctx_size = Tagged c_twofish_ctx_size
nc_ctx (TWOFISH c) = c
nc_Ctx = TWOFISH
instance NettleBlockCipher TWOFISH where
nbc_blockSize = Tagged 16
nbc_ecb_encrypt = Tagged c_twofish_encrypt
nbc_ecb_decrypt = Tagged c_twofish_decrypt
nbc_fun_encrypt = Tagged p_twofish_encrypt
nbc_fun_decrypt = Tagged p_twofish_decrypt
INSTANCE_BLOCKCIPHER(TWOFISH)
newtype ARCFOUR = ARCFOUR SecureMem
instance NettleCipher ARCFOUR where
nc_cipherInit = Tagged c_arcfour_set_key
nc_cipherName = Tagged "ARCFOUR"
nc_cipherKeySize = Tagged $ KeySizeEnum [16,24,32]
nc_ctx_size = Tagged c_arcfour_ctx_size
nc_ctx (ARCFOUR c) = c
nc_Ctx = ARCFOUR
instance NettleStreamCipher ARCFOUR where
nsc_streamCombine = Tagged c_arcfour_crypt
INSTANCE_STREAMCIPHER(ARCFOUR)
class StreamCipher cipher => StreamNonceCipher cipher where
streamNonceSize :: cipher -> KeySizeSpecifier
streamSetNonce :: cipher -> B.ByteString -> Maybe cipher
word64BE :: Word64 -> B.ByteString
word64BE value = B.pack $ _work (8::Int) [] value where
_work 0 r _ = r
_work n r v = let d = v `shiftR` 8; m = fromIntegral v :: Word8 in _work (n-1) (m:r) d
streamSetNonceWord64 :: StreamNonceCipher cipher => cipher -> Word64 -> Maybe cipher
streamSetNonceWord64 c nonce = streamSetNonce c $ word64BE nonce
wrap_chacha_set_key :: Ptr Word8 -> Word -> Ptr Word8 -> IO ()
wrap_chacha_set_key ctxptr _ keyptr = do
c_chacha_set_key ctxptr keyptr
withByteStringPtr (B.replicate 8 0) $ \_ nonceptr ->
c_chacha_set_nonce ctxptr nonceptr
wrap_chacha_set_nonce :: Ptr Word8 -> Word -> Ptr Word8 -> IO ()
wrap_chacha_set_nonce ctxptr ivlen ivptr = if ivlen == 8 then c_chacha_set_nonce ctxptr ivptr else fail "Invalid nonce length"
newtype CHACHA = CHACHA (SecureMem, B.ByteString)
instance NettleCipher CHACHA where
nc_cipherInit = Tagged wrap_chacha_set_key
nc_cipherName = Tagged "ChaCha"
nc_cipherKeySize = Tagged $ KeySizeFixed 32
nc_ctx_size = Tagged c_chacha_ctx_size
nc_ctx (CHACHA (c, _)) = c
nc_Ctx c = CHACHA (c, B.empty)
instance NettleBlockedStreamCipher CHACHA where
nbsc_blockSize = Tagged 64
nbsc_IncompleteState (CHACHA (c, _)) inc = CHACHA (c, inc)
nbsc_incompleteState (CHACHA (_, inc)) = inc
nbsc_streamCombine = Tagged c_chacha_crypt
nbsc_nonceSize = Tagged $ KeySizeFixed 8
nbsc_setNonce = Tagged $ Just wrap_chacha_set_nonce
INSTANCE_BLOCKEDSTREAMNONCECIPHER(CHACHA)
wrap_salsa20_set_key :: Ptr Word8 -> Word -> Ptr Word8 -> IO ()
wrap_salsa20_set_key ctxptr keylen keyptr = do
c_salsa20_set_key ctxptr keylen keyptr
withByteStringPtr (B.replicate 8 0) $ \_ nonceptr ->
c_salsa20_set_nonce ctxptr nonceptr
wrap_salsa20_set_nonce :: Ptr Word8 -> Word -> Ptr Word8 -> IO ()
wrap_salsa20_set_nonce ctxptr ivlen ivptr = if ivlen == 8 then c_salsa20_set_nonce ctxptr ivptr else fail "Invalid nonce length"
newtype SALSA20 = SALSA20 (SecureMem, B.ByteString)
instance NettleCipher SALSA20 where
nc_cipherInit = Tagged wrap_salsa20_set_key
nc_cipherName = Tagged "Salsa20"
nc_cipherKeySize = Tagged $ KeySizeEnum [16,32]
nc_ctx_size = Tagged c_salsa20_ctx_size
nc_ctx (SALSA20 (c, _)) = c
nc_Ctx c = SALSA20 (c, B.empty)
instance NettleBlockedStreamCipher SALSA20 where
nbsc_blockSize = Tagged 64
nbsc_IncompleteState (SALSA20 (c, _)) inc = SALSA20 (c, inc)
nbsc_incompleteState (SALSA20 (_, inc)) = inc
nbsc_streamCombine = Tagged c_salsa20_crypt
nbsc_nonceSize = Tagged $ KeySizeFixed 8
nbsc_setNonce = Tagged $ Just wrap_salsa20_set_nonce
INSTANCE_BLOCKEDSTREAMNONCECIPHER(SALSA20)
newtype ESTREAM_SALSA20 = ESTREAM_SALSA20 (SecureMem, B.ByteString)
instance NettleCipher ESTREAM_SALSA20 where
nc_cipherInit = Tagged wrap_salsa20_set_key
nc_cipherName = Tagged "eSTREAM-Salsa20"
nc_cipherKeySize = Tagged $ KeySizeEnum [16,32]
nc_ctx_size = Tagged c_salsa20_ctx_size
nc_ctx (ESTREAM_SALSA20 (c, _)) = c
nc_Ctx c = ESTREAM_SALSA20 (c, B.empty)
instance NettleBlockedStreamCipher ESTREAM_SALSA20 where
nbsc_blockSize = Tagged 64
nbsc_IncompleteState (ESTREAM_SALSA20 (c, _)) inc = ESTREAM_SALSA20 (c, inc)
nbsc_incompleteState (ESTREAM_SALSA20 (_, inc)) = inc
nbsc_streamCombine = Tagged c_salsa20r12_crypt
nbsc_nonceSize = Tagged $ KeySizeFixed 8
nbsc_setNonce = Tagged $ Just wrap_salsa20_set_nonce
INSTANCE_BLOCKEDSTREAMNONCECIPHER(ESTREAM_SALSA20)