1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package crypto11
23
24 import (
25 "bytes"
26 "crypto/cipher"
27 "runtime"
28 "testing"
29
30 "github.com/miekg/pkcs11"
31 "github.com/stretchr/testify/require"
32 )
33
34 func TestHardSymmetric(t *testing.T) {
35 ctx, err := ConfigureFromFile("config")
36 require.NoError(t, err)
37
38 defer func() {
39 require.NoError(t, ctx.Close())
40 }()
41
42 t.Run("AES128", func(t *testing.T) { testHardSymmetric(t, ctx, pkcs11.CKK_AES, 128) })
43 t.Run("AES192", func(t *testing.T) { testHardSymmetric(t, ctx, pkcs11.CKK_AES, 192) })
44 t.Run("AES256", func(t *testing.T) { testHardSymmetric(t, ctx, pkcs11.CKK_AES, 256) })
45 t.Run("DES3", func(t *testing.T) { testHardSymmetric(t, ctx, pkcs11.CKK_DES3, 0) })
46 }
47
48 func testHardSymmetric(t *testing.T, ctx *Context, keytype int, bits int) {
49 for _, p := range Ciphers[keytype].GenParams {
50 skipIfMechUnsupported(t, ctx, p.GenMech)
51 }
52
53 id := randomBytes()
54 key, err := ctx.GenerateSecretKey(id, bits, Ciphers[keytype])
55 require.NoError(t, err)
56 require.NotNil(t, key)
57 defer key.Delete()
58
59 var key2 *SecretKey
60 t.Run("Find", func(t *testing.T) {
61 key2, err = ctx.FindKey(id, nil)
62 require.NoError(t, err)
63 })
64
65 t.Run("Block", func(t *testing.T) {
66 skipIfMechUnsupported(t, key.context, key.Cipher.ECBMech)
67 testSymmetricBlock(t, key, key2)
68 })
69
70 iv := make([]byte, key.BlockSize())
71 for i := range iv {
72 iv[i] = 0xF0
73 }
74
75 t.Run("CBC", func(t *testing.T) {
76
77 skipIfMechUnsupported(t, key2.context, key2.Cipher.ECBMech)
78 testSymmetricMode(t, cipher.NewCBCEncrypter(key2, iv), cipher.NewCBCDecrypter(key2, iv))
79 })
80
81 t.Run("CBCClose", func(t *testing.T) {
82 skipIfMechUnsupported(t, key2.context, key2.Cipher.CBCMech)
83 enc, err := key2.NewCBCEncrypterCloser(iv)
84 require.NoError(t, err)
85
86 dec, err := key2.NewCBCDecrypterCloser(iv)
87 require.NoError(t, err)
88
89 testSymmetricMode(t, enc, dec)
90 enc.Close()
91 dec.Close()
92 })
93
94 t.Run("CBCNoClose", func(t *testing.T) {
95 skipIfMechUnsupported(t, key2.context, key2.Cipher.CBCMech)
96 enc, err := key2.NewCBCEncrypter(iv)
97 require.NoError(t, err)
98
99 dec, err := key2.NewCBCDecrypter(iv)
100 require.NoError(t, err)
101 testSymmetricMode(t, enc, dec)
102
103
104 runtime.GC()
105 })
106
107 t.Run("CBCSealOpen", func(t *testing.T) {
108 aead, err := key2.NewCBC(PaddingNone)
109 require.NoError(t, err)
110 testAEADMode(t, aead, 128, 0)
111 })
112
113 t.Run("CBCPKCSSealOpen", func(t *testing.T) {
114 aead, err := key2.NewCBC(PaddingPKCS)
115 require.NoError(t, err)
116 testAEADMode(t, aead, 127, 0)
117 })
118 if bits == 128 {
119 t.Run("GCMSoft", func(t *testing.T) {
120 aead, err := cipher.NewGCM(key2)
121 require.NoError(t, err)
122 testAEADMode(t, aead, 127, 129)
123 })
124 t.Run("GCMHard", func(t *testing.T) {
125 aead, err := key2.NewGCM()
126 require.NoError(t, err)
127 skipIfMechUnsupported(t, key2.context, pkcs11.CKM_AES_GCM)
128 testAEADMode(t, aead, 127, 129)
129 })
130
131 }
132
133
134
135
136 }
137
138 func testSymmetricBlock(t *testing.T, encryptKey cipher.Block, decryptKey cipher.Block) {
139
140
141 defer func() {
142 if cause := recover(); cause != nil {
143 t.Fatalf("Caught panic: %q", cause)
144 }
145 }()
146
147 b := encryptKey.BlockSize()
148 input := make([]byte, 3*b)
149 middle := make([]byte, 3*b)
150 output := make([]byte, 3*b)
151
152 for i := 0; i < 3*b; i++ {
153 input[i] = byte(i)
154 middle[i] = byte(i + 3*b)
155 output[i] = byte(i + 6*b)
156 }
157 encryptKey.Encrypt(middle, input)
158 if bytes.Equal(input[:b], middle[:b]) {
159 t.Errorf("crypto11.PKCSSecretKey.Encrypt: identity transformation")
160 return
161 }
162 matches := 0
163 for i := 0; i < b; i++ {
164 if middle[i] == byte(i+3*b) {
165 matches++
166 }
167 }
168 if matches == b {
169 t.Errorf("crypto11.PKCSSecretKey.Encrypt: didn't modify destination")
170 return
171 }
172 for i := 0; i < 3*b; i++ {
173 if input[i] != byte(i) {
174 t.Errorf("crypto11.PKCSSecretKey.Encrypt: corrupted source")
175 return
176 }
177 if i >= b && middle[i] != byte(i+3*b) {
178 t.Errorf("crypto11.PKCSSecretKey.Encrypt: corrupted destination past blocksize")
179 return
180 }
181 }
182 decryptKey.Decrypt(output, middle)
183 if !bytes.Equal(input[:b], output[:b]) {
184 t.Errorf("crypto11.PKCSSecretKey.Decrypt: plaintext wrong")
185 return
186 }
187 for i := 0; i < 3*b; i++ {
188 if i >= b && output[i] != byte(i+6*b) {
189 t.Errorf("crypto11.PKCSSecretKey.Decrypt: corrupted destination past blocksize")
190 return
191 }
192 }
193 }
194
195 func testSymmetricMode(t *testing.T, encrypt cipher.BlockMode, decrypt cipher.BlockMode) {
196
197
198 defer func() {
199 if cause := recover(); cause != nil {
200 t.Fatalf("Caught panic: %q", cause)
201 }
202 }()
203
204 input := make([]byte, 256)
205 middle := make([]byte, 256)
206 output := make([]byte, 256)
207
208 for i := 0; i < 256; i++ {
209 input[i] = byte(i)
210 middle[i] = byte(i + 32)
211 output[i] = byte(i + 64)
212 }
213
214 encrypt.CryptBlocks(middle, input[:128])
215 if bytes.Equal(input[:128], middle[:128]) {
216 t.Errorf("BlockMode.Encrypt: did not modify destination")
217 return
218 }
219 for i := 0; i < 128; i++ {
220 if input[i] != byte(i) {
221 t.Errorf("BlockMode.Encrypt: corrupted source")
222 return
223 }
224 }
225 for i := 128; i < 256; i++ {
226 if middle[i] != byte(i+32) {
227 t.Errorf("BlockMode.Encrypt: corrupted destination past input size")
228 return
229 }
230 }
231
232 encrypt.CryptBlocks(middle[128:], input[128:])
233
234 decrypt.CryptBlocks(output, middle)
235 if !bytes.Equal(input, output) {
236 t.Errorf("BlockMode.Decrypt: plaintext wrong")
237 return
238 }
239 }
240
241 func testAEADMode(t *testing.T, aead cipher.AEAD, ptlen int, adlen int) {
242 nonce := make([]byte, aead.NonceSize())
243 plaintext := make([]byte, ptlen)
244 for i := 0; i < len(plaintext); i++ {
245 plaintext[i] = byte(i)
246 }
247 additionalData := make([]byte, adlen)
248 for i := 0; i < len(additionalData); i++ {
249 additionalData[i] = byte(i + 16)
250 }
251 ciphertext := aead.Seal([]byte{}, nonce, plaintext, additionalData)
252
253
257 if len(ciphertext) == aead.NonceSize()+len(plaintext)+aead.Overhead() {
258 nonce = ciphertext[len(ciphertext)-aead.NonceSize():]
259 ciphertext = ciphertext[:len(ciphertext)-aead.NonceSize()]
260 }
261
262 decrypted, err := aead.Open([]byte{}, nonce, ciphertext, additionalData)
263 if err != nil {
264 t.Errorf("aead.Open: %s", err)
265 return
266 }
267 if !bytes.Equal(plaintext, decrypted) {
268 t.Errorf("aead.Open: mismatch")
269 return
270 }
271 }
272
273 func BenchmarkCBC(b *testing.B) {
274 ctx, err := ConfigureFromFile("config")
275 require.NoError(b, err)
276
277 defer func() {
278 require.NoError(b, ctx.Close())
279 }()
280
281 id := randomBytes()
282 key, err := ctx.GenerateSecretKey(id, 128, Ciphers[pkcs11.CKK_AES])
283 require.NoError(b, err)
284 require.NotNil(b, key)
285 defer key.Delete()
286
287 iv := make([]byte, 16)
288 plaintext := make([]byte, 65536)
289 ciphertext := make([]byte, 65536)
290
291 b.Run("Native", func(b *testing.B) {
292 for i := 0; i < b.N; i++ {
293 mode := cipher.NewCBCEncrypter(key, iv)
294 mode.CryptBlocks(ciphertext, plaintext)
295 }
296 })
297
298 b.Run("IdiomaticClose", func(b *testing.B) {
299 for i := 0; i < b.N; i++ {
300 mode, err := key.NewCBCEncrypterCloser(iv)
301 if err != nil {
302 panic(err)
303 }
304 mode.CryptBlocks(ciphertext, plaintext)
305 mode.Close()
306 }
307 })
308
309 b.Run("Idiomatic", func(b *testing.B) {
310 for i := 0; i < b.N; i++ {
311 mode, err := key.NewCBCEncrypter(iv)
312 if err != nil {
313 panic(err)
314 }
315 mode.CryptBlocks(ciphertext, plaintext)
316 }
317 runtime.GC()
318 })
319 }
320
321 func TestSymmetricRequiredArgs(t *testing.T) {
322 ctx, err := ConfigureFromFile("config")
323 require.NoError(t, err)
324
325 defer func() {
326 require.NoError(t, ctx.Close())
327 }()
328
329 _, err = ctx.GenerateSecretKey(nil, 128, CipherAES)
330 require.Error(t, err)
331
332 val := randomBytes()
333
334 _, err = ctx.GenerateSecretKeyWithLabel(nil, val, 128, CipherAES)
335 require.Error(t, err)
336
337 _, err = ctx.GenerateSecretKeyWithLabel(val, nil, 128, CipherAES)
338 require.Error(t, err)
339 }
340
341
342
View as plain text