decred.org/dcrdex@v1.0.5/dex/encrypt/encrypt_test.go (about)

     1  // This code is available on the terms of the project LICENSE.md file,
     2  // also available online at https://blueoakcouncil.org/license/1.0.0.
     3  
     4  package encrypt
     5  
     6  import (
     7  	"bytes"
     8  	"math/rand"
     9  	"testing"
    10  
    11  	"decred.org/dcrdex/dex/encode"
    12  )
    13  
    14  var (
    15  	copyB = encode.CopySlice
    16  	randB = encode.RandomBytes
    17  )
    18  
    19  func TestDecrypt(t *testing.T) {
    20  	pw := []byte("4kliaOCha2")
    21  	crypter := NewCrypter(pw)
    22  	thing := randB(50)
    23  	encThing, err := crypter.Encrypt(thing)
    24  	if err != nil {
    25  		t.Fatalf("Encrypt error: %v", err)
    26  	}
    27  
    28  	reCheck := func() {
    29  		reThing, err := crypter.Decrypt(encThing)
    30  		if err != nil {
    31  			t.Fatalf("Decrypt error: %v", err)
    32  		}
    33  		if !bytes.Equal(thing, reThing) {
    34  			t.Fatalf("%x != %x", thing, reThing)
    35  		}
    36  	}
    37  	reCheck()
    38  
    39  	// Change the version.
    40  	var badThing encode.BuildyBytes = copyB(encThing)
    41  	badThing[0] = 1
    42  	_, err = crypter.Decrypt(badThing)
    43  	if err == nil {
    44  		t.Fatalf("no error for wrong version")
    45  	}
    46  	reCheck()
    47  
    48  	// Drop the second push.
    49  	ver, pushes, _ := encode.DecodeBlob(encThing)
    50  	badThing = encode.BuildyBytes{ver}.AddData(pushes[0])
    51  	_, err = crypter.Decrypt(badThing)
    52  	if err == nil {
    53  		t.Fatalf("no error for trunacted pushes")
    54  	}
    55  	reCheck()
    56  
    57  	// Wrong size nonce.
    58  	badThing = encode.BuildyBytes{ver}.AddData(append(copyB(pushes[0]), 5)).AddData(pushes[1])
    59  	_, err = crypter.Decrypt(badThing)
    60  	if err == nil {
    61  		t.Fatalf("no error for extended nonce")
    62  	}
    63  	reCheck()
    64  
    65  	// Corrupted blob
    66  	badThing = append(copyB(encThing), 123)
    67  	_, err = crypter.Decrypt(badThing)
    68  	if err == nil {
    69  		t.Fatalf("no error for corrupted blob")
    70  	}
    71  	reCheck()
    72  
    73  }
    74  
    75  func FuzzDecrypt(f *testing.F) {
    76  	seeds := []struct {
    77  		b []byte
    78  		n int
    79  	}{{
    80  		n: 200,
    81  		b: []byte("4kliaOCha2longerbyte"),
    82  	}, {
    83  		n: 20,
    84  		b: []byte("short123456"),
    85  	}, {
    86  		n: 50,
    87  		b: []byte("23Fgfge34"),
    88  	}, {
    89  		n: 1000000000,
    90  		b: []byte("asdf$#@*(gth#4"),
    91  	}}
    92  
    93  	for _, seed := range seeds {
    94  		f.Add(seed.n, seed.b)
    95  	}
    96  
    97  	f.Fuzz(func(t *testing.T, n int, b []byte) {
    98  		if n < 1 || n > encode.MaxDataLen || len(b) > encode.MaxDataLen {
    99  			t.Skip()
   100  		}
   101  		crypter := NewCrypter(b)
   102  		thing := randB(n)
   103  		encThing, err := crypter.Encrypt(thing)
   104  		if err != nil {
   105  			t.Fatalf("Encrypt error: %v", err)
   106  		}
   107  		reThing, err := crypter.Decrypt(encThing)
   108  		if err != nil {
   109  			t.Fatalf("Decrypt error: %v", err)
   110  		}
   111  		if !bytes.Equal(thing, reThing) {
   112  			t.Fatalf("%x != %x", thing, reThing)
   113  		}
   114  	})
   115  }
   116  
   117  func TestSerialize(t *testing.T) {
   118  	pw := []byte("20O6KcujCU")
   119  	crypter := NewCrypter(pw)
   120  	thing := randB(50)
   121  	encThing, err := crypter.Encrypt(thing)
   122  	if err != nil {
   123  		t.Fatalf("Encrypt error: %v", err)
   124  	}
   125  	serializedCrypter := crypter.Serialize()
   126  	reCheck := func(tag string) {
   127  		reCrypter, err := Deserialize(pw, serializedCrypter)
   128  		if err != nil {
   129  			t.Fatalf("%s: reCheck deserialization error: %v", tag, err)
   130  		}
   131  		reThing, err := reCrypter.Decrypt(encThing)
   132  		if err != nil {
   133  			t.Fatalf("%s: reCrypter failed to decrypt thing: %v", tag, err)
   134  		}
   135  		if !bytes.Equal(reThing, thing) {
   136  			t.Fatalf("%s: reCrypter's decoded thing is messed up: %x != %x", tag, reThing, thing)
   137  		}
   138  	}
   139  	reCheck("first")
   140  
   141  	// Can't deserialize with wrong password.
   142  	_, err = Deserialize([]byte("wrong password"), serializedCrypter)
   143  	if err == nil {
   144  		t.Fatalf("no Deserialize error for wrong password")
   145  	}
   146  	reCheck("after wrong password")
   147  
   148  	// Adding a random bytes should fail at DecodeBlob
   149  	badCrypter := append(copyB(serializedCrypter), 5)
   150  	_, err = Deserialize(pw, badCrypter)
   151  	if err == nil {
   152  		t.Fatalf("no Deserialize error for corrupted blob")
   153  	}
   154  	reCheck("after corrupted blob")
   155  
   156  	// Version 1 not known.
   157  	badCrypter = copyB(serializedCrypter)
   158  	badCrypter[0] = 1
   159  	_, err = Deserialize(pw, badCrypter)
   160  	if err == nil {
   161  		t.Fatalf("no Deserialize error for blob from the future")
   162  	}
   163  	reCheck("after wrong password")
   164  
   165  	// Trim the salt, which is push 0 and normally 16 bytes.
   166  	badCrypter = trimPush(copyB(serializedCrypter), 0, 15)
   167  	_, err = Deserialize(pw, badCrypter)
   168  	if err == nil {
   169  		t.Fatalf("no Deserialize error trimmed salt")
   170  	}
   171  	reCheck("after trimmed salt")
   172  
   173  	// Trim the threads parameter, which is push 3 and normally 1 byte.
   174  	badCrypter = trimPush(copyB(serializedCrypter), 3, 0)
   175  	_, err = Deserialize(pw, badCrypter)
   176  	if err == nil {
   177  		t.Fatalf("no Deserialize error zero-length threads")
   178  	}
   179  	reCheck("after zero-length threads")
   180  
   181  	// Trim the tag parameter, which is push 4 and normally 16 bytes.
   182  	badCrypter = trimPush(copyB(serializedCrypter), 4, 15)
   183  	_, err = Deserialize(pw, badCrypter)
   184  	if err == nil {
   185  		t.Fatalf("no Deserialize error trimmed tag")
   186  	}
   187  	reCheck("after trimmed tag")
   188  }
   189  
   190  func TestRandomness(t *testing.T) {
   191  	pw := randB(15)
   192  	crypter := NewCrypter(pw)
   193  	numToDo := 10_000
   194  	if testing.Short() {
   195  		numToDo /= 10
   196  	}
   197  	for i := 0; i < numToDo; i++ {
   198  		thing := randB(rand.Intn(100))
   199  		encThing, err := crypter.Encrypt(thing)
   200  		if err != nil {
   201  			t.Fatalf("error encrypting %x with password %x", thing, pw)
   202  		}
   203  		reThing, err := crypter.Decrypt(encThing)
   204  		if err != nil {
   205  			t.Fatalf("error decrypting %x, which is encrypted %x with password %x", encThing, thing, pw)
   206  		}
   207  		if !bytes.Equal(thing, reThing) {
   208  			t.Fatalf("decrypted %x is different that encrypted %x with password %x", reThing, thing, pw)
   209  		}
   210  	}
   211  }
   212  
   213  func trimPush(b []byte, idx, newLen int) []byte {
   214  	ver, pushes, _ := encode.DecodeBlob(b)
   215  	newB := encode.BuildyBytes{ver}
   216  	for i := range pushes {
   217  		if i == idx {
   218  			newB = newB.AddData(pushes[i][:newLen])
   219  		} else {
   220  			newB = newB.AddData(pushes[i])
   221  		}
   222  	}
   223  	return newB
   224  }