add NaCl crypto_box scheme

This commit is contained in:
Evgeny Poberezkin
2021-12-12 22:59:11 +00:00
parent bfa05c9432
commit 560d9ceb71
+38
View File
@@ -44,6 +44,7 @@ module Simplex.Messaging.Crypto
CryptoPrivateKey (..),
KeyPair,
DhSecret (..),
ADhSecret (..),
CryptoDhSecret (..),
KeyHash (..),
generateKeyPair,
@@ -77,6 +78,7 @@ module Simplex.Messaging.Crypto
-- * DH derivation
dh',
dhSecret,
dhSecret',
-- * AES256 AEAD-GCM scheme
Key (..),
@@ -91,6 +93,10 @@ module Simplex.Messaging.Crypto
aesKeyP,
ivP,
-- * NaCl crypto_box
cbEncrypt,
cbDecrypt,
-- * Encoding of RSA keys
publicKeyHash,
@@ -107,8 +113,10 @@ import Control.Monad.Except
import Control.Monad.Trans.Except
import Crypto.Cipher.AES (AES256)
import qualified Crypto.Cipher.Types as AES
import qualified Crypto.Cipher.XSalsa as XSalsa
import qualified Crypto.Error as CE
import Crypto.Hash (Digest, SHA256 (..), hash)
import qualified Crypto.MAC.Poly1305 as Poly1305
import Crypto.Number.Generate (generateMax)
import Crypto.Number.Prime (findPrimeFrom)
import qualified Crypto.PubKey.Curve25519 as X25519
@@ -747,6 +755,8 @@ data CryptoError
CryptoIVError
| -- | AES decryption error
AESDecryptError
| -- CryptoBox decryption error
CBDecryptError
| -- | message does not fit in SMP block
CryptoLargeMsgError
| -- | failure parsing RSA-encrypted message header
@@ -982,6 +992,34 @@ dh' :: DhAlgorithm a => PublicKey a -> PrivateKey a -> DhSecret a
dh' (PublicKeyX25519 k) (PrivateKeyX25519 pk) = DhSecretX25519 $ X25519.dh k pk
dh' (PublicKeyX448 k) (PrivateKeyX448 pk) = DhSecretX448 $ X448.dh k pk
-- | NaCl @crypto_box@ encrypt with a shared DH secret and 192-bit nonce.
cbEncrypt :: DhSecret X25519 -> ByteString -> ByteString -> ByteString
cbEncrypt secret nonce msg = BA.convert tag `B.append` c
where
(rs, c) = xSalsa20 secret nonce msg
tag = Poly1305.auth rs c
-- | NaCl @crypto_box@ decrypt with a shared DH secret and 192-bit nonce.
cbDecrypt :: DhSecret X25519 -> ByteString -> ByteString -> Either CryptoError ByteString
cbDecrypt secret nonce packet
| B.length packet < 16 = Left CBDecryptError
| BA.constEq tag' tag = Right msg
| otherwise = Left CBDecryptError
where
(tag', c) = B.splitAt 16 packet
(rs, msg) = xSalsa20 secret nonce c
tag = Poly1305.auth rs c
xSalsa20 :: DhSecret X25519 -> ByteString -> ByteString -> (ByteString, ByteString)
xSalsa20 (DhSecretX25519 shared) nonce msg = (rs, msg')
where
zero = B.replicate 16 $ toEnum 0
(iv0, iv1) = B.splitAt 8 nonce
state0 = XSalsa.initialize 20 shared (zero `B.append` iv0)
state1 = XSalsa.derive state0 iv1
(rs, state2) = XSalsa.generate state1 32
(msg', _) = XSalsa.combine state2 msg
pubVerifyKey :: APublicKey -> Either String APublicVerifyKey
pubVerifyKey (APublicKey a k) = case signatureAlgorithm a of
Just Dict -> Right $ APublicVerifyKey a k