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  }