...

Source file src/github.com/ProtonMail/go-crypto/eax/eax_test.go

Documentation: github.com/ProtonMail/go-crypto/eax

     1  // Copyright 2019 ProtonTech AG.
     2  //
     3  // This file only tests EAX mode when instantiated with AES-128.
     4  
     5  package eax
     6  
     7  import (
     8  	"bytes"
     9  	"crypto/aes"
    10  	"crypto/cipher"
    11  	"crypto/rand"
    12  	"encoding/hex"
    13  	mathrand "math/rand"
    14  	"testing"
    15  )
    16  
    17  const (
    18  	blockLength = 16
    19  	maxLength   = 1 << 12
    20  )
    21  
    22  func TestEAXImplementsAEADInterface(t *testing.T) {
    23  	var eaxInstance eax
    24  	var aux interface{} = &eaxInstance
    25  	_, ok := aux.(cipher.AEAD)
    26  	if !ok {
    27  		t.Errorf("Error: EAX does not implement AEAD interface")
    28  	}
    29  }
    30  
    31  // Test vectors from https://web.cs.ucdavis.edu/~rogaway/papers/eax.pdf
    32  func TestEncryptDecryptEAXTestVectors(t *testing.T) {
    33  	for _, test := range testVectors {
    34  		adata, _ := hex.DecodeString(test.header)
    35  		key, _ := hex.DecodeString(test.key)
    36  		nonce, _ := hex.DecodeString(test.nonce)
    37  		targetPt, _ := hex.DecodeString(test.msg)
    38  		targetCt, _ := hex.DecodeString(test.ciphertext)
    39  		aesCipher, err := aes.NewCipher(key)
    40  		if err != nil {
    41  			t.Fatal(err)
    42  		}
    43  		eax, err := NewEAX(aesCipher)
    44  		if err != nil {
    45  			t.Fatal(err)
    46  		}
    47  
    48  		ct := eax.Seal(nil, nonce, targetPt, adata)
    49  		if !bytes.Equal(ct, targetCt) {
    50  			t.Errorf(
    51  				`Test vectors Encrypt error (ciphertexts don't match):
    52  				Got:  %X
    53  				Want: %X`, ct, targetCt)
    54  		}
    55  		pt, err := eax.Open(nil, nonce, ct, adata)
    56  		if err != nil {
    57  			t.Errorf(
    58  				`Decrypt refused valid tag:
    59  				ciphertext %X
    60  				key %X
    61  				nonce %X
    62  				header %X`, ct, key, nonce, adata)
    63  		}
    64  		if !bytes.Equal(pt, targetPt) {
    65  			t.Errorf(
    66  				`Test vectors Decrypt error (plaintexts don't match):
    67  				Got:  %X
    68  				Want: %X`, pt, targetPt)
    69  		}
    70  	}
    71  }
    72  
    73  // Test vectors from generated file
    74  func TestEncryptDecryptGoTestVectors(t *testing.T) {
    75  	for _, test := range randomVectors {
    76  		adata, _ := hex.DecodeString(test.header)
    77  		key, _ := hex.DecodeString(test.key)
    78  		nonce, _ := hex.DecodeString(test.nonce)
    79  		targetPt, _ := hex.DecodeString(test.plaintext)
    80  		targetCt, _ := hex.DecodeString(test.ciphertext)
    81  		aesCipher, err := aes.NewCipher(key)
    82  		if err != nil {
    83  			t.Fatal(err)
    84  		}
    85  		eax, err := NewEAX(aesCipher)
    86  		if err != nil {
    87  			t.Fatal(err)
    88  		}
    89  
    90  		ct := eax.Seal(nil, nonce, targetPt, adata)
    91  		if !bytes.Equal(ct, targetCt) {
    92  			t.Errorf(
    93  				`Test vectors Encrypt error (ciphertexts don't match):
    94  				Got:  %X
    95  				Want: %X`, ct, targetCt)
    96  		}
    97  		pt, err := eax.Open(nil, nonce, ct, adata)
    98  		if err != nil {
    99  			t.Errorf(
   100  				`Decrypt refused valid tag:
   101  				ciphertext %X
   102  				key %X
   103  				nonce %X
   104  				header %X`, ct, key, nonce, adata)
   105  		}
   106  		if !bytes.Equal(pt, targetPt) {
   107  			t.Errorf(
   108  				`Test vectors Decrypt error (plaintexts don't match):
   109  				Got:  %X
   110  				Want: %X`, pt, targetPt)
   111  		}
   112  	}
   113  }
   114  
   115  func TestNewEaxIncorrectNonceLength(t *testing.T) {
   116  	aesCipher, err := aes.NewCipher(make([]byte, 16))
   117  	if err != nil {
   118  		t.Fatal(err)
   119  	}
   120  	e, err := NewEAXWithNonceAndTagSize(aesCipher, 0, 16)
   121  	if err == nil || e != nil {
   122  		t.Errorf("EAX with nonceLength 0 was not rejected")
   123  	}
   124  }
   125  
   126  func TestSealIncorrectNonceLength(t *testing.T) {
   127  	aesCipher, err := aes.NewCipher(make([]byte, 16))
   128  	if err != nil {
   129  		t.Fatal(err)
   130  	}
   131  	e, err := NewEAXWithNonceAndTagSize(aesCipher, 16, 16)
   132  	if err != nil {
   133  		t.Fatal(err)
   134  	}
   135  	defer func() {
   136  		if r := recover(); r == nil {
   137  			t.Errorf("Eax.Seal didn't panic on exceedingly long nonce")
   138  		}
   139  	}()
   140  	longNonce := make([]byte, e.NonceSize()+1)
   141  	e.Seal(nil, longNonce, nil, nil)
   142  }
   143  
   144  func TestOpenIncorrectNonceLength(t *testing.T) {
   145  	aesCipher, err := aes.NewCipher(make([]byte, 16))
   146  	if err != nil {
   147  		t.Fatal(err)
   148  	}
   149  	e, err := NewEAXWithNonceAndTagSize(aesCipher, 16, 16)
   150  	if err != nil {
   151  		t.Fatal(err)
   152  	}
   153  	defer func() {
   154  		if r := recover(); r == nil {
   155  			t.Errorf("Eax.Open didn't panic on exceedingly long nonce")
   156  		}
   157  	}()
   158  	longNonce := make([]byte, e.NonceSize()+1)
   159  	_, err = e.Open(nil, longNonce, nil, nil)
   160  	// Let the Open procedure panic
   161  	if err != nil {
   162  	}
   163  }
   164  
   165  func TestOpenShortCiphertext(t *testing.T) {
   166  	aesCipher, err := aes.NewCipher(make([]byte, 16))
   167  	if err != nil {
   168  		t.Fatal(err)
   169  	}
   170  	e, err := NewEAXWithNonceAndTagSize(aesCipher, 16, 16)
   171  	if err != nil {
   172  		t.Fatal(err)
   173  	}
   174  	shortCt := make([]byte, e.Overhead()-1)
   175  	pt, err := e.Open(nil, nil, nil, shortCt)
   176  	if pt != nil || err == nil {
   177  		t.Errorf("Eax.Open processed an exceedingly short ciphertext")
   178  	}
   179  }
   180  
   181  // Generates random examples and tests correctness
   182  func TestEncryptDecryptVectorsWithPreviousDataRandomizeSlow(t *testing.T) {
   183  	// Considering AES
   184  	allowedKeyLengths := []int{16, 24, 32}
   185  	for _, keyLength := range allowedKeyLengths {
   186  		pt := make([]byte, mathrand.Intn(maxLength))
   187  		header := make([]byte, mathrand.Intn(maxLength))
   188  		key := make([]byte, keyLength)
   189  		nonce := make([]byte, 1+mathrand.Intn(blockLength))
   190  		previousData := make([]byte, mathrand.Intn(maxLength-2*blockLength))
   191  		// Populate items with crypto/rand
   192  		itemsToRandomize := [][]byte{pt, header, key, nonce, previousData}
   193  		for _, item := range itemsToRandomize {
   194  			_, err := rand.Read(item)
   195  			if err != nil {
   196  				t.Fatal(err)
   197  			}
   198  		}
   199  		aesCipher, err := aes.NewCipher(key)
   200  		if err != nil {
   201  			t.Fatal(err)
   202  		}
   203  		eax, err := NewEAX(aesCipher)
   204  		if err != nil {
   205  			t.Fatal(err)
   206  		}
   207  		newData := eax.Seal(previousData, nonce, pt, header)
   208  		ct := newData[len(previousData):]
   209  		decrypted, err := eax.Open(nil, nonce, ct, header)
   210  		if err != nil {
   211  			t.Errorf(
   212  				`Decrypt refused valid tag (not displaying long output)`)
   213  			break
   214  		}
   215  		if !bytes.Equal(pt, decrypted) {
   216  			t.Errorf(
   217  				`Random Encrypt/Decrypt error (plaintexts don't match)`)
   218  			break
   219  		}
   220  	}
   221  }
   222  
   223  func TestRejectTamperedCiphertextRandomizeSlow(t *testing.T) {
   224  	pt := make([]byte, mathrand.Intn(maxLength))
   225  	header := make([]byte, mathrand.Intn(maxLength))
   226  	key := make([]byte, blockLength)
   227  	nonce := make([]byte, blockLength)
   228  	itemsToRandomize := [][]byte{pt, header, key, nonce}
   229  	for _, item := range itemsToRandomize {
   230  		_, err := rand.Read(item)
   231  		if err != nil {
   232  			t.Fatal(err)
   233  		}
   234  	}
   235  	aesCipher, err := aes.NewCipher(key)
   236  	if err != nil {
   237  		t.Fatal(err)
   238  	}
   239  	eax, err := NewEAX(aesCipher)
   240  	if err != nil {
   241  		t.Fatal(err)
   242  	}
   243  	ct := eax.Seal(nil, nonce, pt, header)
   244  	// Change one byte of ct (could affect either the tag or the ciphertext)
   245  	tampered := make([]byte, len(ct))
   246  	copy(tampered, ct)
   247  	for bytes.Equal(tampered, ct) {
   248  		tampered[mathrand.Intn(len(ct))] = byte(mathrand.Intn(len(ct)))
   249  	}
   250  	_, err = eax.Open(nil, nonce, tampered, header)
   251  	if err == nil {
   252  		t.Errorf(`Tampered ciphertext was not refused decryption`)
   253  	}
   254  }
   255  
   256  func TestParameters(t *testing.T) {
   257  	t.Run("Should return error on too long tagSize", func(st *testing.T) {
   258  		tagSize := blockLength + 1 + mathrand.Intn(12)
   259  		nonceSize := 1 + mathrand.Intn(16)
   260  		key := make([]byte, blockLength)
   261  		aesCipher, err := aes.NewCipher(key)
   262  		if err != nil {
   263  			t.Fatal(err)
   264  		}
   265  		_, err = NewEAXWithNonceAndTagSize(aesCipher, nonceSize, tagSize)
   266  		if err == nil {
   267  			st.Errorf("No error was given")
   268  		}
   269  	})
   270  	t.Run("Should not give error with allowed custom parameters", func(st *testing.T) {
   271  		key := make([]byte, blockLength)
   272  		nonceSize := mathrand.Intn(32) + 1
   273  		tagSize := 12 + mathrand.Intn(blockLength-11)
   274  		aesCipher, err := aes.NewCipher(key)
   275  		if err != nil {
   276  			t.Fatal(err)
   277  		}
   278  		_, err = NewEAXWithNonceAndTagSize(aesCipher, nonceSize, tagSize)
   279  		if err != nil {
   280  			st.Errorf("An error was returned")
   281  		}
   282  	})
   283  }
   284  
   285  func BenchmarkEncrypt(b *testing.B) {
   286  	headerLength := 16
   287  	pt := make([]byte, maxLength)
   288  	header := make([]byte, headerLength)
   289  	key := make([]byte, blockLength)
   290  	nonce := make([]byte, blockLength)
   291  	itemsToRandomize := [][]byte{pt, header, key, nonce}
   292  	for _, item := range itemsToRandomize {
   293  		_, err := rand.Read(item)
   294  		if err != nil {
   295  			b.Fatal(err)
   296  		}
   297  	}
   298  	aesCipher, err := aes.NewCipher(key)
   299  	if err != nil {
   300  		b.Fatal(err)
   301  	}
   302  	eax, err := NewEAX(aesCipher)
   303  	if err != nil {
   304  		b.Fatal(err)
   305  	}
   306  	for i := 0; i < b.N; i++ {
   307  		eax.Seal(nil, nonce, pt, header)
   308  	}
   309  }
   310  
   311  func BenchmarkDecrypt(b *testing.B) {
   312  	headerLength := 16
   313  	pt := make([]byte, maxLength)
   314  	header := make([]byte, headerLength)
   315  	key := make([]byte, blockLength)
   316  	nonce := make([]byte, blockLength)
   317  	itemsToRandomize := [][]byte{pt, header, key, nonce}
   318  	for _, item := range itemsToRandomize {
   319  		_, err := rand.Read(item)
   320  		if err != nil {
   321  			b.Fatal(err)
   322  		}
   323  	}
   324  	aesCipher, err := aes.NewCipher(key)
   325  	if err != nil {
   326  		b.Fatal(err)
   327  	}
   328  	eax, err := NewEAX(aesCipher)
   329  	if err != nil {
   330  		b.Fatal(err)
   331  	}
   332  	ct := eax.Seal(nil, nonce, pt, header)
   333  	for i := 0; i < b.N; i++ {
   334  		_, err := eax.Open(nil, nonce, ct, header)
   335  		if err != nil {
   336  			b.Fatal(err)
   337  		}
   338  	}
   339  }
   340  

View as plain text