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 }