{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}
module Crypto.Nettle.ChaChaPoly1305 (
	
	
	
	
	
	  chaChaPoly1305Encrypt
	, chaChaPoly1305Decrypt
	) where
import qualified Data.ByteString as B
import qualified Data.ByteString.Internal as B
import Data.SecureMem
import Crypto.Nettle.Ciphers.ForeignImports
import Nettle.Utils
chaChaPoly1305Encrypt
	:: B.ByteString                 
	-> B.ByteString                 
	-> B.ByteString                 
	-> B.ByteString                 
	-> (B.ByteString, B.ByteString) 
chaChaPoly1305Encrypt key nonce aad plain = unsafeDupablePerformIO $ do
	ctx <- allocateSecureMem c_chacha_poly1305_ctx_size
	tag <- B.create 16 (\_ -> return ())
	cipher <- B.create (B.length plain) (\_ -> return ())
	withByteStringPtr plain $ \psize pptr ->
		withByteStringPtr aad $ \aadsize aadptr ->
		withByteStringPtr cipher $ \_ cipherptr ->
		withByteStringPtr tag $ \_ tagptr ->
		withSecureMemPtr ctx $ \ctxptr ->
		withSecureMemPtrSz (toSecureMem key) $ \ksize kptr -> if ksize /= 32 then error "Invalid key length" else
		withSecureMemPtrSz (toSecureMem nonce) $ \nsize nptr -> if nsize /= 12 then error "Invalid nonce length" else do
		c_chacha_poly1305_set_key ctxptr kptr
		c_chacha_poly1305_set_nonce ctxptr nptr
		c_chacha_poly1305_update ctxptr aadsize aadptr
		c_chacha_poly1305_encrypt ctxptr psize cipherptr pptr
		c_chacha_poly1305_digest ctxptr 16 tagptr
	return (cipher, tag)
chaChaPoly1305Decrypt :: B.ByteString -> B.ByteString -> B.ByteString -> B.ByteString -> B.ByteString -> Maybe B.ByteString
chaChaPoly1305Decrypt key nonce aad cipher verifytag = unsafeDupablePerformIO $ do
	ctx <- allocateSecureMem c_chacha_poly1305_ctx_size
	tag <- B.create 16 (\_ -> return ())
	plain <- B.create (B.length cipher) (\_ -> return ())
	withByteStringPtr cipher $ \psize pptr ->
		withByteStringPtr aad $ \aadsize aadptr ->
		withByteStringPtr plain $ \_ plainptr ->
		withByteStringPtr tag $ \_ tagptr ->
		withSecureMemPtr ctx $ \ctxptr ->
		withSecureMemPtrSz (toSecureMem key) $ \ksize kptr -> if ksize /= 32 then error "Invalid key length" else
		withSecureMemPtrSz (toSecureMem nonce) $ \nsize nptr -> if nsize /= 12 then error "Invalid nonce length" else do
		c_chacha_poly1305_set_key ctxptr kptr
		c_chacha_poly1305_set_nonce ctxptr nptr
		c_chacha_poly1305_update ctxptr aadsize aadptr
		c_chacha_poly1305_decrypt ctxptr psize plainptr pptr
		c_chacha_poly1305_digest ctxptr 16 tagptr
	if B.take (B.length verifytag) tag == verifytag then return $ Just plain else return Nothing