{-# OPTIONS_HADDOCK prune #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ViewPatterns #-}
module Crypto.AEAD.ChaCha20Poly1305 (
encrypt
, decrypt
, _poly1305_key_gen
) where
import qualified Crypto.Cipher.ChaCha20 as ChaCha20
import qualified Crypto.MAC.Poly1305 as Poly1305
import Data.Bits ((.>>.))
import qualified Data.ByteString as BS
import qualified Data.ByteString.Internal as BI
import Data.Word (Word64)
fi :: (Integral a, Num b) => a -> b
fi :: forall a b. (Integral a, Num b) => a -> b
fi = a -> b
forall a b. (Integral a, Num b) => a -> b
fromIntegral
{-# INLINE fi #-}
unroll :: Word64 -> BS.ByteString
unroll :: Word64 -> ByteString
unroll Word64
i = case Word64
i of
Word64
0 -> Word8 -> ByteString
BS.singleton Word8
0
Word64
_ -> (Word64 -> Maybe (Word8, Word64)) -> Word64 -> ByteString
forall a. (a -> Maybe (Word8, a)) -> a -> ByteString
BS.unfoldr Word64 -> Maybe (Word8, Word64)
coalg Word64
i
where
coalg :: Word64 -> Maybe (Word8, Word64)
coalg = \case
Word64
0 -> Maybe (Word8, Word64)
forall a. Maybe a
Nothing
Word64
m -> (Word8, Word64) -> Maybe (Word8, Word64)
forall a. a -> Maybe a
Just ((Word8, Word64) -> Maybe (Word8, Word64))
-> (Word8, Word64) -> Maybe (Word8, Word64)
forall a b. (a -> b) -> a -> b
$! (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fi Word64
m, Word64
m Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
.>>. Int
8)
{-# INLINE unroll #-}
unroll8 :: Word64 -> BS.ByteString
unroll8 :: Word64 -> ByteString
unroll8 (Word64 -> ByteString
unroll -> u :: ByteString
u@(BI.PS ForeignPtr Word8
_ Int
_ Int
l))
| Int
l Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
8 = ByteString
u ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Int -> Word8 -> ByteString
BS.replicate (Int
8 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
l) Word8
0
| Bool
otherwise = ByteString
u
{-# INLINE unroll8 #-}
_poly1305_key_gen
:: BS.ByteString
-> BS.ByteString
-> BS.ByteString
_poly1305_key_gen :: ByteString -> ByteString -> ByteString
_poly1305_key_gen key :: ByteString
key@(BI.PS ForeignPtr Word8
_ Int
_ Int
l) ByteString
nonce
| Int
l Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
32 = [Char] -> ByteString
forall a. HasCallStack => [Char] -> a
error [Char]
"ppad-aead (poly1305_key_gen): invalid key"
| Bool
otherwise = Int -> ByteString -> ByteString
BS.take Int
32 (ByteString -> Word32 -> ByteString -> ByteString
ChaCha20.block ByteString
key Word32
0 ByteString
nonce)
{-# INLINEABLE _poly1305_key_gen #-}
pad16 :: BS.ByteString -> BS.ByteString
pad16 :: ByteString -> ByteString
pad16 (BI.PS ForeignPtr Word8
_ Int
_ Int
l)
| Int
l Int -> Int -> Int
forall a. Integral a => a -> a -> a
`rem` Int
16 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 = ByteString
forall a. Monoid a => a
mempty
| Bool
otherwise = Int -> Word8 -> ByteString
BS.replicate (Int
16 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
l Int -> Int -> Int
forall a. Integral a => a -> a -> a
`rem` Int
16) Word8
0
{-# INLINE pad16 #-}
encrypt
:: BS.ByteString
-> BS.ByteString
-> BS.ByteString
-> BS.ByteString
-> (BS.ByteString, BS.ByteString)
encrypt :: ByteString
-> ByteString
-> ByteString
-> ByteString
-> (ByteString, ByteString)
encrypt ByteString
aad ByteString
key ByteString
nonce ByteString
plaintext
| ByteString -> Int
BS.length ByteString
key Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
32 = [Char] -> (ByteString, ByteString)
forall a. HasCallStack => [Char] -> a
error [Char]
"ppad-aead (encrypt): invalid key"
| ByteString -> Int
BS.length ByteString
nonce Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
12 = [Char] -> (ByteString, ByteString)
forall a. HasCallStack => [Char] -> a
error [Char]
"ppad-aead (encrypt): invalid nonce"
| Bool
otherwise =
let otk :: ByteString
otk = ByteString -> ByteString -> ByteString
_poly1305_key_gen ByteString
key ByteString
nonce
cip :: ByteString
cip = ByteString -> Word32 -> ByteString -> ByteString -> ByteString
ChaCha20.cipher ByteString
key Word32
1 ByteString
nonce ByteString
plaintext
md0 :: ByteString
md0 = ByteString
aad ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString -> ByteString
pad16 ByteString
aad
md1 :: ByteString
md1 = ByteString
md0 ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
cip ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString -> ByteString
pad16 ByteString
cip
md2 :: ByteString
md2 = ByteString
md1 ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Word64 -> ByteString
unroll8 (Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fi (ByteString -> Int
BS.length ByteString
aad))
md3 :: ByteString
md3 = ByteString
md2 ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Word64 -> ByteString
unroll8 (Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fi (ByteString -> Int
BS.length ByteString
cip))
tag :: ByteString
tag = ByteString -> ByteString -> ByteString
Poly1305.mac ByteString
otk ByteString
md3
in (ByteString
cip, ByteString
tag)
decrypt
:: BS.ByteString
-> BS.ByteString
-> BS.ByteString
-> (BS.ByteString, BS.ByteString)
-> Maybe BS.ByteString
decrypt :: ByteString
-> ByteString
-> ByteString
-> (ByteString, ByteString)
-> Maybe ByteString
decrypt ByteString
aad ByteString
key ByteString
nonce (ByteString
cip, ByteString
mac)
| ByteString -> Int
BS.length ByteString
key Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
32 = [Char] -> Maybe ByteString
forall a. HasCallStack => [Char] -> a
error [Char]
"ppad-aead (decrypt): invalid key"
| ByteString -> Int
BS.length ByteString
nonce Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
12 = [Char] -> Maybe ByteString
forall a. HasCallStack => [Char] -> a
error [Char]
"ppad-aead (decrypt): invalid nonce"
| ByteString -> Int
BS.length ByteString
mac Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
16 = Maybe ByteString
forall a. Maybe a
Nothing
| Bool
otherwise =
let otk :: ByteString
otk = ByteString -> ByteString -> ByteString
_poly1305_key_gen ByteString
key ByteString
nonce
md0 :: ByteString
md0 = ByteString
aad ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString -> ByteString
pad16 ByteString
aad
md1 :: ByteString
md1 = ByteString
md0 ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
cip ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString -> ByteString
pad16 ByteString
cip
md2 :: ByteString
md2 = ByteString
md1 ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Word64 -> ByteString
unroll8 (Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fi (ByteString -> Int
BS.length ByteString
aad))
md3 :: ByteString
md3 = ByteString
md2 ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Word64 -> ByteString
unroll8 (Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fi (ByteString -> Int
BS.length ByteString
cip))
tag :: ByteString
tag = ByteString -> ByteString -> ByteString
Poly1305.mac ByteString
otk ByteString
md3
in if ByteString
mac ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString
tag
then ByteString -> Maybe ByteString
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ByteString -> Word32 -> ByteString -> ByteString -> ByteString
ChaCha20.cipher ByteString
key Word32
1 ByteString
nonce ByteString
cip)
else Maybe ByteString
forall a. Maybe a
Nothing