github.com/mad-day/Yawning-crypto@v0.0.0-20190711051033-5a5f8cca32ec/aez/aez_test.go (about)

     1  // aez_test.go - AEZ tests.
     2  //
     3  // To the extent possible under law, Yawning Angel has waived all copyright
     4  // and related or neighboring rights to aez, using the Creative
     5  // Commons "CC0" public domain dedication. See LICENSE or
     6  // <http://creativecommons.org/publicdomain/zero/1.0/> for full details.
     7  
     8  package aez
     9  
    10  import (
    11  	"bytes"
    12  	"crypto/cipher"
    13  	"crypto/rand"
    14  	"encoding/hex"
    15  	"encoding/json"
    16  	"fmt"
    17  	"os"
    18  	"path/filepath"
    19  	"testing"
    20  )
    21  
    22  func readJsonTestdata(t *testing.T, name string, destination interface{}) {
    23  	var file *os.File
    24  	file, err := os.Open(filepath.Join("testdata", name))
    25  	if err != nil {
    26  		t.Fatalf("Failed to read test vectors in %s", name)
    27  	}
    28  
    29  	decoder := json.NewDecoder(file)
    30  	if err := decoder.Decode(&destination); err != nil {
    31  		t.Fatalf("Failed to parse test vectors in %s", name)
    32  	}
    33  }
    34  
    35  // (a,b)  ==>  Extract(a) = b.
    36  type ExtractVector struct {
    37  	A string `json:"a"`
    38  	B string `json:"b"`
    39  }
    40  
    41  func TestExtract(t *testing.T) {
    42  	var extractVectors []ExtractVector
    43  
    44  	readJsonTestdata(t, "extract.json", &extractVectors)
    45  
    46  	for i, vec := range extractVectors {
    47  		var extractedKey [extractedKeySize]byte
    48  
    49  		vecA, err := hex.DecodeString(vec.A)
    50  		if err != nil {
    51  			t.Fatal(err)
    52  		}
    53  		vecB, err := hex.DecodeString(vec.B)
    54  		if err != nil {
    55  			t.Fatal(err)
    56  		}
    57  
    58  		extract(vecA, &extractedKey)
    59  		assertEqual(t, i, vecB, extractedKey[:])
    60  	}
    61  }
    62  
    63  // {K, tau, [N, A...], V) ==> AEZ-hash{K, {[tau]_128, N, A...)) = V
    64  type HashVector struct {
    65  	K    string   `json:"k"`
    66  	Tau  int      `json:"tau"`
    67  	Data []string `json:"data"`
    68  	V    string   `json:"v"`
    69  }
    70  
    71  func TestHash(t *testing.T) {
    72  	var e eState
    73  	var hashVectors []HashVector
    74  
    75  	readJsonTestdata(t, "hash.json", &hashVectors)
    76  
    77  	for i, vec := range hashVectors {
    78  		vecK, err := hex.DecodeString(vec.K)
    79  		if err != nil {
    80  			t.Fatal(err)
    81  		}
    82  		var data [][]byte
    83  		for _, v := range vec.Data {
    84  			d, err := hex.DecodeString(v)
    85  			if err != nil {
    86  				t.Fatal(err)
    87  			}
    88  			data = append(data, d)
    89  		}
    90  		vecV, err := hex.DecodeString(vec.V)
    91  		if err != nil {
    92  			t.Fatal(err)
    93  		}
    94  
    95  		var nonce []byte
    96  		var ad [][]byte
    97  		if len(data) > 0 {
    98  			nonce = data[0]
    99  			if len(data) > 1 {
   100  				ad = data[1:]
   101  			}
   102  		}
   103  
   104  		var result [blockSize]byte
   105  
   106  		e.init(vecK)
   107  		e.aezHash(nonce, ad, vec.Tau, result[:])
   108  		assertEqual(t, i, vecV, result[:])
   109  	}
   110  }
   111  
   112  // (K, delta, tau, R) ==> AEZ-prf(K, T, tau*8) = R where delta = AEZ-hash(K,T)
   113  type PrfVector struct {
   114  	K     string `json:"k"`
   115  	Delta string `json:"delta"`
   116  	Tau   int    `json:"tau"`
   117  	R     string `json:"R"`
   118  }
   119  
   120  func TestPRF(t *testing.T) {
   121  	var e eState
   122  	var prfVectors []PrfVector
   123  
   124  	readJsonTestdata(t, "prf.json", &prfVectors)
   125  
   126  	for i, vec := range prfVectors {
   127  		vecK, err := hex.DecodeString(vec.K)
   128  		if err != nil {
   129  			t.Fatal(err)
   130  		}
   131  		vecDelta, err := hex.DecodeString(vec.Delta)
   132  		if err != nil {
   133  			t.Fatal(err)
   134  		}
   135  		vecR, err := hex.DecodeString(vec.R)
   136  		if err != nil {
   137  			t.Fatal(err)
   138  		}
   139  
   140  		var vDelta [blockSize]byte
   141  		copy(vDelta[:], vecDelta)
   142  
   143  		result := make([]byte, len(vecR))
   144  		e.init(vecK)
   145  		e.aezPRF(&vDelta, vec.Tau, result)
   146  		assertEqual(t, i, vecR, result)
   147  	}
   148  }
   149  
   150  // (K, N, A, taubytes, M, C) ==> Encrypt(K,N,A,taubytes,M) = C
   151  type EncryptVector struct {
   152  	K     string   `json:"k"`
   153  	Nonce string   `json:"nonce"`
   154  	Data  []string `json:"data"`
   155  	Tau   int      `json:"tau"`
   156  	M     string   `json:"m"`
   157  	C     string   `json:"c"`
   158  }
   159  
   160  func TestEncryptDecrypt(t *testing.T) {
   161  	var encryptVectors []EncryptVector
   162  
   163  	readJsonTestdata(t, "encrypt.json", &encryptVectors)
   164  	assertEncrypt(t, encryptVectors)
   165  
   166  	//
   167  	// No AD test cases
   168  	//
   169  	readJsonTestdata(t, "encrypt_no_ad.json", &encryptVectors)
   170  	assertEncrypt(t, encryptVectors)
   171  
   172  	//
   173  	// 33 bytes of AD test cases
   174  	//
   175  	readJsonTestdata(t, "encrypt_33_byte_ad.json", &encryptVectors)
   176  	assertEncrypt(t, encryptVectors)
   177  
   178  	//
   179  	// 16 byte key test cases
   180  	//
   181  	readJsonTestdata(t, "encrypt_16_byte_key.json", &encryptVectors)
   182  	assertEncrypt(t, encryptVectors)
   183  }
   184  
   185  func assertEncrypt(t *testing.T, vectors []EncryptVector) {
   186  	var e eState
   187  
   188  	for i, vec := range vectors {
   189  		vecK, err := hex.DecodeString(vec.K)
   190  		if err != nil {
   191  			t.Fatal(err)
   192  		}
   193  		vecNonce, err := hex.DecodeString(vec.Nonce)
   194  		if err != nil {
   195  			t.Fatal(err)
   196  		}
   197  		var vecData [][]byte
   198  		for _, s := range vec.Data {
   199  			d, err := hex.DecodeString(s)
   200  			if err != nil {
   201  				t.Fatal(err)
   202  			}
   203  			vecData = append(vecData, d)
   204  		}
   205  		vecM, err := hex.DecodeString(vec.M)
   206  		if err != nil {
   207  			t.Fatal(err)
   208  		}
   209  		vecC, err := hex.DecodeString(vec.C)
   210  		if err != nil {
   211  			t.Fatal(err)
   212  		}
   213  
   214  		// Test the cipher.AEAD code as well, for applicable test vectors.
   215  		var aead cipher.AEAD
   216  		var ad []byte
   217  		if len(vecNonce) == aeadNonceSize && vec.Tau == aeadOverhead && len(vecData) <= 1 {
   218  			aead, err = New(vecK)
   219  			if err != nil {
   220  				t.Fatal(err)
   221  			}
   222  			if len(vecData) == 1 {
   223  				ad = vecData[0]
   224  			}
   225  		}
   226  
   227  		e.init(vecK)
   228  		c := Encrypt(vecK, vecNonce, vecData, vec.Tau, vecM, nil)
   229  		assertEqual(t, i, vecC, c)
   230  		if aead != nil {
   231  			ac := aead.Seal(nil, vecNonce, vecM, ad)
   232  			assertEqual(t, i, vecC, ac)
   233  		}
   234  
   235  		m, ok := Decrypt(vecK, vecNonce, vecData, vec.Tau, vecC, nil)
   236  		if !ok {
   237  			t.Fatalf("decrypt failed: [%d]", i)
   238  		}
   239  		assertEqual(t, i, vecM, m)
   240  		if aead != nil {
   241  			am, err := aead.Open(nil, vecNonce, vecC, ad)
   242  			if err != nil {
   243  				t.Fatal(err)
   244  			}
   245  			assertEqual(t, i, vecM, am)
   246  		}
   247  	}
   248  }
   249  
   250  func assertEqual(t *testing.T, idx int, expected, actual []byte) {
   251  	if !bytes.Equal(expected, actual) {
   252  		for i, v := range actual {
   253  			if expected[i] != v {
   254  				t.Errorf("[%d] first mismatch at offset: %d (%02x != %02x)", idx, i, expected[i], v)
   255  				break
   256  			}
   257  		}
   258  		t.Errorf("expected: %s", hex.Dump(expected))
   259  		t.Errorf("actual: %s", hex.Dump(actual))
   260  		t.FailNow()
   261  	}
   262  }
   263  
   264  var benchOutput []byte
   265  
   266  func doBenchEncrypt(b *testing.B, n int) {
   267  	var key [extractedKeySize]byte
   268  	if _, err := rand.Read(key[:]); err != nil {
   269  		b.Error(err)
   270  		b.Fail()
   271  	}
   272  
   273  	const tau = 16
   274  
   275  	var nonce [16]byte
   276  	src := make([]byte, n)
   277  	dst := make([]byte, n+tau)
   278  	check := make([]byte, n+tau)
   279  
   280  	b.SetBytes(int64(n))
   281  	b.ResetTimer()
   282  	for i := 0; i < b.N; i++ {
   283  		b.StartTimer()
   284  		dst = Encrypt(key[:], nonce[:], nil, tau, src[:n], dst[:0])
   285  		b.StopTimer()
   286  		dec, ok := Decrypt(key[:], nonce[:], nil, tau, dst, check[:0])
   287  		if !ok {
   288  			b.Fatalf("decrypt failed")
   289  		}
   290  		if !bytes.Equal(dec, src) {
   291  			b.Fatalf("decrypt produced invalid output")
   292  		}
   293  		copy(src, dst[:n])
   294  	}
   295  
   296  	benchOutput = src
   297  }
   298  
   299  func BenchmarkEncrypt(b *testing.B) {
   300  	sizes := []int{1, 32, 512, 1024, 2048, 16384, 32768, 65536, 1024768}
   301  	if testing.Short() {
   302  		sizes = []int{1, 32, 512, 1024, 16384, 65536, 1024768}
   303  	}
   304  
   305  	b.SetParallelism(1) // AES-NI is a per-physical core thing.
   306  
   307  	for _, sz := range sizes {
   308  		n := fmt.Sprintf("%d", sz)
   309  		b.Run(n, func(b *testing.B) { doBenchEncrypt(b, sz) })
   310  	}
   311  }