When inplace encryption is required then enforce it rather than doing a low-performan...
[cryptodev-linux.git] / tests / cipher-gcm.c
blob9b5f4f9470753d6f26bb037f7e24d416da4f5f16
1 /*
2 * Demo on how to use /dev/crypto device for ciphering.
4 * Placed under public domain.
6 */
7 #include <stdio.h>
8 #include <stdint.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <fcntl.h>
13 #include <sys/ioctl.h>
14 #include <crypto/cryptodev.h>
16 #define DATA_SIZE (8*1024)
17 #define AUTH_SIZE 31
18 #define BLOCK_SIZE 16
19 #define KEY_SIZE 16
21 #define my_perror(x) {fprintf(stderr, "%s: %d\n", __func__, __LINE__); perror(x); }
23 static void print_buf(char *desc, const unsigned char *buf, int size)
25 int i;
26 fputs(desc, stdout);
27 for (i = 0; i < size; i++) {
28 printf("%.2x", (uint8_t) buf[i]);
30 fputs("\n", stdout);
33 struct aes_gcm_vectors_st {
34 const uint8_t *key;
35 const uint8_t *auth;
36 int auth_size;
37 const uint8_t *plaintext;
38 int plaintext_size;
39 const uint8_t *iv;
40 const uint8_t *ciphertext;
41 const uint8_t *tag;
44 struct aes_gcm_vectors_st aes_gcm_vectors[] = {
46 .key =
47 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
48 .auth = NULL,
49 .auth_size = 0,
50 .plaintext =
51 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
52 .plaintext_size = 16,
53 .ciphertext =
54 "\x03\x88\xda\xce\x60\xb6\xa3\x92\xf3\x28\xc2\xb9\x71\xb2\xfe\x78",
55 .iv = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
56 .tag =
57 "\xab\x6e\x47\xd4\x2c\xec\x13\xbd\xf5\x3a\x67\xb2\x12\x57\xbd\xdf"
60 .key =
61 "\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08",
62 .auth = NULL,
63 .auth_size = 0,
64 .plaintext =
65 "\xd9\x31\x32\x25\xf8\x84\x06\xe5\xa5\x59\x09\xc5\xaf\xf5\x26\x9a\x86\xa7\xa9\x53\x15\x34\xf7\xda\x2e\x4c\x30\x3d\x8a\x31\x8a\x72\x1c\x3c\x0c\x95\x95\x68\x09\x53\x2f\xcf\x0e\x24\x49\xa6\xb5\x25\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57\xba\x63\x7b\x39\x1a\xaf\xd2\x55",
66 .plaintext_size = 64,
67 .ciphertext =
68 "\x42\x83\x1e\xc2\x21\x77\x74\x24\x4b\x72\x21\xb7\x84\xd0\xd4\x9c\xe3\xaa\x21\x2f\x2c\x02\xa4\xe0\x35\xc1\x7e\x23\x29\xac\xa1\x2e\x21\xd5\x14\xb2\x54\x66\x93\x1c\x7d\x8f\x6a\x5a\xac\x84\xaa\x05\x1b\xa3\x0b\x39\x6a\x0a\xac\x97\x3d\x58\xe0\x91\x47\x3f\x59\x85",
69 .iv = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad\xde\xca\xf8\x88",
70 .tag = "\x4d\x5c\x2a\xf3\x27\xcd\x64\xa6\x2c\xf3\x5a\xbd\x2b\xa6\xfa\xb4"
73 .key =
74 "\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08",
75 .auth =
76 "\xfe\xed\xfa\xce\xde\xad\xbe\xef\xfe\xed\xfa\xce\xde\xad\xbe\xef\xab\xad\xda\xd2",
77 .auth_size = 20,
78 .plaintext =
79 "\xd9\x31\x32\x25\xf8\x84\x06\xe5\xa5\x59\x09\xc5\xaf\xf5\x26\x9a\x86\xa7\xa9\x53\x15\x34\xf7\xda\x2e\x4c\x30\x3d\x8a\x31\x8a\x72\x1c\x3c\x0c\x95\x95\x68\x09\x53\x2f\xcf\x0e\x24\x49\xa6\xb5\x25\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57\xba\x63\x7b\x39",
80 .plaintext_size = 60,
81 .ciphertext =
82 "\x42\x83\x1e\xc2\x21\x77\x74\x24\x4b\x72\x21\xb7\x84\xd0\xd4\x9c\xe3\xaa\x21\x2f\x2c\x02\xa4\xe0\x35\xc1\x7e\x23\x29\xac\xa1\x2e\x21\xd5\x14\xb2\x54\x66\x93\x1c\x7d\x8f\x6a\x5a\xac\x84\xaa\x05\x1b\xa3\x0b\x39\x6a\x0a\xac\x97\x3d\x58\xe0\x91",
83 .iv = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad\xde\xca\xf8\x88",
84 .tag =
85 "\x5b\xc9\x4f\xbc\x32\x21\xa5\xdb\x94\xfa\xe9\x5a\xe7\x12\x1a\x47"
90 /* Test against AES-GCM test vectors.
92 static int test_crypto(int cfd)
94 char iv[BLOCK_SIZE];
95 unsigned char tag[16];
96 int pad, i;
97 int8_t tmp[128];
99 struct session_op sess;
100 struct crypt_auth_op cao;
101 #ifdef CIOCGSESSINFO
102 struct session_info_op siop;
103 #endif
105 /* Get crypto session for AES128 */
107 fprintf(stdout, "Tests on AES-GCM vectors: ");
108 fflush(stdout);
109 for (i = 0;
110 i < sizeof(aes_gcm_vectors) / sizeof(aes_gcm_vectors[0]);
111 i++) {
112 memset(&sess, 0, sizeof(sess));
113 memset(tmp, 0, sizeof(tmp));
115 sess.cipher = CRYPTO_AES_GCM;
116 sess.keylen = 16;
117 sess.key = (void *) aes_gcm_vectors[i].key;
119 if (ioctl(cfd, CIOCGSESSION, &sess)) {
120 my_perror("ioctl(CIOCGSESSION)");
121 return 1;
124 memset(&cao, 0, sizeof(cao));
126 cao.ses = sess.ses;
127 cao.dst = tmp;
128 cao.iv = (void *) aes_gcm_vectors[i].iv;
129 cao.iv_len = 12;
130 cao.op = COP_ENCRYPT;
131 cao.flags = 0;
133 if (aes_gcm_vectors[i].auth_size > 0) {
134 cao.auth_src = (void *) aes_gcm_vectors[i].auth;
135 cao.auth_len = aes_gcm_vectors[i].auth_size;
138 if (aes_gcm_vectors[i].plaintext_size > 0) {
139 cao.src = (void *) aes_gcm_vectors[i].plaintext;
140 cao.len = aes_gcm_vectors[i].plaintext_size;
143 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
144 my_perror("ioctl(CIOCAUTHCRYPT)");
145 return 1;
148 if (aes_gcm_vectors[i].plaintext_size > 0)
149 if (memcmp
150 (tmp, aes_gcm_vectors[i].ciphertext,
151 aes_gcm_vectors[i].plaintext_size) != 0) {
152 fprintf(stderr,
153 "AES-GCM test vector %d failed!\n",
156 print_buf("Cipher: ", tmp, aes_gcm_vectors[i].plaintext_size);
157 print_buf("Expected: ", aes_gcm_vectors[i].ciphertext, aes_gcm_vectors[i].plaintext_size);
158 return 1;
161 if (memcmp
162 (&tmp[cao.len - cao.tag_len], aes_gcm_vectors[i].tag,
163 16) != 0) {
164 fprintf(stderr,
165 "AES-GCM test vector %d failed (tag)!\n",
168 print_buf("Tag: ", tmp, cao.tag_len);
169 print_buf("Expected tag: ",
170 aes_gcm_vectors[i].tag, 16);
171 return 1;
175 fprintf(stdout, "ok\n");
176 fprintf(stdout, "\n");
178 /* Finish crypto session */
179 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
180 my_perror("ioctl(CIOCFSESSION)");
181 return 1;
184 return 0;
187 /* Checks if encryption and subsequent decryption
188 * produces the same data.
190 static int test_encrypt_decrypt(int cfd)
192 char plaintext_raw[DATA_SIZE + 63], *plaintext;
193 char ciphertext_raw[DATA_SIZE + 63], *ciphertext;
194 char iv[BLOCK_SIZE];
195 char key[KEY_SIZE];
196 char auth[AUTH_SIZE];
197 unsigned char sha1mac[20];
198 int pad, i, enc_len;
200 struct session_op sess;
201 struct crypt_auth_op cao;
202 #ifdef CIOCGSESSINFO
203 struct session_info_op siop;
204 #endif
206 fprintf(stdout, "Tests on AES-GCM encryption/decryption: ");
207 fflush(stdout);
209 memset(&sess, 0, sizeof(sess));
210 memset(&cao, 0, sizeof(cao));
212 memset(key, 0x33, sizeof(key));
213 memset(iv, 0x03, sizeof(iv));
214 memset(auth, 0xf1, sizeof(auth));
216 /* Get crypto session for AES128 */
217 sess.cipher = CRYPTO_AES_GCM;
218 sess.keylen = KEY_SIZE;
219 sess.key = key;
221 if (ioctl(cfd, CIOCGSESSION, &sess)) {
222 my_perror("ioctl(CIOCGSESSION)");
223 return 1;
226 #ifdef CIOCGSESSINFO
227 siop.ses = sess.ses;
228 if (ioctl(cfd, CIOCGSESSINFO, &siop)) {
229 my_perror("ioctl(CIOCGSESSINFO)");
230 return 1;
232 // printf("requested cipher CRYPTO_AES_CBC/HMAC-SHA1, got %s with driver %s\n",
233 // siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name);
235 plaintext =
236 (char *) (((unsigned long) plaintext_raw + siop.alignmask) &
237 ~siop.alignmask);
238 ciphertext =
239 (char *) (((unsigned long) ciphertext_raw + siop.alignmask) &
240 ~siop.alignmask);
241 #else
242 plaintext = plaintext_raw;
243 ciphertext = ciphertext_raw;
244 #endif
245 memset(plaintext, 0x15, DATA_SIZE);
247 /* Encrypt data.in to data.encrypted */
248 cao.ses = sess.ses;
249 cao.auth_src = auth;
250 cao.auth_len = sizeof(auth);
251 cao.len = DATA_SIZE;
252 cao.src = plaintext;
253 cao.dst = ciphertext;
254 cao.iv = iv;
255 cao.iv_len = 12;
256 cao.op = COP_ENCRYPT;
257 cao.flags = 0;
259 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
260 my_perror("ioctl(CIOCAUTHCRYPT)");
261 return 1;
264 enc_len = cao.len;
265 //printf("Original plaintext size: %d, ciphertext: %d\n", DATA_SIZE, enc_len);
267 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
268 my_perror("ioctl(CIOCFSESSION)");
269 return 1;
272 /* Get crypto session for AES128 */
273 memset(&sess, 0, sizeof(sess));
274 sess.cipher = CRYPTO_AES_GCM;
275 sess.keylen = KEY_SIZE;
276 sess.key = key;
278 if (ioctl(cfd, CIOCGSESSION, &sess)) {
279 my_perror("ioctl(CIOCGSESSION)");
280 return 1;
283 /* Decrypt data.encrypted to data.decrypted */
284 cao.ses = sess.ses;
285 cao.auth_src = auth;
286 cao.auth_len = sizeof(auth);
287 cao.len = enc_len;
288 cao.src = ciphertext;
289 cao.dst = ciphertext;
290 cao.iv = iv;
291 cao.iv_len = 12;
292 cao.op = COP_DECRYPT;
293 cao.flags = 0;
295 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
296 my_perror("ioctl(CIOCAUTHCRYPT)");
297 return 1;
300 if (cao.len != DATA_SIZE) {
301 fprintf(stderr, "decrypted data size incorrect!\n");
302 return 1;
305 /* Verify the result */
306 if (memcmp(plaintext, ciphertext, DATA_SIZE) != 0) {
307 int i;
308 fprintf(stderr,
309 "FAIL: Decrypted data are different from the input data.\n");
310 printf("plaintext:");
311 for (i = 0; i < DATA_SIZE; i++) {
312 if ((i % 30) == 0)
313 printf("\n");
314 printf("%02x ", plaintext[i]);
316 printf("ciphertext:");
317 for (i = 0; i < DATA_SIZE; i++) {
318 if ((i % 30) == 0)
319 printf("\n");
320 printf("%02x ", ciphertext[i]);
322 printf("\n");
323 return 1;
326 /* Finish crypto session */
327 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
328 my_perror("ioctl(CIOCFSESSION)");
329 return 1;
332 fprintf(stdout, "ok\n");
333 fprintf(stdout, "\n");
335 return 0;
338 static int test_encrypt_decrypt_error(int cfd, int err)
340 char plaintext_raw[DATA_SIZE + 63], *plaintext;
341 char ciphertext_raw[DATA_SIZE + 63], *ciphertext;
342 char iv[BLOCK_SIZE];
343 char key[KEY_SIZE];
344 char auth[AUTH_SIZE];
345 int pad, i, enc_len;
347 struct session_op sess;
348 struct crypt_op co;
349 struct crypt_auth_op cao;
350 #ifdef CIOCGSESSINFO
351 struct session_info_op siop;
352 #endif
354 fprintf(stdout, "Tests on AES-GCM tag verification: ");
355 fflush(stdout);
357 memset(&sess, 0, sizeof(sess));
358 memset(&cao, 0, sizeof(cao));
359 memset(&co, 0, sizeof(co));
361 memset(key, 0x33, sizeof(key));
362 memset(iv, 0x03, sizeof(iv));
363 memset(auth, 0xf1, sizeof(auth));
365 /* Get crypto session for AES128 */
366 sess.cipher = CRYPTO_AES_CBC;
367 sess.keylen = KEY_SIZE;
368 sess.key = key;
370 sess.mac = CRYPTO_SHA1_HMAC;
371 sess.mackeylen = 16;
372 sess.mackey =
373 (uint8_t *)
374 "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
376 if (ioctl(cfd, CIOCGSESSION, &sess)) {
377 my_perror("ioctl(CIOCGSESSION)");
378 return 1;
380 #ifdef CIOCGSESSINFO
381 siop.ses = sess.ses;
382 if (ioctl(cfd, CIOCGSESSINFO, &siop)) {
383 my_perror("ioctl(CIOCGSESSINFO)");
384 return 1;
386 // printf("requested cipher CRYPTO_AES_CBC/HMAC-SHA1, got %s with driver %s\n",
387 // siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name);
389 plaintext =
390 (char *) (((unsigned long) plaintext_raw + siop.alignmask) &
391 ~siop.alignmask);
392 ciphertext =
393 (char *) (((unsigned long) ciphertext_raw + siop.alignmask) &
394 ~siop.alignmask);
395 #else
396 plaintext = plaintext_raw;
397 ciphertext = ciphertext_raw;
398 #endif
399 memset(plaintext, 0x15, DATA_SIZE);
401 /* Encrypt data.in to data.encrypted */
402 cao.ses = sess.ses;
403 cao.auth_src = auth;
404 cao.auth_len = sizeof(auth);
405 cao.len = DATA_SIZE;
406 cao.src = plaintext;
407 cao.dst = ciphertext;
408 cao.iv = iv;
409 cao.op = COP_ENCRYPT;
410 cao.flags = COP_FLAG_AEAD_TLS_TYPE;
412 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
413 my_perror("ioctl(CIOCAUTHCRYPT)");
414 return 1;
417 enc_len = cao.len;
418 //printf("Original plaintext size: %d, ciphertext: %d\n", DATA_SIZE, enc_len);
420 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
421 my_perror("ioctl(CIOCFSESSION)");
422 return 1;
425 /* Get crypto session for AES128 */
426 memset(&sess, 0, sizeof(sess));
427 sess.cipher = CRYPTO_AES_CBC;
428 sess.keylen = KEY_SIZE;
429 sess.key = key;
430 sess.mac = CRYPTO_SHA1_HMAC;
431 sess.mackeylen = 16;
432 sess.mackey =
433 (uint8_t *)
434 "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
436 if (ioctl(cfd, CIOCGSESSION, &sess)) {
437 my_perror("ioctl(CIOCGSESSION)");
438 return 1;
441 if (err == 0)
442 auth[2]++;
443 else
444 ciphertext[4]++;
446 /* Decrypt data.encrypted to data.decrypted */
447 cao.ses = sess.ses;
448 cao.auth_src = auth;
449 cao.auth_len = sizeof(auth);
450 cao.len = enc_len;
451 cao.src = ciphertext;
452 cao.dst = ciphertext;
453 cao.iv = iv;
454 cao.op = COP_DECRYPT;
455 cao.flags = COP_FLAG_AEAD_TLS_TYPE;
456 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
457 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
458 my_perror("ioctl(CIOCFSESSION)");
459 return 1;
462 fprintf(stdout, "ok\n");
463 fprintf(stdout, "\n");
464 return 0;
467 /* Finish crypto session */
468 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
469 my_perror("ioctl(CIOCFSESSION)");
470 return 1;
474 fprintf(stderr, "Modification to ciphertext was not detected\n");
475 return 1;
478 int main()
480 int fd = -1, cfd = -1;
482 /* Open the crypto device */
483 fd = open("/dev/crypto", O_RDWR, 0);
484 if (fd < 0) {
485 my_perror("open(/dev/crypto)");
486 return 1;
489 /* Clone file descriptor */
490 if (ioctl(fd, CRIOGET, &cfd)) {
491 my_perror("ioctl(CRIOGET)");
492 return 1;
495 /* Set close-on-exec (not really neede here) */
496 if (fcntl(cfd, F_SETFD, 1) == -1) {
497 my_perror("fcntl(F_SETFD)");
498 return 1;
501 /* Run the test itself */
503 if (test_crypto(cfd))
504 return 1;
506 if (test_encrypt_decrypt(cfd))
507 return 1;
509 if (test_encrypt_decrypt_error(cfd, 0))
510 return 1;
512 if (test_encrypt_decrypt_error(cfd, 1))
513 return 1;
515 /* Close cloned descriptor */
516 if (close(cfd)) {
517 my_perror("close(cfd)");
518 return 1;
521 /* Close the original descriptor */
522 if (close(fd)) {
523 my_perror("close(fd)");
524 return 1;
527 return 0;