1
2
3
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 for n := 1; n <= 1024; n++ {
18 if n > 16 && testing.Short() {
19 n += n >> 3
20 }
21 for alignP := 0; alignP < 8; alignP++ {
22 for alignQ := 0; alignQ < 8; alignQ++ {
23 for alignD := 0; alignD < 8; alignD++ {
24 p := make([]byte, alignP+n, alignP+n+100)[alignP:]
25 q := make([]byte, alignQ+n, alignQ+n+100)[alignQ:]
26 if n&1 != 0 {
27 p = p[:n]
28 } else {
29 q = q[:n]
30 }
31 rand.Read(p)
32 rand.Read(q)
33
34 d := make([]byte, alignD+n+100)
35 rand.Read(d)
36
37 want := bytes.Clone(d)
38 for i := range n {
39 want[alignD+i] = p[i] ^ q[i]
40 }
41
42 if nn := XORBytes(d[alignD:], p, q); !bytes.Equal(d, want) {
43 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)
44 } else if nn != n {
45 t.Errorf("n=%d alignP=%d alignQ=%d alignD=%d: got %d, want %d", n, alignP, alignQ, alignD, nn, n)
46 }
47 p1 := bytes.Clone(p)
48 if nn := XORBytes(p, p, q); !bytes.Equal(p, want[alignD:alignD+n]) {
49 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)
50 } else if nn != n {
51 t.Errorf("n=%d alignP=%d alignQ=%d alignD=%d: got %d, want %d", n, alignP, alignQ, alignD, nn, n)
52 }
53 if nn := XORBytes(q, p1, q); !bytes.Equal(q, want[alignD:alignD+n]) {
54 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)
55 } else if nn != n {
56 t.Errorf("n=%d alignP=%d alignQ=%d alignD=%d: got %d, want %d", n, alignP, alignQ, alignD, nn, n)
57 }
58
59 if nn := XORBytes(p, p, p); !bytes.Equal(p, make([]byte, n)) {
60 t.Errorf("n=%d alignP=%d alignQ=%d alignD=%d: got %x, want %x", n, alignP, alignQ, alignD, p, make([]byte, n))
61 } else if nn != n {
62 t.Errorf("n=%d alignP=%d alignQ=%d alignD=%d: got %d, want %d", n, alignP, alignQ, alignD, nn, n)
63 }
64 if nn := XORBytes(p1, q, q); !bytes.Equal(p1, make([]byte, n)) {
65 t.Errorf("n=%d alignP=%d alignQ=%d alignD=%d: got %x, want %x", n, alignP, alignQ, alignD, p1, make([]byte, n))
66 } else if nn != n {
67 t.Errorf("n=%d alignP=%d alignQ=%d alignD=%d: got %d, want %d", n, alignP, alignQ, alignD, nn, n)
68 }
69 }
70 }
71 }
72 }
73 }
74
75 func TestXorBytesPanic(t *testing.T) {
76 mustPanic(t, "subtle.XORBytes: dst too short", func() {
77 XORBytes(nil, make([]byte, 1), make([]byte, 1))
78 })
79 mustPanic(t, "subtle.XORBytes: dst too short", func() {
80 XORBytes(make([]byte, 1), make([]byte, 2), make([]byte, 3))
81 })
82 mustPanic(t, "subtle.XORBytes: invalid overlap", func() {
83 x := make([]byte, 3)
84 XORBytes(x, x[1:], make([]byte, 2))
85 })
86 mustPanic(t, "subtle.XORBytes: invalid overlap", func() {
87 x := make([]byte, 3)
88 XORBytes(x, make([]byte, 2), x[1:])
89 })
90 }
91
92 func TestXORBytesBoundary(t *testing.T) {
93 safe := make([]byte, 1000)
94 start, end := cryptotest.BoundarySlices(t, 1000)
95 for i := 1; i <= 1000; i++ {
96 start := start[:i]
97 end := end[len(end)-i:]
98 XORBytes(end, safe, safe[:i])
99 XORBytes(start, safe, safe[:i])
100 XORBytes(safe, start, safe)
101 XORBytes(safe, end, safe)
102 XORBytes(safe, safe, start)
103 XORBytes(safe, safe, end)
104 }
105 }
106
107 func BenchmarkXORBytes(b *testing.B) {
108 dst := make([]byte, 1<<15)
109 data0 := make([]byte, 1<<15)
110 data1 := make([]byte, 1<<15)
111 sizes := []int64{1 << 3, 1 << 7, 1 << 11, 1 << 13, 1 << 15}
112 for _, size := range sizes {
113 b.Run(fmt.Sprintf("%dBytes", size), func(b *testing.B) {
114 s0 := data0[:size]
115 s1 := data1[:size]
116 b.SetBytes(int64(size))
117 for i := 0; i < b.N; i++ {
118 XORBytes(dst, s0, s1)
119 }
120 })
121 }
122 }
123
124 func BenchmarkXORBytesAlignment(b *testing.B) {
125 dst := make([]byte, 8+1<<11)
126 data0 := make([]byte, 8+1<<11)
127 data1 := make([]byte, 8+1<<11)
128 sizes := []int64{1 << 3, 1 << 7, 1 << 11}
129 for _, size := range sizes {
130 for offset := int64(0); offset < 8; offset++ {
131 b.Run(fmt.Sprintf("%dBytes%dOffset", size, offset), func(b *testing.B) {
132 d := dst[offset : offset+size]
133 s0 := data0[offset : offset+size]
134 s1 := data1[offset : offset+size]
135 b.SetBytes(int64(size))
136 for i := 0; i < b.N; i++ {
137 XORBytes(d, s0, s1)
138 }
139 })
140 }
141 }
142 }
143
144 func mustPanic(t *testing.T, expected string, f func()) {
145 t.Helper()
146 defer func() {
147 t.Helper()
148 switch msg := recover().(type) {
149 case nil:
150 t.Errorf("expected panic(%q), but did not panic", expected)
151 case string:
152 if msg != expected {
153 t.Errorf("expected panic(%q), but got panic(%q)", expected, msg)
154 }
155 default:
156 t.Errorf("expected panic(%q), but got panic(%T%v)", expected, msg, msg)
157 }
158 }()
159 f()
160 }
161
View as plain text