summaryrefslogtreecommitdiff
path: root/src/crypto/reflibs/Crypto/Cipher/ChaChaPoly1305.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/crypto/reflibs/Crypto/Cipher/ChaChaPoly1305.hs')
-rw-r--r--src/crypto/reflibs/Crypto/Cipher/ChaChaPoly1305.hs72
1 files changed, 72 insertions, 0 deletions
diff --git a/src/crypto/reflibs/Crypto/Cipher/ChaChaPoly1305.hs b/src/crypto/reflibs/Crypto/Cipher/ChaChaPoly1305.hs
new file mode 100644
index 0000000..c849c0b
--- /dev/null
+++ b/src/crypto/reflibs/Crypto/Cipher/ChaChaPoly1305.hs
@@ -0,0 +1,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