github.com/avahowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/crypto/encrypt_test.go (about) 1 package crypto 2 3 import ( 4 "bytes" 5 "compress/gzip" 6 "crypto/rand" 7 "testing" 8 ) 9 10 // TestTwofishEncryption checks that encryption and decryption works correctly. 11 func TestTwofishEncryption(t *testing.T) { 12 // Get a key for encryption. 13 key, err := GenerateTwofishKey() 14 if err != nil { 15 t.Fatal(err) 16 } 17 18 // Encrypt and decrypt a zero plaintext, and compare the decrypted to the 19 // original. 20 plaintext := make([]byte, 600) 21 ciphertext, err := key.EncryptBytes(plaintext) 22 if err != nil { 23 t.Fatal(err) 24 } 25 decryptedPlaintext, err := key.DecryptBytes(ciphertext) 26 if err != nil { 27 t.Fatal(err) 28 } 29 if !bytes.Equal(plaintext, decryptedPlaintext) { 30 t.Fatal("Encrypted and decrypted zero plaintext do not match") 31 } 32 33 // Try again with a nonzero plaintext. 34 plaintext = make([]byte, 600) 35 _, err = rand.Read(plaintext) 36 if err != nil { 37 t.Fatal(err) 38 } 39 ciphertext, err = key.EncryptBytes(plaintext) 40 if err != nil { 41 t.Fatal(err) 42 } 43 decryptedPlaintext, err = key.DecryptBytes(ciphertext) 44 if err != nil { 45 t.Fatal(err) 46 } 47 if !bytes.Equal(plaintext, decryptedPlaintext) { 48 t.Fatal("Encrypted and decrypted zero plaintext do not match") 49 } 50 51 // Try to decrypt using a different key 52 key2, err := GenerateTwofishKey() 53 if err != nil { 54 t.Fatal(err) 55 } 56 _, err = key2.DecryptBytes(ciphertext) 57 if err == nil { 58 t.Fatal("Expecting failed authentication err", err) 59 } 60 61 // Try to decrypt using bad ciphertexts. 62 ciphertext[0]++ 63 _, err = key.DecryptBytes(ciphertext) 64 if err == nil { 65 t.Fatal("Expecting failed authentication err", err) 66 } 67 _, err = key.DecryptBytes(ciphertext[:10]) 68 if err != ErrInsufficientLen { 69 t.Error("Expecting ErrInsufficientLen:", err) 70 } 71 72 // Try to trigger a panic or error with nil values. 73 _, err = key.EncryptBytes(nil) 74 if err != nil { 75 t.Error(err) 76 } 77 _, err = key.DecryptBytes(nil) 78 if err != ErrInsufficientLen { 79 t.Error("Expecting ErrInsufficientLen:", err) 80 } 81 } 82 83 // TestReaderWriter probes the NewReader and NewWriter methods of the key type. 84 func TestReaderWriter(t *testing.T) { 85 // Get a key for encryption. 86 key, err := GenerateTwofishKey() 87 if err != nil { 88 t.Fatal(err) 89 } 90 91 // Generate plaintext. 92 const plaintextSize = 600 93 plaintext := make([]byte, plaintextSize) 94 _, err = rand.Read(plaintext) 95 if err != nil { 96 t.Fatal(err) 97 } 98 99 // Create writer and encrypt plaintext. 100 buf := new(bytes.Buffer) 101 key.NewWriter(buf).Write(plaintext) 102 103 // There should be no overhead present. 104 if buf.Len() != plaintextSize { 105 t.Fatalf("encryption introduced %v bytes of overhead", buf.Len()-plaintextSize) 106 } 107 108 // Create reader and decrypt ciphertext. 109 var decrypted = make([]byte, plaintextSize) 110 key.NewReader(buf).Read(decrypted) 111 112 if !bytes.Equal(plaintext, decrypted) { 113 t.Error("couldn't decrypt encrypted stream") 114 } 115 } 116 117 // TestTwofishEntropy encrypts and then decrypts a zero plaintext, checking 118 // that the ciphertext is high entropy. 119 func TestTwofishEntropy(t *testing.T) { 120 if testing.Short() { 121 t.SkipNow() 122 } 123 124 // Encrypt a larger zero plaintext and make sure that the outcome is high 125 // entropy. Entropy is measured by compressing the ciphertext with gzip. 126 // 10 * 1000 bytes was chosen to minimize the impact of gzip overhead. 127 const cipherSize = 10e3 128 key, err := GenerateTwofishKey() 129 if err != nil { 130 t.Fatal(err) 131 } 132 plaintext := make([]byte, cipherSize) 133 ciphertext, err := key.EncryptBytes(plaintext) 134 if err != nil { 135 t.Fatal(err) 136 } 137 138 // Gzip the ciphertext 139 var b bytes.Buffer 140 zip := gzip.NewWriter(&b) 141 _, err = zip.Write(ciphertext) 142 if err != nil { 143 t.Fatal(err) 144 } 145 zip.Close() 146 if b.Len() < cipherSize { 147 t.Error("supposedly high entropy ciphertext has been compressed!") 148 } 149 } 150 151 // TestUnitCiphertextUnmarshalInvalidJSON tests that Ciphertext.UnmarshalJSON 152 // correctly fails on invalid JSON marshalled Ciphertext. 153 func TestUnitCiphertextUnmarshalInvalidJSON(t *testing.T) { 154 // Test unmarshalling invalid JSON. 155 invalidJSONBytes := [][]byte{ 156 nil, 157 {}, 158 []byte("\""), 159 } 160 for _, jsonBytes := range invalidJSONBytes { 161 var ct Ciphertext 162 err := ct.UnmarshalJSON(jsonBytes) 163 if err == nil { 164 t.Errorf("expected unmarshall to fail on the invalid JSON: %q\n", jsonBytes) 165 } 166 } 167 } 168 169 // TestCiphertextMarshalling tests that marshalling Ciphertexts to JSON results 170 // in the expected JSON. Also tests that marshalling that JSON back to 171 // Ciphertext results in the original Ciphertext. 172 func TestCiphertextMarshalling(t *testing.T) { 173 // Ciphertexts and corresponding JSONs to test marshalling and 174 // unmarshalling. 175 ciphertextMarshallingTests := []struct { 176 ct Ciphertext 177 jsonBytes []byte 178 }{ 179 {ct: Ciphertext(nil), jsonBytes: []byte("null")}, 180 {ct: Ciphertext(""), jsonBytes: []byte(`""`)}, 181 {ct: Ciphertext("a ciphertext"), jsonBytes: []byte(`"YSBjaXBoZXJ0ZXh0"`) /* base64 encoding of the Ciphertext */}, 182 } 183 for _, test := range ciphertextMarshallingTests { 184 expectedCt := test.ct 185 expectedJSONBytes := test.jsonBytes 186 187 // Create a copy of expectedCt so Unmarshalling does not modify it, as 188 // we need it later for comparison. 189 var ct Ciphertext 190 if expectedCt == nil { 191 ct = nil 192 } else { 193 ct = make(Ciphertext, len(expectedCt)) 194 copy(ct, expectedCt) 195 } 196 197 // Marshal Ciphertext to JSON. 198 jsonBytes, err := ct.MarshalJSON() 199 if err != nil { 200 t.Fatal(err) 201 } 202 if !bytes.Equal(jsonBytes, expectedJSONBytes) { 203 // Use %#v instead of %v because %v prints Ciphertexts constructed 204 // with nil and []byte{} identically. 205 t.Fatalf("Ciphertext %#v marshalled incorrectly: expected %q, got %q\n", ct, expectedJSONBytes, jsonBytes) 206 } 207 208 // Unmarshal back to Ciphertext. 209 err = ct.UnmarshalJSON(jsonBytes) 210 if err != nil { 211 t.Fatal(err) 212 } 213 // Compare resulting Ciphertext with expected Ciphertext. 214 if expectedCt == nil && ct != nil || expectedCt != nil && ct == nil || !bytes.Equal(expectedCt, ct) { 215 // Use %#v instead of %v because %v prints Ciphertexts constructed 216 // with nil and []byte{} identically. 217 t.Errorf("Ciphertext %#v unmarshalled incorrectly: got %#v\n", expectedCt, ct) 218 } 219 } 220 } 221 222 // TestTwofishNewCipherAssumption tests that the length of a TwofishKey is 16, 223 // 24, or 32 as these are the only cases where twofish.NewCipher(key[:]) 224 // doesn't return an error. 225 func TestTwofishNewCipherAssumption(t *testing.T) { 226 // Generate key. 227 key, err := GenerateTwofishKey() 228 if err != nil { 229 t.Fatal(err) 230 } 231 // Test key length. 232 keyLen := len(key) 233 if keyLen != 16 && keyLen != 24 && keyLen != 32 { 234 t.Errorf("TwofishKey must have length 16, 24, or 32, but generated key has length %d\n", keyLen) 235 } 236 } 237 238 // TestCipherNewGCMAssumption tests that the BlockSize of a cipher block is 16, 239 // as this is the only case where cipher.NewGCM(block) doesn't return an error. 240 func TestCipherNewGCMAssumption(t *testing.T) { 241 // Generate a key and then cipher block from key. 242 key, err := GenerateTwofishKey() 243 if err != nil { 244 t.Fatal(err) 245 } 246 // Test block size. 247 block := key.NewCipher() 248 if block.BlockSize() != 16 { 249 t.Errorf("cipher must have BlockSize 16, but generated cipher has BlockSize %d\n", block.BlockSize()) 250 } 251 }