1// Copyright 2016 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package ed25519 6 7import ( 8 "bufio" 9 "bytes" 10 "compress/gzip" 11 "crypto" 12 "crypto/internal/boring" 13 "crypto/rand" 14 "crypto/sha512" 15 "encoding/hex" 16 "internal/testenv" 17 "log" 18 "os" 19 "strings" 20 "testing" 21) 22 23func Example_ed25519ctx() { 24 pub, priv, err := GenerateKey(nil) 25 if err != nil { 26 log.Fatal(err) 27 } 28 29 msg := []byte("The quick brown fox jumps over the lazy dog") 30 31 sig, err := priv.Sign(nil, msg, &Options{ 32 Context: "Example_ed25519ctx", 33 }) 34 if err != nil { 35 log.Fatal(err) 36 } 37 38 if err := VerifyWithOptions(pub, msg, sig, &Options{ 39 Context: "Example_ed25519ctx", 40 }); err != nil { 41 log.Fatal("invalid signature") 42 } 43} 44 45type zeroReader struct{} 46 47func (zeroReader) Read(buf []byte) (int, error) { 48 clear(buf) 49 return len(buf), nil 50} 51 52func TestSignVerify(t *testing.T) { 53 var zero zeroReader 54 public, private, _ := GenerateKey(zero) 55 56 message := []byte("test message") 57 sig := Sign(private, message) 58 if !Verify(public, message, sig) { 59 t.Errorf("valid signature rejected") 60 } 61 62 wrongMessage := []byte("wrong message") 63 if Verify(public, wrongMessage, sig) { 64 t.Errorf("signature of different message accepted") 65 } 66} 67 68func TestSignVerifyHashed(t *testing.T) { 69 // From RFC 8032, Section 7.3 70 key, _ := hex.DecodeString("833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf") 71 expectedSig, _ := hex.DecodeString("98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae4131f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406") 72 message, _ := hex.DecodeString("616263") 73 74 private := PrivateKey(key) 75 public := private.Public().(PublicKey) 76 hash := sha512.Sum512(message) 77 sig, err := private.Sign(nil, hash[:], crypto.SHA512) 78 if err != nil { 79 t.Fatal(err) 80 } 81 if !bytes.Equal(sig, expectedSig) { 82 t.Error("signature doesn't match test vector") 83 } 84 sig, err = private.Sign(nil, hash[:], &Options{Hash: crypto.SHA512}) 85 if err != nil { 86 t.Fatal(err) 87 } 88 if !bytes.Equal(sig, expectedSig) { 89 t.Error("signature doesn't match test vector") 90 } 91 if err := VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA512}); err != nil { 92 t.Errorf("valid signature rejected: %v", err) 93 } 94 95 if err := VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA256}); err == nil { 96 t.Errorf("expected error for wrong hash") 97 } 98 99 wrongHash := sha512.Sum512([]byte("wrong message")) 100 if VerifyWithOptions(public, wrongHash[:], sig, &Options{Hash: crypto.SHA512}) == nil { 101 t.Errorf("signature of different message accepted") 102 } 103 104 sig[0] ^= 0xff 105 if VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA512}) == nil { 106 t.Errorf("invalid signature accepted") 107 } 108 sig[0] ^= 0xff 109 sig[SignatureSize-1] ^= 0xff 110 if VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA512}) == nil { 111 t.Errorf("invalid signature accepted") 112 } 113 114 // The RFC provides no test vectors for Ed25519ph with context, so just sign 115 // and verify something. 116 sig, err = private.Sign(nil, hash[:], &Options{Hash: crypto.SHA512, Context: "123"}) 117 if err != nil { 118 t.Fatal(err) 119 } 120 if err := VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA512, Context: "123"}); err != nil { 121 t.Errorf("valid signature rejected: %v", err) 122 } 123 if err := VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA512, Context: "321"}); err == nil { 124 t.Errorf("expected error for wrong context") 125 } 126 if err := VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA256, Context: "123"}); err == nil { 127 t.Errorf("expected error for wrong hash") 128 } 129} 130 131func TestSignVerifyContext(t *testing.T) { 132 // From RFC 8032, Section 7.2 133 key, _ := hex.DecodeString("0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292") 134 expectedSig, _ := hex.DecodeString("55a4cc2f70a54e04288c5f4cd1e45a7bb520b36292911876cada7323198dd87a8b36950b95130022907a7fb7c4e9b2d5f6cca685a587b4b21f4b888e4e7edb0d") 135 message, _ := hex.DecodeString("f726936d19c800494e3fdaff20b276a8") 136 context := "foo" 137 138 private := PrivateKey(key) 139 public := private.Public().(PublicKey) 140 sig, err := private.Sign(nil, message, &Options{Context: context}) 141 if err != nil { 142 t.Fatal(err) 143 } 144 if !bytes.Equal(sig, expectedSig) { 145 t.Error("signature doesn't match test vector") 146 } 147 if err := VerifyWithOptions(public, message, sig, &Options{Context: context}); err != nil { 148 t.Errorf("valid signature rejected: %v", err) 149 } 150 151 if VerifyWithOptions(public, []byte("bar"), sig, &Options{Context: context}) == nil { 152 t.Errorf("signature of different message accepted") 153 } 154 if VerifyWithOptions(public, message, sig, &Options{Context: "bar"}) == nil { 155 t.Errorf("signature with different context accepted") 156 } 157 158 sig[0] ^= 0xff 159 if VerifyWithOptions(public, message, sig, &Options{Context: context}) == nil { 160 t.Errorf("invalid signature accepted") 161 } 162 sig[0] ^= 0xff 163 sig[SignatureSize-1] ^= 0xff 164 if VerifyWithOptions(public, message, sig, &Options{Context: context}) == nil { 165 t.Errorf("invalid signature accepted") 166 } 167} 168 169func TestCryptoSigner(t *testing.T) { 170 var zero zeroReader 171 public, private, _ := GenerateKey(zero) 172 173 signer := crypto.Signer(private) 174 175 publicInterface := signer.Public() 176 public2, ok := publicInterface.(PublicKey) 177 if !ok { 178 t.Fatalf("expected PublicKey from Public() but got %T", publicInterface) 179 } 180 181 if !bytes.Equal(public, public2) { 182 t.Errorf("public keys do not match: original:%x vs Public():%x", public, public2) 183 } 184 185 message := []byte("message") 186 var noHash crypto.Hash 187 signature, err := signer.Sign(zero, message, noHash) 188 if err != nil { 189 t.Fatalf("error from Sign(): %s", err) 190 } 191 192 signature2, err := signer.Sign(zero, message, &Options{Hash: noHash}) 193 if err != nil { 194 t.Fatalf("error from Sign(): %s", err) 195 } 196 if !bytes.Equal(signature, signature2) { 197 t.Errorf("signatures keys do not match") 198 } 199 200 if !Verify(public, message, signature) { 201 t.Errorf("Verify failed on signature from Sign()") 202 } 203} 204 205func TestEqual(t *testing.T) { 206 public, private, _ := GenerateKey(rand.Reader) 207 208 if !public.Equal(public) { 209 t.Errorf("public key is not equal to itself: %q", public) 210 } 211 if !public.Equal(crypto.Signer(private).Public()) { 212 t.Errorf("private.Public() is not Equal to public: %q", public) 213 } 214 if !private.Equal(private) { 215 t.Errorf("private key is not equal to itself: %q", private) 216 } 217 218 otherPub, otherPriv, _ := GenerateKey(rand.Reader) 219 if public.Equal(otherPub) { 220 t.Errorf("different public keys are Equal") 221 } 222 if private.Equal(otherPriv) { 223 t.Errorf("different private keys are Equal") 224 } 225} 226 227func TestGolden(t *testing.T) { 228 // sign.input.gz is a selection of test cases from 229 // https://ed25519.cr.yp.to/python/sign.input 230 testDataZ, err := os.Open("testdata/sign.input.gz") 231 if err != nil { 232 t.Fatal(err) 233 } 234 defer testDataZ.Close() 235 testData, err := gzip.NewReader(testDataZ) 236 if err != nil { 237 t.Fatal(err) 238 } 239 defer testData.Close() 240 241 scanner := bufio.NewScanner(testData) 242 lineNo := 0 243 244 for scanner.Scan() { 245 lineNo++ 246 247 line := scanner.Text() 248 parts := strings.Split(line, ":") 249 if len(parts) != 5 { 250 t.Fatalf("bad number of parts on line %d", lineNo) 251 } 252 253 privBytes, _ := hex.DecodeString(parts[0]) 254 pubKey, _ := hex.DecodeString(parts[1]) 255 msg, _ := hex.DecodeString(parts[2]) 256 sig, _ := hex.DecodeString(parts[3]) 257 // The signatures in the test vectors also include the message 258 // at the end, but we just want R and S. 259 sig = sig[:SignatureSize] 260 261 if l := len(pubKey); l != PublicKeySize { 262 t.Fatalf("bad public key length on line %d: got %d bytes", lineNo, l) 263 } 264 265 var priv [PrivateKeySize]byte 266 copy(priv[:], privBytes) 267 copy(priv[32:], pubKey) 268 269 sig2 := Sign(priv[:], msg) 270 if !bytes.Equal(sig, sig2[:]) { 271 t.Errorf("different signature result on line %d: %x vs %x", lineNo, sig, sig2) 272 } 273 274 if !Verify(pubKey, msg, sig2) { 275 t.Errorf("signature failed to verify on line %d", lineNo) 276 } 277 278 priv2 := NewKeyFromSeed(priv[:32]) 279 if !bytes.Equal(priv[:], priv2) { 280 t.Errorf("recreating key pair gave different private key on line %d: %x vs %x", lineNo, priv[:], priv2) 281 } 282 283 if pubKey2 := priv2.Public().(PublicKey); !bytes.Equal(pubKey, pubKey2) { 284 t.Errorf("recreating key pair gave different public key on line %d: %x vs %x", lineNo, pubKey, pubKey2) 285 } 286 287 if seed := priv2.Seed(); !bytes.Equal(priv[:32], seed) { 288 t.Errorf("recreating key pair gave different seed on line %d: %x vs %x", lineNo, priv[:32], seed) 289 } 290 } 291 292 if err := scanner.Err(); err != nil { 293 t.Fatalf("error reading test data: %s", err) 294 } 295} 296 297func TestMalleability(t *testing.T) { 298 // https://tools.ietf.org/html/rfc8032#section-5.1.7 adds an additional test 299 // that s be in [0, order). This prevents someone from adding a multiple of 300 // order to s and obtaining a second valid signature for the same message. 301 msg := []byte{0x54, 0x65, 0x73, 0x74} 302 sig := []byte{ 303 0x7c, 0x38, 0xe0, 0x26, 0xf2, 0x9e, 0x14, 0xaa, 0xbd, 0x05, 0x9a, 304 0x0f, 0x2d, 0xb8, 0xb0, 0xcd, 0x78, 0x30, 0x40, 0x60, 0x9a, 0x8b, 305 0xe6, 0x84, 0xdb, 0x12, 0xf8, 0x2a, 0x27, 0x77, 0x4a, 0xb0, 0x67, 306 0x65, 0x4b, 0xce, 0x38, 0x32, 0xc2, 0xd7, 0x6f, 0x8f, 0x6f, 0x5d, 307 0xaf, 0xc0, 0x8d, 0x93, 0x39, 0xd4, 0xee, 0xf6, 0x76, 0x57, 0x33, 308 0x36, 0xa5, 0xc5, 0x1e, 0xb6, 0xf9, 0x46, 0xb3, 0x1d, 309 } 310 publicKey := []byte{ 311 0x7d, 0x4d, 0x0e, 0x7f, 0x61, 0x53, 0xa6, 0x9b, 0x62, 0x42, 0xb5, 312 0x22, 0xab, 0xbe, 0xe6, 0x85, 0xfd, 0xa4, 0x42, 0x0f, 0x88, 0x34, 313 0xb1, 0x08, 0xc3, 0xbd, 0xae, 0x36, 0x9e, 0xf5, 0x49, 0xfa, 314 } 315 316 if Verify(publicKey, msg, sig) { 317 t.Fatal("non-canonical signature accepted") 318 } 319} 320 321func TestAllocations(t *testing.T) { 322 if boring.Enabled { 323 t.Skip("skipping allocations test with BoringCrypto") 324 } 325 testenv.SkipIfOptimizationOff(t) 326 327 if allocs := testing.AllocsPerRun(100, func() { 328 seed := make([]byte, SeedSize) 329 message := []byte("Hello, world!") 330 priv := NewKeyFromSeed(seed) 331 pub := priv.Public().(PublicKey) 332 signature := Sign(priv, message) 333 if !Verify(pub, message, signature) { 334 t.Fatal("signature didn't verify") 335 } 336 }); allocs > 0 { 337 t.Errorf("expected zero allocations, got %0.1f", allocs) 338 } 339} 340 341func BenchmarkKeyGeneration(b *testing.B) { 342 var zero zeroReader 343 for i := 0; i < b.N; i++ { 344 if _, _, err := GenerateKey(zero); err != nil { 345 b.Fatal(err) 346 } 347 } 348} 349 350func BenchmarkNewKeyFromSeed(b *testing.B) { 351 seed := make([]byte, SeedSize) 352 for i := 0; i < b.N; i++ { 353 _ = NewKeyFromSeed(seed) 354 } 355} 356 357func BenchmarkSigning(b *testing.B) { 358 var zero zeroReader 359 _, priv, err := GenerateKey(zero) 360 if err != nil { 361 b.Fatal(err) 362 } 363 message := []byte("Hello, world!") 364 b.ResetTimer() 365 for i := 0; i < b.N; i++ { 366 Sign(priv, message) 367 } 368} 369 370func BenchmarkVerification(b *testing.B) { 371 var zero zeroReader 372 pub, priv, err := GenerateKey(zero) 373 if err != nil { 374 b.Fatal(err) 375 } 376 message := []byte("Hello, world!") 377 signature := Sign(priv, message) 378 b.ResetTimer() 379 for i := 0; i < b.N; i++ { 380 Verify(pub, message, signature) 381 } 382} 383