{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Network.QUIC.Crypto.Nite (
    niteEncrypt,
    niteEncrypt',
    niteDecrypt,
    niteDecrypt',
    protectionMask,
    aes128gcmEncrypt,
    makeNonce,
    makeNiteEncrypt,
    makeNiteDecrypt,
    makeNiteProtector,
) where

import Crypto.Cipher.AES
import Crypto.Cipher.Types hiding (Cipher, IV)
import Crypto.Error (maybeCryptoError)
import qualified Data.ByteArray as Byte (convert)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Internal as BS
import Foreign.ForeignPtr (newForeignPtr_, withForeignPtr)
import Foreign.Marshal.Alloc (mallocBytes)
import Foreign.Marshal.Utils (copyBytes)
import Foreign.Ptr (Ptr, nullPtr, plusPtr)
import Foreign.Storable (peek, poke)
import Network.TLS hiding (Version)
import Network.TLS.Extra.Cipher

import Network.QUIC.Crypto.Types
import Network.QUIC.Imports
import Network.QUIC.Types

----------------------------------------------------------------

-- It would be nice to take [PlainText] and update AEAD context with
-- [PlainText]. But since each PlainText is not aligned to cipher block,
-- it's impossible.
cipherEncrypt
    :: Cipher -> Key -> Nonce -> PlainText -> AssDat -> Maybe (CipherText, CipherText)
cipherEncrypt :: Cipher
-> Key
-> Nonce
-> ByteString
-> AssDat
-> Maybe (ByteString, ByteString)
cipherEncrypt Cipher
cipher
    | Cipher
cipher forall a. Eq a => a -> a -> Bool
== Cipher
cipher_TLS13_AES128GCM_SHA256 = Key
-> Nonce -> ByteString -> AssDat -> Maybe (ByteString, ByteString)
aes128gcmEncrypt
    | Cipher
cipher forall a. Eq a => a -> a -> Bool
== Cipher
cipher_TLS13_AES128CCM_SHA256 =
        forall a. HasCallStack => [Char] -> a
error [Char]
"cipher_TLS13_AES128CCM_SHA256"
    | Cipher
cipher forall a. Eq a => a -> a -> Bool
== Cipher
cipher_TLS13_AES256GCM_SHA384 = Key
-> Nonce -> ByteString -> AssDat -> Maybe (ByteString, ByteString)
aes256gcmEncrypt
    | Bool
otherwise = forall a. HasCallStack => [Char] -> a
error [Char]
"cipherEncrypt"

cipherDecrypt
    :: Cipher -> Key -> Nonce -> CipherText -> AssDat -> Maybe PlainText
cipherDecrypt :: Cipher -> Key -> Nonce -> ByteString -> AssDat -> Maybe ByteString
cipherDecrypt Cipher
cipher
    | Cipher
cipher forall a. Eq a => a -> a -> Bool
== Cipher
cipher_TLS13_AES128GCM_SHA256 = Key -> Nonce -> ByteString -> AssDat -> Maybe ByteString
aes128gcmDecrypt
    | Cipher
cipher forall a. Eq a => a -> a -> Bool
== Cipher
cipher_TLS13_AES128CCM_SHA256 =
        forall a. HasCallStack => [Char] -> a
error [Char]
"cipher_TLS13_AES128CCM_SHA256"
    | Cipher
cipher forall a. Eq a => a -> a -> Bool
== Cipher
cipher_TLS13_AES256GCM_SHA384 = Key -> Nonce -> ByteString -> AssDat -> Maybe ByteString
aes256gcmDecrypt
    | Bool
otherwise = forall a. HasCallStack => [Char] -> a
error [Char]
"cipherDecrypt"

-- IMPORTANT: Using 'let' so that parameters can be memorized.
aes128gcmEncrypt
    :: Key -> (Nonce -> PlainText -> AssDat -> Maybe (CipherText, CipherText))
aes128gcmEncrypt :: Key
-> Nonce -> ByteString -> AssDat -> Maybe (ByteString, ByteString)
aes128gcmEncrypt (Key ByteString
key) = case forall a. CryptoFailable a -> Maybe a
maybeCryptoError forall a b. (a -> b) -> a -> b
$ forall cipher key.
(Cipher cipher, ByteArray key) =>
key -> CryptoFailable cipher
cipherInit ByteString
key of
    Maybe AES128
Nothing -> \Nonce
_ ByteString
_ AssDat
_ -> forall a. Maybe a
Nothing
    Just (AES128
aes :: AES128) -> \(Nonce ByteString
nonce) ByteString
plaintext (AssDat ByteString
ad) ->
        case forall a. CryptoFailable a -> Maybe a
maybeCryptoError forall a b. (a -> b) -> a -> b
$ forall cipher iv.
(BlockCipher cipher, ByteArrayAccess iv) =>
AEADMode -> cipher -> iv -> CryptoFailable (AEAD cipher)
aeadInit AEADMode
AEAD_GCM AES128
aes ByteString
nonce of
            Maybe (AEAD AES128)
Nothing -> forall a. Maybe a
Nothing
            Just AEAD AES128
aead ->
                let (AuthTag Bytes
tag0, ByteString
ciphertext) = forall aad ba a.
(ByteArrayAccess aad, ByteArray ba) =>
AEAD a -> aad -> ba -> Int -> (AuthTag, ba)
aeadSimpleEncrypt AEAD AES128
aead ByteString
ad ByteString
plaintext Int
16
                    tag :: ByteString
tag = forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
Byte.convert Bytes
tag0
                 in forall a. a -> Maybe a
Just (ByteString
ciphertext, ByteString
tag)

aes128gcmDecrypt :: Key -> (Nonce -> CipherText -> AssDat -> Maybe PlainText)
aes128gcmDecrypt :: Key -> Nonce -> ByteString -> AssDat -> Maybe ByteString
aes128gcmDecrypt (Key ByteString
key) = case forall a. CryptoFailable a -> Maybe a
maybeCryptoError forall a b. (a -> b) -> a -> b
$ forall cipher key.
(Cipher cipher, ByteArray key) =>
key -> CryptoFailable cipher
cipherInit ByteString
key of
    Maybe AES128
Nothing -> \Nonce
_ ByteString
_ AssDat
_ -> forall a. Maybe a
Nothing
    Just (AES128
aes :: AES128) -> \(Nonce ByteString
nonce) ByteString
ciphertag (AssDat ByteString
ad) ->
        case forall a. CryptoFailable a -> Maybe a
maybeCryptoError forall a b. (a -> b) -> a -> b
$ forall cipher iv.
(BlockCipher cipher, ByteArrayAccess iv) =>
AEADMode -> cipher -> iv -> CryptoFailable (AEAD cipher)
aeadInit AEADMode
AEAD_GCM AES128
aes ByteString
nonce of
            Maybe (AEAD AES128)
Nothing -> forall a. Maybe a
Nothing
            Just AEAD AES128
aead ->
                let (ByteString
ciphertext, ByteString
tag) = Int -> ByteString -> (ByteString, ByteString)
BS.splitAt (ByteString -> Int
BS.length ByteString
ciphertag forall a. Num a => a -> a -> a
- Int
16) ByteString
ciphertag
                    authtag :: AuthTag
authtag = Bytes -> AuthTag
AuthTag forall a b. (a -> b) -> a -> b
$ forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
Byte.convert ByteString
tag
                 in forall aad ba a.
(ByteArrayAccess aad, ByteArray ba) =>
AEAD a -> aad -> ba -> AuthTag -> Maybe ba
aeadSimpleDecrypt AEAD AES128
aead ByteString
ad ByteString
ciphertext AuthTag
authtag

aes256gcmEncrypt
    :: Key -> (Nonce -> PlainText -> AssDat -> Maybe (CipherText, CipherText))
aes256gcmEncrypt :: Key
-> Nonce -> ByteString -> AssDat -> Maybe (ByteString, ByteString)
aes256gcmEncrypt (Key ByteString
key) = case forall a. CryptoFailable a -> Maybe a
maybeCryptoError forall a b. (a -> b) -> a -> b
$ forall cipher key.
(Cipher cipher, ByteArray key) =>
key -> CryptoFailable cipher
cipherInit ByteString
key of
    Maybe AES256
Nothing -> \Nonce
_ ByteString
_ AssDat
_ -> forall a. Maybe a
Nothing
    Just (AES256
aes :: AES256) -> \(Nonce ByteString
nonce) ByteString
plaintext (AssDat ByteString
ad) ->
        case forall a. CryptoFailable a -> Maybe a
maybeCryptoError forall a b. (a -> b) -> a -> b
$ forall cipher iv.
(BlockCipher cipher, ByteArrayAccess iv) =>
AEADMode -> cipher -> iv -> CryptoFailable (AEAD cipher)
aeadInit AEADMode
AEAD_GCM AES256
aes ByteString
nonce of
            Maybe (AEAD AES256)
Nothing -> forall a. Maybe a
Nothing
            Just AEAD AES256
aead ->
                let (AuthTag Bytes
tag0, ByteString
ciphertext) = forall aad ba a.
(ByteArrayAccess aad, ByteArray ba) =>
AEAD a -> aad -> ba -> Int -> (AuthTag, ba)
aeadSimpleEncrypt AEAD AES256
aead ByteString
ad ByteString
plaintext Int
16
                    tag :: ByteString
tag = forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
Byte.convert Bytes
tag0
                 in forall a. a -> Maybe a
Just (ByteString
ciphertext, ByteString
tag)

aes256gcmDecrypt :: Key -> (Nonce -> CipherText -> AssDat -> Maybe PlainText)
aes256gcmDecrypt :: Key -> Nonce -> ByteString -> AssDat -> Maybe ByteString
aes256gcmDecrypt (Key ByteString
key) = case forall a. CryptoFailable a -> Maybe a
maybeCryptoError forall a b. (a -> b) -> a -> b
$ forall cipher key.
(Cipher cipher, ByteArray key) =>
key -> CryptoFailable cipher
cipherInit ByteString
key of
    Maybe AES256
Nothing -> \Nonce
_ ByteString
_ AssDat
_ -> forall a. Maybe a
Nothing
    Just (AES256
aes :: AES256) -> \(Nonce ByteString
nonce) ByteString
ciphertag (AssDat ByteString
ad) ->
        case forall a. CryptoFailable a -> Maybe a
maybeCryptoError forall a b. (a -> b) -> a -> b
$ forall cipher iv.
(BlockCipher cipher, ByteArrayAccess iv) =>
AEADMode -> cipher -> iv -> CryptoFailable (AEAD cipher)
aeadInit AEADMode
AEAD_GCM AES256
aes ByteString
nonce of
            Maybe (AEAD AES256)
Nothing -> forall a. Maybe a
Nothing
            Just AEAD AES256
aead ->
                let (ByteString
ciphertext, ByteString
tag) = Int -> ByteString -> (ByteString, ByteString)
BS.splitAt (ByteString -> Int
BS.length ByteString
ciphertag forall a. Num a => a -> a -> a
- Int
16) ByteString
ciphertag
                    authtag :: AuthTag
authtag = Bytes -> AuthTag
AuthTag forall a b. (a -> b) -> a -> b
$ forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
Byte.convert ByteString
tag
                 in forall aad ba a.
(ByteArrayAccess aad, ByteArray ba) =>
AEAD a -> aad -> ba -> AuthTag -> Maybe ba
aeadSimpleDecrypt AEAD AES256
aead ByteString
ad ByteString
ciphertext AuthTag
authtag

----------------------------------------------------------------

makeNonce :: IV -> ByteString -> Nonce
makeNonce :: IV -> ByteString -> Nonce
makeNonce (IV ByteString
iv) ByteString
pn = ByteString -> Nonce
Nonce ByteString
nonce
  where
    nonce :: ByteString
nonce = ByteString -> ByteString -> ByteString
bsXORpad ByteString
iv ByteString
pn

-- XORing IV and a packet numbr with left padded.
--             src0
-- IV          +IIIIIIIIIIIIIIIIII--------+
--                 diff          src1
-- PN          +000000000000000000+-------+
--             dst
-- Nonce       +IIIIIIIIIIIIIIIIII--------+
bsXORpad :: ByteString -> ByteString -> ByteString
bsXORpad :: ByteString -> ByteString -> ByteString
bsXORpad (PS ForeignPtr Word8
fp0 Int
off0 Int
len0) (PS ForeignPtr Word8
fp1 Int
off1 Int
len1)
    | Int
len0 forall a. Ord a => a -> a -> Bool
< Int
len1 = forall a. HasCallStack => [Char] -> a
error [Char]
"bsXORpad"
    | Bool
otherwise = Int -> (Ptr Word8 -> IO ()) -> ByteString
BS.unsafeCreate Int
len0 forall a b. (a -> b) -> a -> b
$ \Ptr Word8
dst ->
        forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr Word8
fp0 forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p0 ->
            forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr Word8
fp1 forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p1 -> do
                let src0 :: Ptr b
src0 = Ptr Word8
p0 forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
off0
                let src1 :: Ptr b
src1 = Ptr Word8
p1 forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
off1
                let diff :: Int
diff = Int
len0 forall a. Num a => a -> a -> a
- Int
len1
                forall a. Ptr a -> Ptr a -> Int -> IO ()
copyBytes Ptr Word8
dst forall {b}. Ptr b
src0 Int
diff
                Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Int -> IO ()
loop (Ptr Word8
dst forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
diff) (forall {b}. Ptr b
src0 forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
diff) forall {b}. Ptr b
src1 Int
len1
  where
    loop :: Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Int -> IO ()
    loop :: Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Int -> IO ()
loop Ptr Word8
_ Ptr Word8
_ Ptr Word8
_ Int
0 = forall (m :: * -> *) a. Monad m => a -> m a
return ()
    loop Ptr Word8
dst Ptr Word8
src0 Ptr Word8
src1 Int
len = do
        Word8
w1 <- forall a. Storable a => Ptr a -> IO a
peek Ptr Word8
src0
        Word8
w2 <- forall a. Storable a => Ptr a -> IO a
peek Ptr Word8
src1
        forall a. Storable a => Ptr a -> a -> IO ()
poke Ptr Word8
dst (Word8
w1 forall a. Bits a => a -> a -> a
`xor` Word8
w2)
        Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Int -> IO ()
loop (Ptr Word8
dst forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
1) (Ptr Word8
src0 forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
1) (Ptr Word8
src1 forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
1) (Int
len forall a. Num a => a -> a -> a
- Int
1)

{-
bsXORpad' :: ByteString -> ByteString -> ByteString
bsXORpad' iv pn = BS.pack $ zipWith xor ivl pnl
  where
    ivl = BS.unpack iv
    diff = BS.length iv - BS.length pn
    pnl = replicate diff 0 ++ BS.unpack pn
-}

----------------------------------------------------------------

type NiteEncrypt = Buffer -> PlainText -> AssDat -> PacketNumber -> IO Int

makeNiteEncrypt :: Cipher -> Key -> IV -> NiteEncrypt
makeNiteEncrypt :: Cipher -> Key -> IV -> NiteEncrypt
makeNiteEncrypt Cipher
cipher Key
key IV
iv = (ByteString -> AssDat -> Int -> Maybe (ByteString, ByteString))
-> NiteEncrypt
niteEncryptWrapper (Cipher
-> Key
-> IV
-> ByteString
-> AssDat
-> Int
-> Maybe (ByteString, ByteString)
niteEncrypt Cipher
cipher Key
key IV
iv)

niteEncryptWrapper
    :: (PlainText -> AssDat -> PacketNumber -> Maybe (CipherText, CipherText))
    -> NiteEncrypt
niteEncryptWrapper :: (ByteString -> AssDat -> Int -> Maybe (ByteString, ByteString))
-> NiteEncrypt
niteEncryptWrapper ByteString -> AssDat -> Int -> Maybe (ByteString, ByteString)
enc Ptr Word8
dst ByteString
plaintext AssDat
ad Int
pn = case ByteString -> AssDat -> Int -> Maybe (ByteString, ByteString)
enc ByteString
plaintext AssDat
ad Int
pn of
    Maybe (ByteString, ByteString)
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return (-Int
1)
    Just (ByteString
hdr, ByteString
bdy) -> do
        Int
len <- Ptr Word8 -> ByteString -> IO Int
copyBS Ptr Word8
dst ByteString
hdr
        let dst' :: Ptr b
dst' = Ptr Word8
dst forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
len
        Int
len' <- Ptr Word8 -> ByteString -> IO Int
copyBS forall {b}. Ptr b
dst' ByteString
bdy
        forall (m :: * -> *) a. Monad m => a -> m a
return (Int
len forall a. Num a => a -> a -> a
+ Int
len')

niteEncrypt
    :: Cipher
    -> Key
    -> IV
    -> PlainText
    -> AssDat
    -> PacketNumber
    -> Maybe (CipherText, CipherText)
niteEncrypt :: Cipher
-> Key
-> IV
-> ByteString
-> AssDat
-> Int
-> Maybe (ByteString, ByteString)
niteEncrypt Cipher
cipher Key
key IV
iv =
    let enc :: Nonce -> ByteString -> AssDat -> Maybe (ByteString, ByteString)
enc = Cipher
-> Key
-> Nonce
-> ByteString
-> AssDat
-> Maybe (ByteString, ByteString)
cipherEncrypt Cipher
cipher Key
key
        mk :: ByteString -> Nonce
mk = IV -> ByteString -> Nonce
makeNonce IV
iv
     in \ByteString
plaintext AssDat
header Int
pn ->
            let bytePN :: ByteString
bytePN = Word64 -> ByteString
bytestring64 forall a b. (a -> b) -> a -> b
$ forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
pn
                nonce :: Nonce
nonce = ByteString -> Nonce
mk ByteString
bytePN
             in Nonce -> ByteString -> AssDat -> Maybe (ByteString, ByteString)
enc Nonce
nonce ByteString
plaintext AssDat
header

niteEncrypt'
    :: Cipher -> Key -> Nonce -> PlainText -> AssDat -> Maybe (CipherText, CipherText)
niteEncrypt' :: Cipher
-> Key
-> Nonce
-> ByteString
-> AssDat
-> Maybe (ByteString, ByteString)
niteEncrypt' Cipher
cipher Key
key Nonce
nonce ByteString
plaintext AssDat
header =
    Cipher
-> Key
-> Nonce
-> ByteString
-> AssDat
-> Maybe (ByteString, ByteString)
cipherEncrypt Cipher
cipher Key
key Nonce
nonce ByteString
plaintext AssDat
header

----------------------------------------------------------------

type NiteDecrypt = Buffer -> CipherText -> AssDat -> PacketNumber -> IO Int

makeNiteDecrypt :: Cipher -> Key -> IV -> NiteDecrypt
makeNiteDecrypt :: Cipher -> Key -> IV -> NiteEncrypt
makeNiteDecrypt Cipher
cipher Key
key IV
iv = (ByteString -> AssDat -> Int -> Maybe ByteString) -> NiteEncrypt
niteDecryptWrapper (Cipher
-> Key -> IV -> ByteString -> AssDat -> Int -> Maybe ByteString
niteDecrypt Cipher
cipher Key
key IV
iv)

niteDecryptWrapper
    :: (CipherText -> AssDat -> PacketNumber -> Maybe PlainText) -> NiteDecrypt
niteDecryptWrapper :: (ByteString -> AssDat -> Int -> Maybe ByteString) -> NiteEncrypt
niteDecryptWrapper ByteString -> AssDat -> Int -> Maybe ByteString
dec Ptr Word8
dst ByteString
ciphertext AssDat
ad Int
pn = case ByteString -> AssDat -> Int -> Maybe ByteString
dec ByteString
ciphertext AssDat
ad Int
pn of
    Maybe ByteString
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return (-Int
1)
    Just ByteString
bs -> Ptr Word8 -> ByteString -> IO Int
copyBS Ptr Word8
dst ByteString
bs

niteDecrypt
    :: Cipher
    -> Key
    -> IV
    -> CipherText
    -> AssDat
    -> PacketNumber
    -> Maybe PlainText
niteDecrypt :: Cipher
-> Key -> IV -> ByteString -> AssDat -> Int -> Maybe ByteString
niteDecrypt Cipher
cipher Key
key IV
iv =
    let dec :: Nonce -> ByteString -> AssDat -> Maybe ByteString
dec = Cipher -> Key -> Nonce -> ByteString -> AssDat -> Maybe ByteString
cipherDecrypt Cipher
cipher Key
key
        mk :: ByteString -> Nonce
mk = IV -> ByteString -> Nonce
makeNonce IV
iv
     in \ByteString
ciphertext AssDat
header Int
pn ->
            let bytePN :: ByteString
bytePN = Word64 -> ByteString
bytestring64 (forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
pn)
                nonce :: Nonce
nonce = ByteString -> Nonce
mk ByteString
bytePN
             in Nonce -> ByteString -> AssDat -> Maybe ByteString
dec Nonce
nonce ByteString
ciphertext AssDat
header

niteDecrypt'
    :: Cipher -> Key -> Nonce -> CipherText -> AssDat -> Maybe PlainText
niteDecrypt' :: Cipher -> Key -> Nonce -> ByteString -> AssDat -> Maybe ByteString
niteDecrypt' Cipher
cipher Key
key Nonce
nonce ByteString
ciphertext AssDat
header =
    Cipher -> Key -> Nonce -> ByteString -> AssDat -> Maybe ByteString
cipherDecrypt Cipher
cipher Key
key Nonce
nonce ByteString
ciphertext AssDat
header

----------------------------------------------------------------

protectionMask :: Cipher -> Key -> (Sample -> Mask)
protectionMask :: Cipher -> Key -> Sample -> Mask
protectionMask Cipher
cipher Key
key =
    let f :: Sample -> Mask
f = Cipher -> Key -> Sample -> Mask
cipherHeaderProtection Cipher
cipher Key
key
     in \Sample
sample -> Sample -> Mask
f Sample
sample

cipherHeaderProtection :: Cipher -> Key -> (Sample -> Mask)
cipherHeaderProtection :: Cipher -> Key -> Sample -> Mask
cipherHeaderProtection Cipher
cipher Key
key
    | Cipher
cipher forall a. Eq a => a -> a -> Bool
== Cipher
cipher_TLS13_AES128GCM_SHA256 = Key -> Sample -> Mask
aes128ecbEncrypt Key
key
    | Cipher
cipher forall a. Eq a => a -> a -> Bool
== Cipher
cipher_TLS13_AES128CCM_SHA256 =
        forall a. HasCallStack => [Char] -> a
error [Char]
"cipher_TLS13_AES128CCM_SHA256"
    | Cipher
cipher forall a. Eq a => a -> a -> Bool
== Cipher
cipher_TLS13_AES256GCM_SHA384 = Key -> Sample -> Mask
aes256ecbEncrypt Key
key
    | Bool
otherwise =
        forall a. HasCallStack => [Char] -> a
error [Char]
"cipherHeaderProtection"

aes128ecbEncrypt :: Key -> (Sample -> Mask)
aes128ecbEncrypt :: Key -> Sample -> Mask
aes128ecbEncrypt (Key ByteString
key) = case forall a. CryptoFailable a -> Maybe a
maybeCryptoError forall a b. (a -> b) -> a -> b
$ forall cipher key.
(Cipher cipher, ByteArray key) =>
key -> CryptoFailable cipher
cipherInit ByteString
key of
    Maybe AES128
Nothing -> \Sample
_ -> ByteString -> Mask
Mask ByteString
"0123456789012345"
    Just (AES128
aes :: AES128) ->
        let encrypt :: ByteString -> ByteString
encrypt = forall cipher ba.
(BlockCipher cipher, ByteArray ba) =>
cipher -> ba -> ba
ecbEncrypt AES128
aes
         in \(Sample ByteString
sample) ->
                let mask :: ByteString
mask = ByteString -> ByteString
encrypt ByteString
sample
                 in ByteString -> Mask
Mask ByteString
mask

aes256ecbEncrypt :: Key -> (Sample -> Mask)
aes256ecbEncrypt :: Key -> Sample -> Mask
aes256ecbEncrypt (Key ByteString
key) = case forall a. CryptoFailable a -> Maybe a
maybeCryptoError forall a b. (a -> b) -> a -> b
$ forall cipher key.
(Cipher cipher, ByteArray key) =>
key -> CryptoFailable cipher
cipherInit ByteString
key of
    Maybe AES256
Nothing -> \Sample
_ -> ByteString -> Mask
Mask ByteString
"0123456789012345"
    Just (AES256
aes :: AES256) ->
        let encrypt :: ByteString -> ByteString
encrypt = forall cipher ba.
(BlockCipher cipher, ByteArray ba) =>
cipher -> ba -> ba
ecbEncrypt AES256
aes
         in \(Sample ByteString
sample) ->
                let mask :: ByteString
mask = ByteString -> ByteString
encrypt ByteString
sample
                 in ByteString -> Mask
Mask ByteString
mask

----------------------------------------------------------------

makeNiteProtector :: Cipher -> Key -> IO (Buffer -> IO (), IO Buffer)
makeNiteProtector :: Cipher -> Key -> IO (Ptr Word8 -> IO (), IO (Ptr Word8))
makeNiteProtector Cipher
cipher Key
key = do
    IORef (Ptr Word8)
ref <- forall a. a -> IO (IORef a)
newIORef forall {b}. Ptr b
nullPtr
    Ptr Word8
dstbuf <- forall a. Int -> IO (Ptr a)
mallocBytes Int
32 -- fixme: free
    forall (m :: * -> *) a. Monad m => a -> m a
return (IORef (Ptr Word8) -> Ptr Word8 -> IO ()
niteSetSample IORef (Ptr Word8)
ref, IORef (Ptr Word8)
-> Int -> (Sample -> Mask) -> Ptr Word8 -> IO (Ptr Word8)
niteGetMask IORef (Ptr Word8)
ref Int
samplelen Sample -> Mask
mkMask Ptr Word8
dstbuf)
  where
    samplelen :: Int
samplelen = Int
16 -- sampleLength cipher -- fixme
    mkMask :: Sample -> Mask
mkMask = Cipher -> Key -> Sample -> Mask
protectionMask Cipher
cipher Key
key

niteSetSample :: IORef Buffer -> Buffer -> IO ()
niteSetSample :: IORef (Ptr Word8) -> Ptr Word8 -> IO ()
niteSetSample = forall a. IORef a -> a -> IO ()
writeIORef

niteGetMask :: IORef Buffer -> Int -> (Sample -> Mask) -> Buffer -> IO Buffer
niteGetMask :: IORef (Ptr Word8)
-> Int -> (Sample -> Mask) -> Ptr Word8 -> IO (Ptr Word8)
niteGetMask IORef (Ptr Word8)
ref Int
samplelen Sample -> Mask
mkMask Ptr Word8
dstbuf = do
    Ptr Word8
srcbuf <- forall a. IORef a -> IO a
readIORef IORef (Ptr Word8)
ref
    ByteString
sample <- do
        ForeignPtr Word8
fptr <- forall a. Ptr a -> IO (ForeignPtr a)
newForeignPtr_ Ptr Word8
srcbuf
        forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ ForeignPtr Word8 -> Int -> Int -> ByteString
PS ForeignPtr Word8
fptr Int
0 Int
samplelen
    let Mask ByteString
mask = Sample -> Mask
mkMask forall a b. (a -> b) -> a -> b
$ ByteString -> Sample
Sample ByteString
sample
    Int
_len <- Ptr Word8 -> ByteString -> IO Int
copyBS Ptr Word8
dstbuf ByteString
mask
    forall (m :: * -> *) a. Monad m => a -> m a
return Ptr Word8
dstbuf