github.com/avahowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/crypto/signatures_test.go (about)

     1  package crypto
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/rand"
     6  	"errors"
     7  	"testing"
     8  
     9  	"github.com/NebulousLabs/Sia/encoding"
    10  	"github.com/NebulousLabs/ed25519"
    11  )
    12  
    13  // mockKeyDeriver is a mock implementation of keyDeriver that saves its provided
    14  // entropy and allows the client to specify the returned SecretKey and
    15  // PublicKey.
    16  type mockKeyDeriver struct {
    17  	called  bool
    18  	entropy [EntropySize]byte
    19  	sk      ed25519.SecretKey
    20  	pk      ed25519.PublicKey
    21  }
    22  
    23  // deriveKeyPair is a mocked key deriver operating on the mockKeyDeriver
    24  // struct.
    25  func (kd *mockKeyDeriver) deriveKeyPair(entropy [EntropySize]byte) (ed25519.SecretKey, ed25519.PublicKey) {
    26  	kd.called = true
    27  	kd.entropy = entropy
    28  	return kd.sk, kd.pk
    29  }
    30  
    31  // TestUnitGenerateRandomKeyPair checks that the Generate method is properly
    32  // calling its dependencies and returning the expected key pair.
    33  func TestUnitGenerateRandomKeyPair(t *testing.T) {
    34  	var mockEntropy [EntropySize]byte
    35  	mockEntropy[0] = 5
    36  	mockEntropy[EntropySize-1] = 5
    37  	entropyReader := bytes.NewReader(mockEntropy[:])
    38  
    39  	sk := ed25519.SecretKey(&[SecretKeySize]byte{})
    40  	sk[0] = 7
    41  	sk[32] = 8
    42  	pk := ed25519.PublicKey(&[PublicKeySize]byte{})
    43  	pk[0] = sk[32]
    44  	kd := mockKeyDeriver{sk: sk, pk: pk}
    45  
    46  	// Create a SignatureKeyGenerator using mocks.
    47  	g := sigKeyGen{entropyReader, &kd}
    48  
    49  	// Create key pair.
    50  	skActual, pkActual, err := g.generate()
    51  
    52  	// Verify that we got back the expected results.
    53  	if err != nil {
    54  		t.Error(err)
    55  	}
    56  	if *sk != skActual {
    57  		t.Errorf("Generated secret key does not match expected! expected = %v, actual = %v", sk, skActual)
    58  	}
    59  	if *pk != pkActual {
    60  		t.Errorf("Generated public key does not match expected! expected = %v, actual = %v", pk, pkActual)
    61  	}
    62  
    63  	// Verify the dependencies were called correctly
    64  	if !kd.called {
    65  		t.Error("keyDeriver was never called.")
    66  	}
    67  	if mockEntropy != kd.entropy {
    68  		t.Errorf("keyDeriver was called with the wrong entropy. expected = %v, actual = %v", mockEntropy, kd.entropy)
    69  	}
    70  }
    71  
    72  // failingReader is a mock implementation of io.Reader that fails with a client-
    73  // defined error.
    74  type failingReader struct {
    75  	err error
    76  }
    77  
    78  // Read satisfies the entropySource of the stdKeyGen, but always fails,
    79  // resulting in errors that must be handled by the generate function.
    80  func (fr failingReader) Read([]byte) (int, error) {
    81  	return 0, fr.err
    82  }
    83  
    84  // TestUnitGenerateRandomKeyBadRand checks that the Generate method fails if
    85  // the call to entropy source fails
    86  func TestUnitGenerateRandomKeyBadRand(t *testing.T) {
    87  	fr := failingReader{err: errors.New("mock error from entropy reader")}
    88  	g := sigKeyGen{entropySource: &fr}
    89  	if _, _, err := g.generate(); err == nil {
    90  		t.Error("Generate should fail when entropy source fails.")
    91  	}
    92  }
    93  
    94  // TestUnitGenerateDeterministicKeyPari checks that the GenerateDeterministic
    95  // method is properly calling its dependencies and returning the expected key
    96  // pair.
    97  func TestUnitGenerateDeterministicKeyPair(t *testing.T) {
    98  	// Create entropy bytes, setting a few bytes explicitly instead of using a
    99  	// buffer of random bytes.
   100  	var mockEntropy [EntropySize]byte
   101  	mockEntropy[0] = 4
   102  	mockEntropy[EntropySize-1] = 5
   103  
   104  	sk := ed25519.SecretKey(&[SecretKeySize]byte{})
   105  	sk[0] = 7
   106  	sk[32] = 8
   107  	pk := ed25519.PublicKey(&[PublicKeySize]byte{})
   108  	pk[0] = sk[32]
   109  	kd := mockKeyDeriver{sk: sk, pk: pk}
   110  	g := sigKeyGen{keyDeriver: &kd}
   111  
   112  	// Create key pair.
   113  	skActual, pkActual := g.generateDeterministic(mockEntropy)
   114  
   115  	// Verify that we got back the right results.
   116  	if *sk != skActual {
   117  		t.Errorf("Generated secret key does not match expected! expected = %v, actual = %v", sk, skActual)
   118  	}
   119  	if *pk != pkActual {
   120  		t.Errorf("Generated public key does not match expected! expected = %v, actual = %v", pk, pkActual)
   121  	}
   122  
   123  	// Verify the dependencies were called correctly.
   124  	if !kd.called {
   125  		t.Error("keyDeriver was never called.")
   126  	}
   127  	if mockEntropy != kd.entropy {
   128  		t.Errorf("keyDeriver was called with the wrong entropy. expected = %v, actual = %v", mockEntropy, kd.entropy)
   129  	}
   130  }
   131  
   132  // TestUnitSignatureEncoding creates and encodes a public key, and verifies
   133  // that it decodes correctly, does the same with a signature.
   134  func TestUnitSignatureEncoding(t *testing.T) {
   135  	// Create a dummy key pair.
   136  	var sk SecretKey
   137  	sk[0] = 4
   138  	sk[32] = 5
   139  	pk := sk.PublicKey()
   140  
   141  	// Marshal and unmarshal the public key.
   142  	marshalledPK := encoding.Marshal(pk)
   143  	var unmarshalledPK PublicKey
   144  	err := encoding.Unmarshal(marshalledPK, &unmarshalledPK)
   145  	if err != nil {
   146  		t.Fatal(err)
   147  	}
   148  
   149  	// Test the public keys for equality.
   150  	if pk != unmarshalledPK {
   151  		t.Error("pubkey not the same after marshalling and unmarshalling")
   152  	}
   153  
   154  	// Create a signature using the secret key.
   155  	var signedData Hash
   156  	rand.Read(signedData[:])
   157  	sig, err := SignHash(signedData, sk)
   158  	if err != nil {
   159  		t.Fatal(err)
   160  	}
   161  
   162  	// Marshal and unmarshal the signature.
   163  	marshalledSig := encoding.Marshal(sig)
   164  	var unmarshalledSig Signature
   165  	err = encoding.Unmarshal(marshalledSig, &unmarshalledSig)
   166  	if err != nil {
   167  		t.Fatal(err)
   168  	}
   169  
   170  	// Test signatures for equality.
   171  	if sig != unmarshalledSig {
   172  		t.Error("signature not same after marshalling and unmarshalling")
   173  	}
   174  
   175  }
   176  
   177  // TestUnitSigning creates a bunch of keypairs and signs random data with each of
   178  // them.
   179  func TestUnitSigning(t *testing.T) {
   180  	if testing.Short() {
   181  		t.SkipNow()
   182  	}
   183  
   184  	// Try a bunch of signatures because at one point there was a library that
   185  	// worked around 98% of the time. Tests would usually pass, but 200
   186  	// iterations would normally cause a failure.
   187  	iterations := 200
   188  	for i := 0; i < iterations; i++ {
   189  		// Create dummy key pair.
   190  		sk, pk, err := GenerateKeyPair()
   191  		if err != nil {
   192  			t.Fatal(err)
   193  		}
   194  
   195  		// Generate and sign the data.
   196  		var randData Hash
   197  		rand.Read(randData[:])
   198  		sig, err := SignHash(randData, sk)
   199  		if err != nil {
   200  			t.Fatal(err)
   201  		}
   202  
   203  		// Verify the signature.
   204  		err = VerifyHash(randData, pk, sig)
   205  		if err != nil {
   206  			t.Fatal(err)
   207  		}
   208  
   209  		// Attempt to verify after the data has been altered.
   210  		randData[0] += 1
   211  		err = VerifyHash(randData, pk, sig)
   212  		if err != ErrInvalidSignature {
   213  			t.Fatal(err)
   214  		}
   215  
   216  		// Restore the data and make sure the signature is valid again.
   217  		randData[0] -= 1
   218  		err = VerifyHash(randData, pk, sig)
   219  		if err != nil {
   220  			t.Fatal(err)
   221  		}
   222  
   223  		// Attempt to verify after the signature has been altered.
   224  		sig[0] += 1
   225  		err = VerifyHash(randData, pk, sig)
   226  		if err != ErrInvalidSignature {
   227  			t.Fatal(err)
   228  		}
   229  	}
   230  }
   231  
   232  // TestIntegrationSigKeyGenerate is an integration test checking that
   233  // GenerateKeyPair and GenerateKeyPairDeterminisitc accurately create keys.
   234  func TestIntegrationSigKeyGeneration(t *testing.T) {
   235  	if testing.Short() {
   236  		t.SkipNow()
   237  	}
   238  	message := HashBytes([]byte{'m', 's', 'g'})
   239  
   240  	// Create a random key and use it.
   241  	randSecKey, randPubKey, err := GenerateKeyPair()
   242  	if err != nil {
   243  		t.Fatal(err)
   244  	}
   245  	sig, err := SignHash(message, randSecKey)
   246  	if err != nil {
   247  		t.Fatal(err)
   248  	}
   249  	err = VerifyHash(message, randPubKey, sig)
   250  	if err != nil {
   251  		t.Error(err)
   252  	}
   253  	// Corrupt the signature
   254  	sig[0]++
   255  	err = VerifyHash(message, randPubKey, sig)
   256  	if err == nil {
   257  		t.Error("corruption failed")
   258  	}
   259  
   260  	// Create a deterministic key and use it.
   261  	var detEntropy [EntropySize]byte
   262  	detEntropy[0] = 35
   263  	detSecKey, detPubKey := GenerateKeyPairDeterministic(detEntropy)
   264  	sig, err = SignHash(message, detSecKey)
   265  	if err != nil {
   266  		t.Fatal(err)
   267  	}
   268  	err = VerifyHash(message, detPubKey, sig)
   269  	if err != nil {
   270  		t.Error(err)
   271  	}
   272  	// Corrupt the signature
   273  	sig[0]++
   274  	err = VerifyHash(message, detPubKey, sig)
   275  	if err == nil {
   276  		t.Error("corruption failed")
   277  	}
   278  }
   279  
   280  // TestReadWriteSignedObject tests the ReadSignObject and WriteSignedObject
   281  // functions, which are inverses of each other.
   282  func TestReadWriteSignedObject(t *testing.T) {
   283  	sk, pk, err := GenerateKeyPair()
   284  	if err != nil {
   285  		t.Fatal(err)
   286  	}
   287  
   288  	// Write signed object into buffer.
   289  	b := new(bytes.Buffer)
   290  	err = WriteSignedObject(b, "foo", sk)
   291  	if err != nil {
   292  		t.Fatal(err)
   293  	}
   294  	// Keep a copy of b's bytes.
   295  	buf := b.Bytes()
   296  
   297  	// Read and verify object.
   298  	var read string
   299  	err = ReadSignedObject(b, &read, 11, pk)
   300  	if err != nil {
   301  		t.Fatal(err)
   302  	}
   303  	if read != "foo" {
   304  		t.Fatal("encode/decode mismatch: expected 'foo', got", []byte(read))
   305  	}
   306  
   307  	// Check that maxlen is being respected.
   308  	b = bytes.NewBuffer(buf) // reset b
   309  	err = ReadSignedObject(b, &read, 10, pk)
   310  	if err == nil || err.Error() != "length 11 exceeds maxLen of 10" {
   311  		t.Fatal("expected length error, got", err)
   312  	}
   313  
   314  	// Disrupt the decoding to get coverage on the failure branch.
   315  	err = ReadSignedObject(b, &read, 11, pk)
   316  	if err == nil || err.Error() != "could not decode type crypto.Signature: unexpected EOF" {
   317  		t.Fatal(err)
   318  	}
   319  
   320  	// Try with an invalid signature.
   321  	buf[0]++                 // alter the first byte of the signature, invalidating it.
   322  	b = bytes.NewBuffer(buf) // reset b
   323  	err = ReadSignedObject(b, &read, 11, pk)
   324  	if err != ErrInvalidSignature {
   325  		t.Fatal(err)
   326  	}
   327  }
   328  
   329  // TestUnitPublicKey tests the PublicKey method
   330  func TestUnitPublicKey(t *testing.T) {
   331  	for i := 0; i < 1000; i++ {
   332  		sk, pk, err := GenerateKeyPair()
   333  		if err != nil {
   334  			t.Fatal(err)
   335  		}
   336  		if sk.PublicKey() != pk {
   337  			t.Error("PublicKey does not match actual public key:", pk, sk.PublicKey())
   338  		}
   339  	}
   340  }