mirror of
https://github.com/simplex-chat/simplexmq.git
synced 2026-10-11 22:19:51 +00:00
crypto: sntrup length validation (#1811)
* Validate SNTRUP761 KEM input lengths * crypto: BBS scheme for anonymous credentials with multiple presentations (#1794) * crypto: BBS scheme for anonymous credentials with multiple presentations * verify * add files to sources * more files * more files, use cabal 3.0 * fix path * extensions * switch libbbs to fork * return either from keygen * use only secret key to sign * improve FFI * simplify * update libbbs to support iOS * add commoncrypto flag * bump libbbs * reject input of wrong length * ci: get submodules --------- Co-authored-by: Evgeny @ SimpleX Chat <[email protected]> * 6.5.4.0 * core: add getentropy shim for windows build (#1809) * simplify --------- Co-authored-by: Paul Bottinelli <[email protected]> Co-authored-by: Evgeny @ SimpleX Chat <[email protected]> Co-authored-by: sh <[email protected]>
This commit is contained in:
co-authored by
Evgeny @ SimpleX Chat
Paul Bottinelli
sh
parent
056314396d
commit
aca1d9a462
@@ -1,11 +1,14 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE PatternSynonyms #-}
|
||||
|
||||
module Simplex.Messaging.Crypto.SNTRUP761.Bindings
|
||||
( KEMPublicKey (..),
|
||||
( KEMPublicKey,
|
||||
KEMSecretKey,
|
||||
KEMCiphertext (..),
|
||||
KEMSharedKey (..),
|
||||
KEMCiphertext,
|
||||
KEMSharedKey,
|
||||
pattern KEMPublicKey,
|
||||
pattern KEMSharedKey,
|
||||
KEMKeyPair,
|
||||
sntrup761Keypair,
|
||||
sntrup761Enc,
|
||||
@@ -25,8 +28,9 @@ import Simplex.Messaging.Crypto.SNTRUP761.Bindings.FFI
|
||||
import Simplex.Messaging.Crypto.SNTRUP761.Bindings.RNG (rngFuncPtr, withDRG)
|
||||
import Simplex.Messaging.Encoding
|
||||
import Simplex.Messaging.Encoding.String
|
||||
import Simplex.Messaging.Util ((<$?>))
|
||||
|
||||
newtype KEMPublicKey = KEMPublicKey ByteString
|
||||
newtype KEMPublicKey = KEMPublicKey_ ByteString
|
||||
deriving (Eq, Show)
|
||||
|
||||
newtype KEMSecretKey = KEMSecretKey ScrubbedBytes
|
||||
@@ -35,18 +39,24 @@ newtype KEMSecretKey = KEMSecretKey ScrubbedBytes
|
||||
newtype KEMCiphertext = KEMCiphertext ByteString
|
||||
deriving (Eq, Show)
|
||||
|
||||
newtype KEMSharedKey = KEMSharedKey ScrubbedBytes
|
||||
newtype KEMSharedKey = KEMSharedKey_ ScrubbedBytes
|
||||
deriving (Eq, Show)
|
||||
|
||||
unsafeRevealKEMSharedKey :: KEMSharedKey -> String
|
||||
unsafeRevealKEMSharedKey (KEMSharedKey scrubbed) = show (BA.convert scrubbed :: ByteString)
|
||||
{-# DEPRECATED unsafeRevealKEMSharedKey "unsafeRevealKEMSharedKey left in code" #-}
|
||||
pattern KEMPublicKey :: ByteString -> KEMPublicKey
|
||||
pattern KEMPublicKey s <- KEMPublicKey_ s
|
||||
|
||||
pattern KEMSharedKey :: ScrubbedBytes -> KEMSharedKey
|
||||
pattern KEMSharedKey s <- KEMSharedKey_ s
|
||||
|
||||
{-# COMPLETE KEMPublicKey #-}
|
||||
|
||||
{-# COMPLETE KEMSharedKey #-}
|
||||
|
||||
type KEMKeyPair = (KEMPublicKey, KEMSecretKey)
|
||||
|
||||
sntrup761Keypair :: TVar ChaChaDRG -> IO KEMKeyPair
|
||||
sntrup761Keypair drg =
|
||||
bimap KEMPublicKey KEMSecretKey
|
||||
bimap KEMPublicKey_ KEMSecretKey
|
||||
<$> BA.allocRet
|
||||
c_SNTRUP761_SECRETKEY_SIZE
|
||||
( \skPtr ->
|
||||
@@ -57,7 +67,7 @@ sntrup761Keypair drg =
|
||||
sntrup761Enc :: TVar ChaChaDRG -> KEMPublicKey -> IO (KEMCiphertext, KEMSharedKey)
|
||||
sntrup761Enc drg (KEMPublicKey pk) =
|
||||
BA.withByteArray pk $ \pkPtr ->
|
||||
bimap KEMCiphertext KEMSharedKey
|
||||
bimap KEMCiphertext KEMSharedKey_
|
||||
<$> BA.allocRet
|
||||
c_SNTRUP761_SIZE
|
||||
( \kPtr ->
|
||||
@@ -69,40 +79,47 @@ sntrup761Dec :: KEMCiphertext -> KEMSecretKey -> IO KEMSharedKey
|
||||
sntrup761Dec (KEMCiphertext c) (KEMSecretKey sk) =
|
||||
BA.withByteArray sk $ \skPtr ->
|
||||
BA.withByteArray c $ \cPtr ->
|
||||
KEMSharedKey
|
||||
KEMSharedKey_
|
||||
<$> BA.alloc c_SNTRUP761_SIZE (\kPtr -> c_sntrup761_dec kPtr cPtr skPtr)
|
||||
|
||||
parseKey :: BA.ByteArrayAccess bs => (bs -> key) -> String -> Int -> bs -> Either String key
|
||||
parseKey kCon name expected s
|
||||
| len == expected = Right $ kCon s
|
||||
| otherwise = Left $ name <> " must be " <> show expected <> " bytes, got " <> show len
|
||||
where
|
||||
len = BA.length s
|
||||
|
||||
instance Encoding KEMSecretKey where
|
||||
smpEncode (KEMSecretKey c) = smpEncode . Large $ BA.convert c
|
||||
smpP = KEMSecretKey . BA.convert . unLarge <$> smpP
|
||||
smpP = parseKey KEMSecretKey "SNTRUP761 secret key" c_SNTRUP761_SECRETKEY_SIZE . BA.convert . unLarge <$?> smpP
|
||||
|
||||
instance StrEncoding KEMSecretKey where
|
||||
strEncode (KEMSecretKey pk) = strEncode (BA.convert pk :: ByteString)
|
||||
strP = KEMSecretKey . BA.convert <$> strP @ByteString
|
||||
strP = parseKey KEMSecretKey "SNTRUP761 secret key" c_SNTRUP761_SECRETKEY_SIZE . BA.convert <$?> strP @ByteString
|
||||
|
||||
instance Encoding KEMPublicKey where
|
||||
smpEncode (KEMPublicKey pk) = smpEncode . Large $ BA.convert pk
|
||||
smpP = KEMPublicKey . BA.convert . unLarge <$> smpP
|
||||
smpP = parseKey KEMPublicKey_ "SNTRUP761 public key" c_SNTRUP761_PUBLICKEY_SIZE . unLarge <$?> smpP
|
||||
|
||||
instance StrEncoding KEMPublicKey where
|
||||
strEncode (KEMPublicKey pk) = strEncode (BA.convert pk :: ByteString)
|
||||
strP = KEMPublicKey . BA.convert <$> strP @ByteString
|
||||
strP = parseKey KEMPublicKey_ "SNTRUP761 public key" c_SNTRUP761_PUBLICKEY_SIZE <$?> strP @ByteString
|
||||
|
||||
instance Encoding KEMCiphertext where
|
||||
smpEncode (KEMCiphertext c) = smpEncode . Large $ BA.convert c
|
||||
smpP = KEMCiphertext . BA.convert . unLarge <$> smpP
|
||||
smpP = parseKey KEMCiphertext "SNTRUP761 ciphertext" c_SNTRUP761_CIPHERTEXT_SIZE . unLarge <$?> smpP
|
||||
|
||||
instance Encoding KEMSharedKey where
|
||||
smpEncode (KEMSharedKey c) = smpEncode (BA.convert c :: ByteString)
|
||||
smpP = KEMSharedKey . BA.convert <$> smpP @ByteString
|
||||
smpP = KEMSharedKey_ . BA.convert <$> smpP @ByteString
|
||||
|
||||
instance StrEncoding KEMCiphertext where
|
||||
strEncode (KEMCiphertext pk) = strEncode (BA.convert pk :: ByteString)
|
||||
strP = KEMCiphertext . BA.convert <$> strP @ByteString
|
||||
strP = parseKey KEMCiphertext "SNTRUP761 ciphertext" c_SNTRUP761_CIPHERTEXT_SIZE <$?> strP @ByteString
|
||||
|
||||
instance StrEncoding KEMSharedKey where
|
||||
strEncode (KEMSharedKey pk) = strEncode (BA.convert pk :: ByteString)
|
||||
strP = KEMSharedKey . BA.convert <$> strP @ByteString
|
||||
strP = KEMSharedKey_ . BA.convert <$> strP @ByteString
|
||||
|
||||
instance ToJSON KEMSecretKey where
|
||||
toJSON = strToJSON
|
||||
@@ -130,9 +147,9 @@ instance ToField KEMSharedKey where
|
||||
|
||||
instance FromField KEMSharedKey where
|
||||
#if defined(dbPostgres)
|
||||
fromField f dat = KEMSharedKey . BA.convert @ByteString <$> fromField f dat
|
||||
fromField f dat = KEMSharedKey_ . BA.convert @ByteString <$> fromField f dat
|
||||
#else
|
||||
fromField f = KEMSharedKey . BA.convert @ByteString <$> fromField f
|
||||
fromField f = KEMSharedKey_ . BA.convert @ByteString <$> fromField f
|
||||
#endif
|
||||
|
||||
instance ToJSON KEMSharedKey where
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{-# LANGUAGE GADTs #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# OPTIONS_GHC -Wno-orphans #-}
|
||||
|
||||
module CoreTests.CryptoTests (cryptoTests) where
|
||||
@@ -10,7 +11,7 @@ import Control.Monad.Except
|
||||
import qualified Data.Aeson as J
|
||||
import qualified Data.ByteString.Char8 as B
|
||||
import qualified Data.ByteString.Lazy.Char8 as LB
|
||||
import Data.Either (isRight)
|
||||
import Data.Either (isLeft, isRight)
|
||||
import Data.Int (Int64)
|
||||
import qualified Data.Text as T
|
||||
import Data.Text.Encoding (encodeUtf8)
|
||||
@@ -25,10 +26,13 @@ import qualified Simplex.Messaging.Crypto as C
|
||||
import qualified Simplex.Messaging.Crypto.Lazy as LC
|
||||
import Simplex.Messaging.Crypto.BBS
|
||||
import Simplex.Messaging.Crypto.SNTRUP761.Bindings
|
||||
import Simplex.Messaging.Crypto.SNTRUP761.Bindings.Defines
|
||||
import Simplex.Messaging.Encoding (Large (..), smpDecode, smpEncode)
|
||||
import Simplex.Messaging.Encoding.String (strDecode, strEncode)
|
||||
import Simplex.Messaging.Transport.Client
|
||||
import Test.Hspec hiding (fit, it)
|
||||
import Test.Hspec.QuickCheck (modifyMaxSuccess)
|
||||
import Test.QuickCheck
|
||||
import Test.QuickCheck hiding (Large)
|
||||
import Util
|
||||
|
||||
cryptoTests :: Spec
|
||||
@@ -101,8 +105,9 @@ cryptoTests = do
|
||||
describe "X448" $ testEncoding C.SX448
|
||||
describe "X509 chains" $ do
|
||||
it "should validate certificates" testValidateX509
|
||||
describe "sntrup761" $
|
||||
describe "sntrup761" $ do
|
||||
it "should enc/dec key" testSNTRUP761
|
||||
it "should reject malformed KEM encodings" testSNTRUP761RejectsMalformedEncodings
|
||||
describe "BBS+" $ do
|
||||
it "should sign and verify" testBBSSignVerify
|
||||
it "should derive public key from secret key" testBBSPublicKeyDerivation
|
||||
@@ -284,6 +289,34 @@ testSNTRUP761 = do
|
||||
KEMSharedKey k' <- sntrup761Dec c sk
|
||||
k' `shouldBe` k
|
||||
|
||||
testSNTRUP761RejectsMalformedEncodings :: IO ()
|
||||
testSNTRUP761RejectsMalformedEncodings = do
|
||||
smpDecode @KEMPublicKey (smpEncode $ Large shortPublicKey) `shouldSatisfy` isLeft
|
||||
strDecode @KEMPublicKey (strEncode shortPublicKey) `shouldSatisfy` isLeft
|
||||
smpDecode @KEMPublicKey (smpEncode $ Large validPublicKey) `shouldSatisfy` isRight
|
||||
strDecode @KEMPublicKey (strEncode validPublicKey) `shouldSatisfy` isRight
|
||||
smpDecode @KEMCiphertext (smpEncode $ Large shortCiphertext) `shouldSatisfy` isLeft
|
||||
strDecode @KEMCiphertext (strEncode shortCiphertext) `shouldSatisfy` isLeft
|
||||
smpDecode @KEMCiphertext (smpEncode $ Large validCiphertext) `shouldSatisfy` isRight
|
||||
strDecode @KEMCiphertext (strEncode validCiphertext) `shouldSatisfy` isRight
|
||||
smpDecode @KEMSecretKey (smpEncode $ Large shortSecretKey) `shouldSatisfy` isLeft
|
||||
strDecode @KEMSecretKey (strEncode shortSecretKey) `shouldSatisfy` isLeft
|
||||
|
||||
shortPublicKey :: B.ByteString
|
||||
shortPublicKey = B.replicate (c_SNTRUP761_PUBLICKEY_SIZE - 1) 'p'
|
||||
|
||||
validPublicKey :: B.ByteString
|
||||
validPublicKey = B.replicate c_SNTRUP761_PUBLICKEY_SIZE 'p'
|
||||
|
||||
shortCiphertext :: B.ByteString
|
||||
shortCiphertext = B.replicate (c_SNTRUP761_CIPHERTEXT_SIZE - 1) 'c'
|
||||
|
||||
validCiphertext :: B.ByteString
|
||||
validCiphertext = B.replicate c_SNTRUP761_CIPHERTEXT_SIZE 'c'
|
||||
|
||||
shortSecretKey :: B.ByteString
|
||||
shortSecretKey = B.replicate (c_SNTRUP761_SECRETKEY_SIZE - 1) 's'
|
||||
|
||||
-- BBS+ tests
|
||||
|
||||
bbsHeader :: BBSHeader
|
||||
|
||||
Reference in New Issue
Block a user