github.com/decred/dcrlnd@v0.7.6/chanbackup/crypto_test.go (about)

     1  package chanbackup
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"testing"
     7  
     8  	"github.com/decred/dcrd/dcrec/secp256k1/v4"
     9  	"github.com/decred/dcrlnd/keychain"
    10  )
    11  
    12  var (
    13  	testWalletPrivKey = []byte{
    14  		0x2b, 0xd8, 0x06, 0xc9, 0x7f, 0x0e, 0x00, 0xaf,
    15  		0x1a, 0x1f, 0xc3, 0x32, 0x8f, 0xa7, 0x63, 0xa9,
    16  		0x26, 0x97, 0x23, 0xc8, 0xdb, 0x8f, 0xac, 0x4f,
    17  		0x93, 0xaf, 0x71, 0xdb, 0x18, 0x6d, 0x6e, 0x90,
    18  	}
    19  )
    20  
    21  type mockKeyRing struct {
    22  	fail bool
    23  }
    24  
    25  func (m *mockKeyRing) DeriveNextKey(keyFam keychain.KeyFamily) (keychain.KeyDescriptor, error) {
    26  	return keychain.KeyDescriptor{}, nil
    27  }
    28  func (m *mockKeyRing) DeriveKey(keyLoc keychain.KeyLocator) (keychain.KeyDescriptor, error) {
    29  	if m.fail {
    30  		return keychain.KeyDescriptor{}, fmt.Errorf("fail")
    31  	}
    32  
    33  	pub := secp256k1.PrivKeyFromBytes(testWalletPrivKey).PubKey()
    34  	return keychain.KeyDescriptor{
    35  		PubKey: pub,
    36  	}, nil
    37  }
    38  
    39  // TestEncryptDecryptPayload tests that given a static key, we're able to
    40  // properly decrypt and encrypted payload. We also test that we'll reject a
    41  // ciphertext that has been modified.
    42  func TestEncryptDecryptPayload(t *testing.T) {
    43  	t.Parallel()
    44  
    45  	payloadCases := []struct {
    46  		// plaintext is the string that we'll be encrypting.
    47  		plaintext []byte
    48  
    49  		// mutator allows a test case to modify the ciphertext before
    50  		// we attempt to decrypt it.
    51  		mutator func(*[]byte)
    52  
    53  		// valid indicates if this test should pass or fail.
    54  		valid bool
    55  	}{
    56  		// Proper payload, should decrypt.
    57  		{
    58  			plaintext: []byte("payload test plain text"),
    59  			mutator:   nil,
    60  			valid:     true,
    61  		},
    62  
    63  		// Mutator modifies cipher text, shouldn't decrypt.
    64  		{
    65  			plaintext: []byte("payload test plain text"),
    66  			mutator: func(p *[]byte) {
    67  				// Flip a byte in the payload to render it invalid.
    68  				(*p)[0] ^= 1
    69  			},
    70  			valid: false,
    71  		},
    72  
    73  		// Cipher text is too small, shouldn't decrypt.
    74  		{
    75  			plaintext: []byte("payload test plain text"),
    76  			mutator: func(p *[]byte) {
    77  				// Modify the cipher text to be zero length.
    78  				*p = []byte{}
    79  			},
    80  			valid: false,
    81  		},
    82  	}
    83  
    84  	keyRing := &mockKeyRing{}
    85  
    86  	for i, payloadCase := range payloadCases {
    87  		var cipherBuffer bytes.Buffer
    88  
    89  		// First, we'll encrypt the passed payload with our scheme.
    90  		payloadReader := bytes.NewBuffer(payloadCase.plaintext)
    91  		err := encryptPayloadToWriter(
    92  			*payloadReader, &cipherBuffer, keyRing,
    93  		)
    94  		if err != nil {
    95  			t.Fatalf("unable encrypt paylaod: %v", err)
    96  		}
    97  
    98  		// If we have a mutator, then we'll wrong the mutator over the
    99  		// cipher text, then reset the main buffer and re-write the new
   100  		// cipher text.
   101  		if payloadCase.mutator != nil {
   102  			cipherText := cipherBuffer.Bytes()
   103  
   104  			payloadCase.mutator(&cipherText)
   105  
   106  			cipherBuffer.Reset()
   107  			cipherBuffer.Write(cipherText)
   108  		}
   109  
   110  		plaintext, err := decryptPayloadFromReader(&cipherBuffer, keyRing)
   111  
   112  		switch {
   113  		// If this was meant to be a valid decryption, but we failed,
   114  		// then we'll return an error.
   115  		case err != nil && payloadCase.valid:
   116  			t.Fatalf("unable to decrypt valid payload case %v", i)
   117  
   118  		// If this was meant to be an invalid decryption, and we didn't
   119  		// fail, then we'll return an error.
   120  		case err == nil && !payloadCase.valid:
   121  			t.Fatalf("payload was invalid yet was able to decrypt")
   122  		}
   123  
   124  		// Only if this case was mean to be valid will we ensure the
   125  		// resulting decrypted plaintext matches the original input.
   126  		if payloadCase.valid &&
   127  			!bytes.Equal(plaintext, payloadCase.plaintext) {
   128  			t.Fatalf("#%v: expected %v, got %v: ", i,
   129  				payloadCase.plaintext, plaintext)
   130  		}
   131  	}
   132  }
   133  
   134  // TestInvalidKeyEncryption tests that encryption fails if we're unable to
   135  // obtain a valid key.
   136  func TestInvalidKeyEncryption(t *testing.T) {
   137  	t.Parallel()
   138  
   139  	var b bytes.Buffer
   140  	err := encryptPayloadToWriter(b, &b, &mockKeyRing{true})
   141  	if err == nil {
   142  		t.Fatalf("expected error due to fail key gen")
   143  	}
   144  }
   145  
   146  // TestInvalidKeyDecrytion tests that decryption fails if we're unable to
   147  // obtain a valid key.
   148  func TestInvalidKeyDecrytion(t *testing.T) {
   149  	t.Parallel()
   150  
   151  	var b bytes.Buffer
   152  	_, err := decryptPayloadFromReader(&b, &mockKeyRing{true})
   153  	if err == nil {
   154  		t.Fatalf("expected error due to fail key gen")
   155  	}
   156  }