1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
module Crypto.Cipher.ChaChaPoly1305 (
AeadState, Nonce, Auth(..),
authTag,
nonce8, nonce12,
aeadInitialize,
aeadAppendAAD, aeadFinalizeAAD,
encrypt, decrypt,
aeadFinalize,
) where
import Crypto.AEAD.ChaCha20Poly1305 qualified as P
import Crypto.Error
import Crypto.MAC.Poly1305
import Data.ByteArray as BA
import Data.ByteString (ByteString)
import Data.ByteString qualified as B
data AeadState = AeadState
{ stKey :: ByteString
, stNonce :: Nonce
, stAAD :: [ ByteString ]
, stAuth :: Maybe Auth
}
newtype Nonce = Nonce ByteString
deriving (Eq, ByteArrayAccess)
nonce8 :: Bytes -> Bytes -> CryptoFailable Nonce
nonce8 c iv
| BA.length c /= 4 = CryptoFailed CryptoError
| BA.length iv /= 8 = CryptoFailed CryptoError
| otherwise = CryptoPassed $ Nonce $ B.concat $ [ BA.convert c, BA.convert iv ]
nonce12 :: Bytes -> CryptoFailable Nonce
nonce12 iv
| BA.length iv /= 12 = CryptoFailed CryptoError
| otherwise = CryptoPassed $ Nonce $ BA.convert iv
aeadInitialize :: ScrubbedBytes -> Nonce -> CryptoFailable AeadState
aeadInitialize key nonce
| BA.length key /= 32 = CryptoFailed CryptoError
| otherwise = CryptoPassed AeadState
{ stKey = BA.convert key
, stNonce = nonce
, stAAD = []
, stAuth = Nothing
}
aeadAppendAAD :: ByteString -> AeadState -> AeadState
aeadAppendAAD aad st = st { stAAD = stAAD st ++ [ aad ] }
aeadFinalizeAAD :: AeadState -> AeadState
aeadFinalizeAAD = id
encrypt :: ByteArray ba => ba -> AeadState -> ( ba, AeadState )
encrypt ptext st =
let Nonce nonce = stNonce st
( ctext, mac ) = P.encrypt (B.concat $ stAAD st) (stKey st) nonce (convert ptext)
in ( convert ctext, st { stAuth = Just $ Auth mac } )
decrypt :: ByteArray ba => ( ba, Auth ) -> AeadState -> Maybe ba
decrypt ( ctext, auth ) st = do
let Nonce nonce = stNonce st
Auth mac = auth
fmap convert $ P.decrypt (B.concat $ stAAD st) (stKey st) nonce ( convert ctext, mac )
aeadFinalize :: AeadState -> Auth
aeadFinalize st = case stAuth st of
Just auth -> auth
Nothing -> aeadFinalize $ snd $ encrypt B.empty st
|