Source file src/crypto/subtle/xor_test.go

     1  // Copyright 2013 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package subtle_test
     6  
     7  import (
     8  	"bytes"
     9  	"crypto/internal/cryptotest"
    10  	"crypto/rand"
    11  	. "crypto/subtle"
    12  	"fmt"
    13  	"testing"
    14  )
    15  
    16  func TestXORBytes(t *testing.T) {
    17  	cryptotest.TestAllImplementations(t, "subtle", testXORBytes)
    18  }
    19  
    20  func testXORBytes(t *testing.T) {
    21  	for n := 1; n <= 1024; n++ {
    22  		if n > 16 && testing.Short() {
    23  			n += n >> 3
    24  		}
    25  		for alignP := 0; alignP < 8; alignP++ {
    26  			for alignQ := 0; alignQ < 8; alignQ++ {
    27  				for alignD := 0; alignD < 8; alignD++ {
    28  					p := make([]byte, alignP+n, alignP+n+100)[alignP:]
    29  					q := make([]byte, alignQ+n, alignQ+n+100)[alignQ:]
    30  					if n&1 != 0 {
    31  						p = p[:n]
    32  					} else {
    33  						q = q[:n]
    34  					}
    35  					rand.Read(p)
    36  					rand.Read(q)
    37  
    38  					d := make([]byte, alignD+n+100)
    39  					rand.Read(d)
    40  
    41  					want := bytes.Clone(d)
    42  					for i := range n {
    43  						want[alignD+i] = p[i] ^ q[i]
    44  					}
    45  
    46  					if nn := XORBytes(d[alignD:], p, q); !bytes.Equal(d, want) {
    47  						t.Errorf("n=%d alignP=%d alignQ=%d alignD=%d:\n\tp = %x\n\tq = %x\n\td = %x\n\twant %x\n", n, alignP, alignQ, alignD, p, q, d, want)
    48  					} else if nn != n {
    49  						t.Errorf("n=%d alignP=%d alignQ=%d alignD=%d: got %d, want %d", n, alignP, alignQ, alignD, nn, n)
    50  					}
    51  					p1 := bytes.Clone(p)
    52  					if nn := XORBytes(p, p, q); !bytes.Equal(p, want[alignD:alignD+n]) {
    53  						t.Errorf("n=%d alignP=%d alignQ=%d alignD=%d:\n\tp = %x\n\tq = %x\n\td = %x\n\twant %x\n", n, alignP, alignQ, alignD, p, q, d, want)
    54  					} else if nn != n {
    55  						t.Errorf("n=%d alignP=%d alignQ=%d alignD=%d: got %d, want %d", n, alignP, alignQ, alignD, nn, n)
    56  					}
    57  					if nn := XORBytes(q, p1, q); !bytes.Equal(q, want[alignD:alignD+n]) {
    58  						t.Errorf("n=%d alignP=%d alignQ=%d alignD=%d:\n\tp = %x\n\tq = %x\n\td = %x\n\twant %x\n", n, alignP, alignQ, alignD, p, q, d, want)
    59  					} else if nn != n {
    60  						t.Errorf("n=%d alignP=%d alignQ=%d alignD=%d: got %d, want %d", n, alignP, alignQ, alignD, nn, n)
    61  					}
    62  
    63  					if nn := XORBytes(p, p, p); !bytes.Equal(p, make([]byte, n)) {
    64  						t.Errorf("n=%d alignP=%d alignQ=%d alignD=%d: got %x, want %x", n, alignP, alignQ, alignD, p, make([]byte, n))
    65  					} else if nn != n {
    66  						t.Errorf("n=%d alignP=%d alignQ=%d alignD=%d: got %d, want %d", n, alignP, alignQ, alignD, nn, n)
    67  					}
    68  					if nn := XORBytes(p1, q, q); !bytes.Equal(p1, make([]byte, n)) {
    69  						t.Errorf("n=%d alignP=%d alignQ=%d alignD=%d: got %x, want %x", n, alignP, alignQ, alignD, p1, make([]byte, n))
    70  					} else if nn != n {
    71  						t.Errorf("n=%d alignP=%d alignQ=%d alignD=%d: got %d, want %d", n, alignP, alignQ, alignD, nn, n)
    72  					}
    73  				}
    74  			}
    75  		}
    76  	}
    77  }
    78  
    79  func TestXorBytesPanic(t *testing.T) {
    80  	mustPanic(t, "subtle.XORBytes: dst too short", func() {
    81  		XORBytes(nil, make([]byte, 1), make([]byte, 1))
    82  	})
    83  	mustPanic(t, "subtle.XORBytes: dst too short", func() {
    84  		XORBytes(make([]byte, 1), make([]byte, 2), make([]byte, 3))
    85  	})
    86  	mustPanic(t, "subtle.XORBytes: invalid overlap", func() {
    87  		x := make([]byte, 3)
    88  		XORBytes(x, x[1:], make([]byte, 2))
    89  	})
    90  	mustPanic(t, "subtle.XORBytes: invalid overlap", func() {
    91  		x := make([]byte, 3)
    92  		XORBytes(x, make([]byte, 2), x[1:])
    93  	})
    94  }
    95  
    96  func TestXORBytesBoundary(t *testing.T) {
    97  	cryptotest.TestAllImplementations(t, "subtle", testXORBytesBoundary)
    98  }
    99  
   100  func testXORBytesBoundary(t *testing.T) {
   101  	safe := make([]byte, 1000)
   102  	start, end := cryptotest.BoundarySlices(t, 1000)
   103  	for i := 1; i <= 1000; i++ {
   104  		start := start[:i]
   105  		end := end[len(end)-i:]
   106  		XORBytes(end, safe, safe[:i])
   107  		XORBytes(start, safe, safe[:i])
   108  		XORBytes(safe, start, safe)
   109  		XORBytes(safe, end, safe)
   110  		XORBytes(safe, safe, start)
   111  		XORBytes(safe, safe, end)
   112  	}
   113  }
   114  
   115  func BenchmarkXORBytes(b *testing.B) {
   116  	dst := make([]byte, 1<<15)
   117  	data0 := make([]byte, 1<<15)
   118  	data1 := make([]byte, 1<<15)
   119  	sizes := []int64{1 << 3, 1 << 7, 1 << 11, 1 << 13, 1 << 15}
   120  	for _, size := range sizes {
   121  		b.Run(fmt.Sprintf("%dBytes", size), func(b *testing.B) {
   122  			s0 := data0[:size]
   123  			s1 := data1[:size]
   124  			b.SetBytes(int64(size))
   125  			for i := 0; i < b.N; i++ {
   126  				XORBytes(dst, s0, s1)
   127  			}
   128  		})
   129  	}
   130  }
   131  
   132  func BenchmarkXORBytesAlignment(b *testing.B) {
   133  	dst := make([]byte, 8+1<<11)
   134  	data0 := make([]byte, 8+1<<11)
   135  	data1 := make([]byte, 8+1<<11)
   136  	sizes := []int64{1 << 3, 1 << 7, 1 << 11}
   137  	for _, size := range sizes {
   138  		for offset := int64(0); offset < 8; offset++ {
   139  			b.Run(fmt.Sprintf("%dBytes%dOffset", size, offset), func(b *testing.B) {
   140  				d := dst[offset : offset+size]
   141  				s0 := data0[offset : offset+size]
   142  				s1 := data1[offset : offset+size]
   143  				b.SetBytes(int64(size))
   144  				for i := 0; i < b.N; i++ {
   145  					XORBytes(d, s0, s1)
   146  				}
   147  			})
   148  		}
   149  	}
   150  }
   151  
   152  func mustPanic(t *testing.T, expected string, f func()) {
   153  	t.Helper()
   154  	defer func() {
   155  		t.Helper()
   156  		switch msg := recover().(type) {
   157  		case nil:
   158  			t.Errorf("expected panic(%q), but did not panic", expected)
   159  		case string:
   160  			if msg != expected {
   161  				t.Errorf("expected panic(%q), but got panic(%q)", expected, msg)
   162  			}
   163  		default:
   164  			t.Errorf("expected panic(%q), but got panic(%T%v)", expected, msg, msg)
   165  		}
   166  	}()
   167  	f()
   168  }
   169  

View as plain text