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 :: ByteString -> ByteString -> CryptoFailable Nonce
nonce8 c iv
| B.length c /= 4 = CryptoFailed CryptoError
| B.length iv /= 8 = CryptoFailed CryptoError
| otherwise = CryptoPassed $ Nonce $ B.concat [ c, iv ]
nonce12 :: ByteString -> CryptoFailable Nonce
nonce12 iv
| B.length iv /= 12 = CryptoFailed CryptoError
| otherwise = CryptoPassed $ Nonce 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 :: ByteString -> AeadState -> ( ByteString, AeadState )
encrypt ptext st =
let Nonce nonce = stNonce st
( ctext, mac ) = P.encrypt (B.concat $ stAAD st) (stKey st) nonce ptext
in ( ctext, st { stAuth = Just $ Auth mac } )
decrypt :: ( ByteString, Auth ) -> AeadState -> Maybe ByteString
decrypt ( ctext, auth ) st = do
let Nonce nonce = stNonce st
Auth mac = auth
P.decrypt (B.concat $ stAAD st) (stKey st) nonce ( ctext, mac )
aeadFinalize :: AeadState -> Auth
aeadFinalize st = case stAuth st of
Just auth -> auth
Nothing -> aeadFinalize $ snd $ encrypt B.empty st
|