1*e7b1675dSTing-Kang Chang// Copyright 2021 Google LLC 2*e7b1675dSTing-Kang Chang// 3*e7b1675dSTing-Kang Chang// Licensed under the Apache License, Version 2.0 (the "License"); 4*e7b1675dSTing-Kang Chang// you may not use this file except in compliance with the License. 5*e7b1675dSTing-Kang Chang// You may obtain a copy of the License at 6*e7b1675dSTing-Kang Chang// 7*e7b1675dSTing-Kang Chang// http://www.apache.org/licenses/LICENSE-2.0 8*e7b1675dSTing-Kang Chang// 9*e7b1675dSTing-Kang Chang// Unless required by applicable law or agreed to in writing, software 10*e7b1675dSTing-Kang Chang// distributed under the License is distributed on an "AS IS" BASIS, 11*e7b1675dSTing-Kang Chang// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*e7b1675dSTing-Kang Chang// See the License for the specific language governing permissions and 13*e7b1675dSTing-Kang Chang// limitations under the License. 14*e7b1675dSTing-Kang Chang// 15*e7b1675dSTing-Kang Chang//////////////////////////////////////////////////////////////////////////////// 16*e7b1675dSTing-Kang Chang 17*e7b1675dSTing-Kang Changpackage subtle_test 18*e7b1675dSTing-Kang Chang 19*e7b1675dSTing-Kang Changimport ( 20*e7b1675dSTing-Kang Chang "crypto/rand" 21*e7b1675dSTing-Kang Chang "encoding/hex" 22*e7b1675dSTing-Kang Chang "fmt" 23*e7b1675dSTing-Kang Chang "testing" 24*e7b1675dSTing-Kang Chang 25*e7b1675dSTing-Kang Chang "golang.org/x/crypto/curve25519" 26*e7b1675dSTing-Kang Chang "github.com/google/tink/go/subtle" 27*e7b1675dSTing-Kang Chang "github.com/google/tink/go/testutil" 28*e7b1675dSTing-Kang Chang) 29*e7b1675dSTing-Kang Chang 30*e7b1675dSTing-Kang Changfunc TestComputeSharedSecretX25519WithRFCTestVectors(t *testing.T) { 31*e7b1675dSTing-Kang Chang // Test vectors are defined at 32*e7b1675dSTing-Kang Chang // https://datatracker.ietf.org/doc/html/rfc7748#section-6.1. 33*e7b1675dSTing-Kang Chang tests := []struct { 34*e7b1675dSTing-Kang Chang priv string 35*e7b1675dSTing-Kang Chang pub string 36*e7b1675dSTing-Kang Chang }{ 37*e7b1675dSTing-Kang Chang {"5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb", "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a"}, 38*e7b1675dSTing-Kang Chang {"77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a", "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f"}, 39*e7b1675dSTing-Kang Chang } 40*e7b1675dSTing-Kang Chang shared := "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742" 41*e7b1675dSTing-Kang Chang 42*e7b1675dSTing-Kang Chang for i, test := range tests { 43*e7b1675dSTing-Kang Chang t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { 44*e7b1675dSTing-Kang Chang priv, err := hex.DecodeString(test.priv) 45*e7b1675dSTing-Kang Chang if err != nil { 46*e7b1675dSTing-Kang Chang t.Fatalf("DecodeString(priv): got err %q, want nil", err) 47*e7b1675dSTing-Kang Chang } 48*e7b1675dSTing-Kang Chang pub, err := hex.DecodeString(test.pub) 49*e7b1675dSTing-Kang Chang if err != nil { 50*e7b1675dSTing-Kang Chang t.Fatalf("DecodeString(pub): got err %q, want nil", err) 51*e7b1675dSTing-Kang Chang } 52*e7b1675dSTing-Kang Chang 53*e7b1675dSTing-Kang Chang gotShared, err := subtle.ComputeSharedSecretX25519(priv, pub) 54*e7b1675dSTing-Kang Chang if err != nil { 55*e7b1675dSTing-Kang Chang t.Fatalf("ComputeSharedSecretX25519(priv, pub): got err %q, want nil", err) 56*e7b1675dSTing-Kang Chang } 57*e7b1675dSTing-Kang Chang if got, want := hex.EncodeToString(gotShared), shared; got != want { 58*e7b1675dSTing-Kang Chang t.Errorf("ComputeSharedSecretX25519(shared): got %v, want %v", got, want) 59*e7b1675dSTing-Kang Chang } 60*e7b1675dSTing-Kang Chang }) 61*e7b1675dSTing-Kang Chang } 62*e7b1675dSTing-Kang Chang} 63*e7b1675dSTing-Kang Chang 64*e7b1675dSTing-Kang Changtype x25519Suite struct { 65*e7b1675dSTing-Kang Chang testutil.WycheproofSuite 66*e7b1675dSTing-Kang Chang TestGroups []*x25519Group `json:"testGroups"` 67*e7b1675dSTing-Kang Chang} 68*e7b1675dSTing-Kang Chang 69*e7b1675dSTing-Kang Changtype x25519Group struct { 70*e7b1675dSTing-Kang Chang testutil.WycheproofGroup 71*e7b1675dSTing-Kang Chang Curve string `json:"curve"` 72*e7b1675dSTing-Kang Chang Tests []*x25519Case `json:"tests"` 73*e7b1675dSTing-Kang Chang} 74*e7b1675dSTing-Kang Chang 75*e7b1675dSTing-Kang Changtype x25519Case struct { 76*e7b1675dSTing-Kang Chang testutil.WycheproofCase 77*e7b1675dSTing-Kang Chang Public string `json:"public"` 78*e7b1675dSTing-Kang Chang Private string `json:"private"` 79*e7b1675dSTing-Kang Chang Shared string `json:"shared"` 80*e7b1675dSTing-Kang Chang Result string `json:"result"` 81*e7b1675dSTing-Kang Chang Flags []string `json:"flags"` 82*e7b1675dSTing-Kang Chang} 83*e7b1675dSTing-Kang Chang 84*e7b1675dSTing-Kang Changfunc TestComputeSharedSecretX25519WithWycheproofVectors(t *testing.T) { 85*e7b1675dSTing-Kang Chang testutil.SkipTestIfTestSrcDirIsNotSet(t) 86*e7b1675dSTing-Kang Chang 87*e7b1675dSTing-Kang Chang suite := new(x25519Suite) 88*e7b1675dSTing-Kang Chang if err := testutil.PopulateSuite(suite, "x25519_test.json"); err != nil { 89*e7b1675dSTing-Kang Chang t.Fatalf("testutil.PopulateSuite: %v", err) 90*e7b1675dSTing-Kang Chang } 91*e7b1675dSTing-Kang Chang 92*e7b1675dSTing-Kang Chang for _, group := range suite.TestGroups { 93*e7b1675dSTing-Kang Chang if group.Curve != "curve25519" { 94*e7b1675dSTing-Kang Chang continue 95*e7b1675dSTing-Kang Chang } 96*e7b1675dSTing-Kang Chang 97*e7b1675dSTing-Kang Chang for _, test := range group.Tests { 98*e7b1675dSTing-Kang Chang t.Run(fmt.Sprintf("%d", test.CaseID), func(t *testing.T) { 99*e7b1675dSTing-Kang Chang pub, err := hex.DecodeString(test.Public) 100*e7b1675dSTing-Kang Chang if err != nil { 101*e7b1675dSTing-Kang Chang t.Fatalf("DecodeString(pub): got err %q, want nil", err) 102*e7b1675dSTing-Kang Chang } 103*e7b1675dSTing-Kang Chang priv, err := hex.DecodeString(test.Private) 104*e7b1675dSTing-Kang Chang if err != nil { 105*e7b1675dSTing-Kang Chang t.Fatalf("DecodeString(priv): got err %q, want nil", err) 106*e7b1675dSTing-Kang Chang } 107*e7b1675dSTing-Kang Chang 108*e7b1675dSTing-Kang Chang gotShared, err := subtle.ComputeSharedSecretX25519(priv, pub) 109*e7b1675dSTing-Kang Chang // ComputeSharedSecretX25519 fails on low order public values. 110*e7b1675dSTing-Kang Chang wantErr := false 111*e7b1675dSTing-Kang Chang for _, flag := range test.Flags { 112*e7b1675dSTing-Kang Chang if flag == "LowOrderPublic" { 113*e7b1675dSTing-Kang Chang wantErr = true 114*e7b1675dSTing-Kang Chang } 115*e7b1675dSTing-Kang Chang } 116*e7b1675dSTing-Kang Chang 117*e7b1675dSTing-Kang Chang if wantErr { 118*e7b1675dSTing-Kang Chang if err == nil { 119*e7b1675dSTing-Kang Chang t.Error("ComputeSharedSecretX25519(priv, pub): got success, want err") 120*e7b1675dSTing-Kang Chang } 121*e7b1675dSTing-Kang Chang } else { 122*e7b1675dSTing-Kang Chang if err != nil { 123*e7b1675dSTing-Kang Chang t.Errorf("ComputeSharedSecretX25519(priv, pub): got err %q, want nil", err) 124*e7b1675dSTing-Kang Chang } 125*e7b1675dSTing-Kang Chang if got, want := hex.EncodeToString(gotShared), test.Shared; got != want { 126*e7b1675dSTing-Kang Chang t.Errorf("ComputeSharedSecretX25519(shared): got %v, want %v", got, want) 127*e7b1675dSTing-Kang Chang } 128*e7b1675dSTing-Kang Chang } 129*e7b1675dSTing-Kang Chang }) 130*e7b1675dSTing-Kang Chang } 131*e7b1675dSTing-Kang Chang } 132*e7b1675dSTing-Kang Chang} 133*e7b1675dSTing-Kang Chang 134*e7b1675dSTing-Kang Changfunc TestComputeSharedSecretX25519Fails(t *testing.T) { 135*e7b1675dSTing-Kang Chang pubs := []string{ 136*e7b1675dSTing-Kang Chang // Should fail on non-32-byte inputs. 137*e7b1675dSTing-Kang Chang "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c", 138*e7b1675dSTing-Kang Chang "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a2a", 139*e7b1675dSTing-Kang Chang // Should fail on low order points, from Sodium 140*e7b1675dSTing-Kang Chang // https://github.com/jedisct1/libsodium/blob/65621a1059a37d/src/libsodium/crypto_scalarmult/curve25519/ref10/x25519_ref10.c#L11-L70. 141*e7b1675dSTing-Kang Chang "0000000000000000000000000000000000000000000000000000000000000000", 142*e7b1675dSTing-Kang Chang "0100000000000000000000000000000000000000000000000000000000000000", 143*e7b1675dSTing-Kang Chang "e0eb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b800", 144*e7b1675dSTing-Kang Chang "5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157", 145*e7b1675dSTing-Kang Chang "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", 146*e7b1675dSTing-Kang Chang "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", 147*e7b1675dSTing-Kang Chang "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", 148*e7b1675dSTing-Kang Chang } 149*e7b1675dSTing-Kang Chang 150*e7b1675dSTing-Kang Chang priv := make([]byte, curve25519.ScalarSize) 151*e7b1675dSTing-Kang Chang if _, err := rand.Read(priv); err != nil { 152*e7b1675dSTing-Kang Chang t.Fatal(err) 153*e7b1675dSTing-Kang Chang } 154*e7b1675dSTing-Kang Chang 155*e7b1675dSTing-Kang Chang for i, pubHex := range pubs { 156*e7b1675dSTing-Kang Chang t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { 157*e7b1675dSTing-Kang Chang pub, err := hex.DecodeString(pubHex) 158*e7b1675dSTing-Kang Chang if err != nil { 159*e7b1675dSTing-Kang Chang t.Fatalf("DecodeString(pub): got err %q, want nil", err) 160*e7b1675dSTing-Kang Chang } 161*e7b1675dSTing-Kang Chang if _, err := subtle.ComputeSharedSecretX25519(priv, pub); err == nil { 162*e7b1675dSTing-Kang Chang t.Error("ComputeSharedSecretX25519(priv, pub): got success, want err") 163*e7b1675dSTing-Kang Chang } 164*e7b1675dSTing-Kang Chang }) 165*e7b1675dSTing-Kang Chang } 166*e7b1675dSTing-Kang Chang} 167*e7b1675dSTing-Kang Chang 168*e7b1675dSTing-Kang Changfunc TestPublicFromPrivateX25519WithRFCTestVectors(t *testing.T) { 169*e7b1675dSTing-Kang Chang // Test vectors are defined at 170*e7b1675dSTing-Kang Chang // https://datatracker.ietf.org/doc/html/rfc7748#section-6.1. 171*e7b1675dSTing-Kang Chang tests := []struct { 172*e7b1675dSTing-Kang Chang priv string 173*e7b1675dSTing-Kang Chang pub string 174*e7b1675dSTing-Kang Chang }{ 175*e7b1675dSTing-Kang Chang {"77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a", "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a"}, 176*e7b1675dSTing-Kang Chang {"5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb", "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f"}, 177*e7b1675dSTing-Kang Chang } 178*e7b1675dSTing-Kang Chang 179*e7b1675dSTing-Kang Chang for i, test := range tests { 180*e7b1675dSTing-Kang Chang t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { 181*e7b1675dSTing-Kang Chang priv, err := hex.DecodeString(test.priv) 182*e7b1675dSTing-Kang Chang if err != nil { 183*e7b1675dSTing-Kang Chang t.Fatalf("DecodeString(priv): got err %q, want nil", err) 184*e7b1675dSTing-Kang Chang } 185*e7b1675dSTing-Kang Chang gotPub, err := subtle.PublicFromPrivateX25519(priv) 186*e7b1675dSTing-Kang Chang if err != nil { 187*e7b1675dSTing-Kang Chang t.Fatalf("PublicFromPrivateX25519(priv): got err %q, want nil", err) 188*e7b1675dSTing-Kang Chang } 189*e7b1675dSTing-Kang Chang if got, want := hex.EncodeToString(gotPub), test.pub; got != want { 190*e7b1675dSTing-Kang Chang t.Errorf("PublicFromPrivateX25519(priv): got %s, want %s", got, want) 191*e7b1675dSTing-Kang Chang } 192*e7b1675dSTing-Kang Chang }) 193*e7b1675dSTing-Kang Chang } 194*e7b1675dSTing-Kang Chang} 195*e7b1675dSTing-Kang Chang 196*e7b1675dSTing-Kang Changfunc TestPublicFromPrivateX25519Fails(t *testing.T) { 197*e7b1675dSTing-Kang Chang // PublicFromPrivateX25519 fails on non-32-byte private keys. 198*e7b1675dSTing-Kang Chang privs := []string{ 199*e7b1675dSTing-Kang Chang "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c", 200*e7b1675dSTing-Kang Chang "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb95", 201*e7b1675dSTing-Kang Chang } 202*e7b1675dSTing-Kang Chang 203*e7b1675dSTing-Kang Chang for i, priv := range privs { 204*e7b1675dSTing-Kang Chang t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { 205*e7b1675dSTing-Kang Chang priv, err := hex.DecodeString(priv) 206*e7b1675dSTing-Kang Chang if err != nil { 207*e7b1675dSTing-Kang Chang t.Fatalf("DecodeString(priv): got err %q, want nil", err) 208*e7b1675dSTing-Kang Chang } 209*e7b1675dSTing-Kang Chang if _, err := subtle.PublicFromPrivateX25519(priv); err == nil { 210*e7b1675dSTing-Kang Chang t.Error("PublicFromPrivateX25519(priv): got success, want err") 211*e7b1675dSTing-Kang Chang } 212*e7b1675dSTing-Kang Chang }) 213*e7b1675dSTing-Kang Chang } 214*e7b1675dSTing-Kang Chang} 215