diff options
| author | Roland Shoemaker <roland@golang.org> | 2022-08-16 10:25:35 -0700 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2022-08-29 22:05:03 +0000 |
| commit | c86fa9a7ed909e2f2a8ab8298254fca727aba16a (patch) | |
| tree | bc4b14bd551c64c545422d6e302f4eb7564a1711 | |
| parent | bd7e27e6170dc8db5a8588e1ac1e971eae90710f (diff) | |
| download | go-x-crypto-c86fa9a7ed909e2f2a8ab8298254fca727aba16a.tar.xz | |
internal/wycheproof: add crypto/ecdh tests
Alongside the existing ECDH tests, add tests that use the new
crypto/ecdh package. The test vectors include a number of private
that use non-standard sizes, which we reject, but aren't flagged,
so we need to skip them.
Change-Id: Iaaef225b0149a86833095f51748d230385d43bfe
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/424274
Reviewed-by: Russ Cox <rsc@golang.org>
Run-TryBot: Roland Shoemaker <roland@golang.org>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
| -rw-r--r-- | internal/wycheproof/ecdh_stdlib_test.go | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/internal/wycheproof/ecdh_stdlib_test.go b/internal/wycheproof/ecdh_stdlib_test.go new file mode 100644 index 0000000..44315fc --- /dev/null +++ b/internal/wycheproof/ecdh_stdlib_test.go @@ -0,0 +1,142 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.20 + +package wycheproof + +import ( + "bytes" + "crypto/ecdh" + "fmt" + "testing" +) + +func TestECDHStdLib(t *testing.T) { + type ECDHTestVector struct { + // A brief description of the test case + Comment string `json:"comment,omitempty"` + // A list of flags + Flags []string `json:"flags,omitempty"` + // the private key + Private string `json:"private,omitempty"` + // Encoded public key + Public string `json:"public,omitempty"` + // Test result + Result string `json:"result,omitempty"` + // The shared secret key + Shared string `json:"shared,omitempty"` + // Identifier of the test case + TcID int `json:"tcId,omitempty"` + } + + type ECDHTestGroup struct { + Curve string `json:"curve,omitempty"` + Tests []*ECDHTestVector `json:"tests,omitempty"` + } + + type Root struct { + TestGroups []*ECDHTestGroup `json:"testGroups,omitempty"` + } + + flagsShouldPass := map[string]bool{ + // We don't support compressed points. + "CompressedPoint": false, + // We don't support decoding custom curves. + "UnnamedCurve": false, + // WrongOrder and UnusedParam are only found with UnnamedCurve. + "WrongOrder": false, + "UnusedParam": false, + + // X25519 specific flags + "Twist": true, + "SmallPublicKey": false, + "LowOrderPublic": false, + "ZeroSharedSecret": false, + "NonCanonicalPublic": true, + } + + // curveToCurve is a map of all elliptic curves supported + // by crypto/elliptic, which can subsequently be parsed and tested. + curveToCurve := map[string]ecdh.Curve{ + "secp256r1": ecdh.P256(), + "secp384r1": ecdh.P384(), + "secp521r1": ecdh.P521(), + "curve25519": ecdh.X25519(), + } + + curveToKeySize := map[string]int{ + "secp256r1": 32, + "secp384r1": 48, + "secp521r1": 66, + "curve25519": 32, + } + + for _, f := range []string{ + "ecdh_secp256r1_ecpoint_test.json", + "ecdh_secp384r1_ecpoint_test.json", + "ecdh_secp521r1_ecpoint_test.json", + "x25519_test.json", + } { + var root Root + readTestVector(t, f, &root) + for _, tg := range root.TestGroups { + if _, ok := curveToCurve[tg.Curve]; !ok { + continue + } + for _, tt := range tg.Tests { + tg, tt := tg, tt + t.Run(fmt.Sprintf("%s/%d", tg.Curve, tt.TcID), func(t *testing.T) { + t.Logf("Type: %v", tt.Result) + t.Logf("Flags: %q", tt.Flags) + t.Log(tt.Comment) + + shouldPass := shouldPass(tt.Result, tt.Flags, flagsShouldPass) + + curve := curveToCurve[tg.Curve] + p := decodeHex(tt.Public) + pub, err := curve.NewPublicKey(p) + if err != nil { + if shouldPass { + t.Errorf("NewPublicKey: %v", err) + } + return + } + + privBytes := decodeHex(tt.Private) + if len(privBytes) != curveToKeySize[tg.Curve] { + t.Skipf("non-standard key size %d", len(privBytes)) + } + + priv, err := curve.NewPrivateKey(privBytes) + if err != nil { + if shouldPass { + t.Errorf("NewPrivateKey: %v", err) + } + return + } + + shared := decodeHex(tt.Shared) + x, err := curve.ECDH(priv, pub) + if err != nil { + if tg.Curve == "curve25519" && !shouldPass { + // ECDH is expected to only return an error when using X25519, + // in all other cases an error is unexpected. + return + } + t.Fatalf("ECDH: %v", err) + } + + if bytes.Equal(shared, x) != shouldPass { + if shouldPass { + t.Errorf("ECDH = %x, want %x", shared, x) + } else { + t.Errorf("ECDH = %x, want anything else", shared) + } + } + }) + } + } + } +} |
