-- SPDX-FileCopyrightText: 2020 Serokell -- -- SPDX-License-Identifier: MPL-2.0 -- | Public-key authenticated encryption. -- -- It is best to import this module qualified: -- -- @ -- import qualified Crypto.Box as Box -- -- encrypted = Box.'create' pk sk nonce message -- decrypted = Box.'open' pk sk nonce encrypted -- @ -- -- This is @crypto_box_*@ from NaCl. module Crypto.Box ( PublicKey , toPublicKey , SecretKey , toSecretKey , keypair , Nonce , toNonce , create , open ) where import Data.ByteArray (ByteArray, ByteArrayAccess) import System.IO.Unsafe (unsafeDupablePerformIO) import Crypto.Box.Internal (Nonce, PublicKey, SecretKey, keypair, toNonce, toPublicKey, toSecretKey) import qualified Crypto.Box.Internal as I -- | Encrypt a message. -- -- @ -- encrypted = Box.create pk sk nonce message -- @ -- -- * @pk@ is the receiver’s public key, used for encryption. -- @sk@ is the sender’s public key, used for authentication. -- -- These are generated using 'keypair' and are supposed to be exchanged -- in advance. Both parties need to know their own secret key and the other’s -- public key. -- -- * @nonce@ is an extra noise that ensures that if you encrypt the same -- message with the same key multiple times, you will get different ciphertexts, -- which is required for -- <https://en.wikipedia.org/wiki/Semantic_security semantic security>. -- There are two standard ways of getting it: -- -- 1. /Use a counter/. In this case you keep a counter of encrypted messages, -- which means that the nonce will be new for each new message. -- -- 2. /Random/. You generate a random nonce every time you encrypt a message. -- Since the nonce is large enough, the chances of you using the same -- nonce twice are negligible. For useful helpers, see @Crypto.Random@, -- in <https://hackage.haskell.org/package/crypto-sodium crypto-sodium>. -- -- * @message@ is the data you are encrypting. -- -- This function adds authentication data, so if anyone modifies the cyphertext, -- @open@ will refuse to decrypt it. create :: ( ByteArrayAccess nonceBytes , ByteArrayAccess ptBytes, ByteArray ctBytes ) => PublicKey -- ^ Receiver’s public key -> SecretKey -- ^ Sender’s secret key -> Nonce nonceBytes -- ^ Nonce -> ptBytes -- ^ Plaintext message -> ctBytes create :: PublicKey -> SecretKey -> Nonce nonceBytes -> ptBytes -> ctBytes create pk :: PublicKey pk sk :: SecretKey sk nonce :: Nonce nonceBytes nonce msg :: ptBytes msg = -- This IO is safe, because it is pure. IO ctBytes -> ctBytes forall a. IO a -> a unsafeDupablePerformIO (IO ctBytes -> ctBytes) -> IO ctBytes -> ctBytes forall a b. (a -> b) -> a -> b $ PublicKey -> SecretKey -> Nonce nonceBytes -> ptBytes -> IO ctBytes forall nonce pt ct. (ByteArrayAccess nonce, ByteArrayAccess pt, ByteArray ct) => PublicKey -> SecretKey -> Nonce nonce -> pt -> IO ct I.create PublicKey pk SecretKey sk Nonce nonceBytes nonce ptBytes msg -- | Decrypt a message. -- -- @ -- decrypted = Box.open sk pk nonce encrypted -- @ -- -- * @sk@ is the receiver’s secret key, used for description. -- * @pk@ is the sender’s public key, used for authentication. -- * @nonce@ is the same that was used for encryption. -- * @encrypted@ is the output of 'create'. -- -- This function will return @Nothing@ if the encrypted message was tampered -- with after it was encrypted. open :: ( ByteArrayAccess nonceBytes , ByteArray ptBytes, ByteArrayAccess ctBytes ) => SecretKey -- ^ Receiver’s secret key -> PublicKey -- ^ Sender’s public key -> Nonce nonceBytes -- ^ Nonce -> ctBytes -- ^ Encrypted message (cyphertext) -> Maybe ptBytes open :: SecretKey -> PublicKey -> Nonce nonceBytes -> ctBytes -> Maybe ptBytes open sk :: SecretKey sk pk :: PublicKey pk nonce :: Nonce nonceBytes nonce ct :: ctBytes ct = -- This IO is safe, because it is pure. IO (Maybe ptBytes) -> Maybe ptBytes forall a. IO a -> a unsafeDupablePerformIO (IO (Maybe ptBytes) -> Maybe ptBytes) -> IO (Maybe ptBytes) -> Maybe ptBytes forall a b. (a -> b) -> a -> b $ SecretKey -> PublicKey -> Nonce nonceBytes -> ctBytes -> IO (Maybe ptBytes) forall nonce pt ct. (ByteArrayAccess nonce, ByteArray pt, ByteArrayAccess ct) => SecretKey -> PublicKey -> Nonce nonce -> ct -> IO (Maybe pt) I.open SecretKey sk PublicKey pk Nonce nonceBytes nonce ctBytes ct