Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 64 additions & 9 deletions botan-low/test/Test/Botan/Low/PubKey/KeyAgreement.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ module Test.Botan.Low.PubKey.KeyAgreement (tests) where
import Botan.Low.PubKey
import Botan.Low.PubKey.KeyAgreement
import Botan.Low.RNG
import Control.Monad (forM_)
import Data.ByteString
import qualified Data.ByteString as ByteString
import Test.Hspec
import Test.Tasty
import Test.Tasty.Hspec
Expand All @@ -15,15 +17,19 @@ import Test.Util.Hspec
tests :: IO TestTree
tests = do
specs <- testSpec "spec_keyAgreement" spec_keyAgreement
specs_matrix <- testSpec "spec_keyAgreement_matrix" spec_keyAgreement_matrix
pure $ testGroup "Test.Botan.Low.PubKey.KeyAgreement" [
specs
specs,
specs_matrix
]

-- TODO: More thorough test with different KDFs and curves / groups
pks :: [(ByteString, ByteString)]
pks =
[ ("DH", "modp/ietf/1024")
[ ("DH", "modp/ietf/2048")
, ("DH", "ffdhe/ietf/3072")
, ("ECDH", "secp256r1")
, ("ECDH", "secp384r1")
, ("ECDH", "secp256k1")
, ("Curve25519", "")
]

Expand All @@ -49,15 +55,64 @@ spec_keyAgreement = testSuite pks pkTestName $ \ (pk, param) -> do
ka <- keyAgreementCreate privKey "HKDF(SHA-256)"
_kaSz <- keyAgreementSize ka
pass
it "keyAgreement" $ do
it "keyAgreement derives different keys for different salts" $ do
rng <- rngInit "system"
privKeyA <- privKeyCreate pk param rng
pubKeyA <- keyAgreementExportPublic privKeyA
privKeyB <- privKeyCreate pk param rng
pubKeyB <- keyAgreementExportPublic privKeyB
kaA <- keyAgreementCreate privKeyA "HKDF(SHA-256)"
kaB <- keyAgreementCreate privKeyB "HKDF(SHA-256)"
sharedKeyA <- keyAgreement kaA pubKeyB "salt"
sharedKeyB <- keyAgreement kaB pubKeyA "salt"
sharedKeyA `shouldBe` sharedKeyB
sharedKeyA1 <- keyAgreement kaA pubKeyB "salt-1"
sharedKeyA2 <- keyAgreement kaA pubKeyB "salt-2"
sharedKeyA1 `shouldNotBe` sharedKeyA2
pass
it "keyAgreement output size matches keyAgreementSize" $ do
rng <- rngInit "system"
privKeyA <- privKeyCreate pk param rng
privKeyB <- privKeyCreate pk param rng
pubKeyB <- keyAgreementExportPublic privKeyB
kaA <- keyAgreementCreate privKeyA "HKDF(SHA-256)"
kaSize <- keyAgreementSize kaA
sharedKey <- keyAgreement kaA pubKeyB "salt"
ByteString.length sharedKey `shouldBe` kaSize
pass

kdfs :: [ByteString]
kdfs =
[ "HKDF(SHA-256)"
, "HKDF(SHA-384)"
, "KDF2(SHA-256)"
]

type PkSpec = (ByteString, ByteString)
type KdfSpec = ByteString

cases :: [(PkSpec, KdfSpec)]
cases =
[ (pkSpec, kdf)
| pkSpec <- pks
, kdf <- kdfs
]

caseTestName :: (PkSpec, KdfSpec) -> String
caseTestName ((pk, param), kdf) =
chars $ pk <> paramPart <> " / " <> kdf
where
paramPart
| param == "" = ""
| otherwise = " " <> param

spec_keyAgreement_matrix :: Spec
spec_keyAgreement_matrix = do
forM_ cases $ \ ((pk, param), kdf) ->
it ("keyAgreement " <> caseTestName ((pk, param), kdf)) $ do
rng <- rngInit "system"
privKeyA <- privKeyCreate pk param rng
pubKeyA <- keyAgreementExportPublic privKeyA
privKeyB <- privKeyCreate pk param rng
pubKeyB <- keyAgreementExportPublic privKeyB
kaA <- keyAgreementCreate privKeyA kdf
kaB <- keyAgreementCreate privKeyB kdf
sharedKeyA <- keyAgreement kaA pubKeyB "salt"
sharedKeyB <- keyAgreement kaB pubKeyA "salt"
sharedKeyA `shouldBe` sharedKeyB
pass