Added real usage examples, and moved test code to tests/
[cryptodev-linux.git] / tests / cipher-aead.c
blobab29aeca810941dd198f289bfba874102a9142bd
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 MAC_SIZE 20 /* SHA1 */
23 static int
24 get_sha1_hmac(int cfd, void* key, int key_size, void* data1, int data1_size, void* data2, int data2_size, void* mac)
26 struct session_op sess;
27 struct crypt_op cryp;
28 int i;
30 memset(&sess, 0, sizeof(sess));
31 memset(&cryp, 0, sizeof(cryp));
33 sess.cipher = 0;
34 sess.mac = CRYPTO_SHA1_HMAC;
35 sess.mackeylen = key_size;
36 sess.mackey = key;
37 if (ioctl(cfd, CIOCGSESSION, &sess)) {
38 perror("ioctl(CIOCGSESSION)");
39 return 1;
42 /* Encrypt data.in to data.encrypted */
43 cryp.ses = sess.ses;
44 cryp.len = data1_size;
45 cryp.src = data1;
46 cryp.dst = NULL;
47 cryp.iv = NULL;
48 cryp.mac = mac;
49 cryp.op = COP_ENCRYPT;
50 cryp.flags = COP_FLAG_UPDATE;
51 if (ioctl(cfd, CIOCCRYPT, &cryp)) {
52 perror("ioctl(CIOCCRYPT)");
53 return 1;
56 cryp.ses = sess.ses;
57 cryp.len = data2_size;
58 cryp.src = data2;
59 cryp.dst = NULL;
60 cryp.iv = NULL;
61 cryp.mac = mac;
62 cryp.op = COP_ENCRYPT;
63 cryp.flags = COP_FLAG_FINAL;
64 if (ioctl(cfd, CIOCCRYPT, &cryp)) {
65 perror("ioctl(CIOCCRYPT)");
66 return 1;
69 /* Finish crypto session */
70 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
71 perror("ioctl(CIOCFSESSION)");
72 return 1;
75 return 0;
78 static void print_buf(char* desc, unsigned char* buf, int size)
80 int i;
81 fputs(desc, stdout);
82 for (i=0;i<size;i++) {
83 printf("%.2x", (uint8_t)buf[i]);
85 fputs("\n", stdout);
88 static int
89 test_crypto(int cfd)
91 char plaintext_raw[DATA_SIZE + 63], *plaintext;
92 char ciphertext_raw[DATA_SIZE + 63], *ciphertext;
93 char iv[BLOCK_SIZE];
94 char key[KEY_SIZE];
95 char auth[AUTH_SIZE];
96 unsigned char sha1mac[20];
97 int pad, i;
99 struct session_op sess;
100 struct crypt_op co;
101 struct crypt_auth_op cao;
102 #ifdef CIOCGSESSINFO
103 struct session_info_op siop;
104 #endif
106 memset(&sess, 0, sizeof(sess));
107 memset(&cao, 0, sizeof(cao));
108 memset(&co, 0, sizeof(co));
110 memset(key,0x33, sizeof(key));
111 memset(iv, 0x03, sizeof(iv));
112 memset(auth, 0xf1, sizeof(auth));
114 /* Get crypto session for AES128 */
115 sess.cipher = CRYPTO_AES_CBC;
116 sess.keylen = KEY_SIZE;
117 sess.key = key;
119 sess.mac = CRYPTO_SHA1_HMAC;
120 sess.mackeylen = 16;
121 sess.mackey = (uint8_t*)"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
123 if (ioctl(cfd, CIOCGSESSION, &sess)) {
124 perror("ioctl(CIOCGSESSION)");
125 return 1;
128 #ifdef CIOCGSESSINFO
129 siop.ses = sess.ses;
130 if (ioctl(cfd, CIOCGSESSINFO, &siop)) {
131 perror("ioctl(CIOCGSESSINFO)");
132 return 1;
134 printf("requested cipher CRYPTO_AES_CBC/HMAC-SHA1, got %s with driver %s\n",
135 siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name);
137 plaintext = (char *)(((unsigned long)plaintext_raw + siop.alignmask) & ~siop.alignmask);
138 ciphertext = (char *)(((unsigned long)ciphertext_raw + siop.alignmask) & ~siop.alignmask);
139 #else
140 plaintext = plaintext_raw;
141 ciphertext = ciphertext_raw;
142 #endif
143 memset(plaintext, 0x15, DATA_SIZE);
145 if (get_sha1_hmac(cfd, sess.mackey, sess.mackeylen, auth, sizeof(auth), plaintext, DATA_SIZE, sha1mac) != 0) {
146 fprintf(stderr, "SHA1 MAC failed\n");
147 return 1;
150 //memcpy(ciphertext, plaintext, DATA_SIZE);
152 /* Encrypt data.in to data.encrypted */
153 cao.ses = sess.ses;
154 cao.auth_src = auth;
155 cao.auth_len = sizeof(auth);
156 cao.len = DATA_SIZE;
157 cao.src = plaintext;
158 cao.dst = ciphertext;
159 cao.iv = iv;
160 cao.op = COP_ENCRYPT;
161 cao.flags = COP_FLAG_AEAD_TLS_TYPE;
163 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
164 perror("ioctl(CIOCAUTHCRYPT)");
165 return 1;
168 //printf("Original plaintext size: %d, ciphertext: %d\n", DATA_SIZE, cao.len);
170 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
171 perror("ioctl(CIOCFSESSION)");
172 return 1;
175 /* Get crypto session for AES128 */
176 memset(&sess, 0, sizeof(sess));
177 sess.cipher = CRYPTO_AES_CBC;
178 sess.keylen = KEY_SIZE;
179 sess.key = key;
181 if (ioctl(cfd, CIOCGSESSION, &sess)) {
182 perror("ioctl(CIOCGSESSION)");
183 return 1;
186 /* Decrypt data.encrypted to data.decrypted */
187 co.ses = sess.ses;
188 co.len = cao.len;
189 co.src = ciphertext;
190 co.dst = ciphertext;
191 co.iv = iv;
192 co.op = COP_DECRYPT;
193 if (ioctl(cfd, CIOCCRYPT, &co)) {
194 perror("ioctl(CIOCCRYPT)");
195 return 1;
198 /* Verify the result */
199 if (memcmp(plaintext, ciphertext, DATA_SIZE) != 0) {
200 int i;
201 fprintf(stderr,
202 "FAIL: Decrypted data are different from the input data.\n");
203 printf("plaintext:");
204 for (i = 0; i < DATA_SIZE; i++) {
205 if ((i % 30) == 0)
206 printf("\n");
207 printf("%02x ", plaintext[i]);
209 printf("ciphertext:");
210 for (i = 0; i < DATA_SIZE; i++) {
211 if ((i % 30) == 0)
212 printf("\n");
213 printf("%02x ", ciphertext[i]);
215 printf("\n");
216 return 1;
219 pad = ciphertext[cao.len-1];
220 if (memcmp(&ciphertext[cao.len-MAC_SIZE-pad-1], sha1mac, 20) != 0) {
221 fprintf(stderr, "AEAD SHA1 MAC does not match plain MAC\n");
222 print_buf("SHA1: ", sha1mac, 20);
223 print_buf("SHA1-TLS: ", &ciphertext[cao.len-MAC_SIZE-pad-1], 20);
224 return 1;
228 for (i=0;i<pad;i++)
229 if (ciphertext[cao.len-1-i] != pad) {
230 fprintf(stderr, "Pad does not match (expected %d)\n", pad);
231 print_buf("PAD: ", &ciphertext[cao.len-1-pad], pad);
232 return 1;
235 printf("Test passed\n");
238 /* Finish crypto session */
239 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
240 perror("ioctl(CIOCFSESSION)");
241 return 1;
244 return 0;
247 static int
248 test_encrypt_decrypt(int cfd)
250 char plaintext_raw[DATA_SIZE + 63], *plaintext;
251 char ciphertext_raw[DATA_SIZE + 63], *ciphertext;
252 char iv[BLOCK_SIZE];
253 char key[KEY_SIZE];
254 char auth[AUTH_SIZE];
255 unsigned char sha1mac[20];
256 int pad, i, enc_len;
258 struct session_op sess;
259 struct crypt_op co;
260 struct crypt_auth_op cao;
261 #ifdef CIOCGSESSINFO
262 struct session_info_op siop;
263 #endif
265 memset(&sess, 0, sizeof(sess));
266 memset(&cao, 0, sizeof(cao));
267 memset(&co, 0, sizeof(co));
269 memset(key,0x33, sizeof(key));
270 memset(iv, 0x03, sizeof(iv));
271 memset(auth, 0xf1, sizeof(auth));
273 /* Get crypto session for AES128 */
274 sess.cipher = CRYPTO_AES_CBC;
275 sess.keylen = KEY_SIZE;
276 sess.key = key;
278 sess.mac = CRYPTO_SHA1_HMAC;
279 sess.mackeylen = 16;
280 sess.mackey = (uint8_t*)"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
282 if (ioctl(cfd, CIOCGSESSION, &sess)) {
283 perror("ioctl(CIOCGSESSION)");
284 return 1;
287 #ifdef CIOCGSESSINFO
288 siop.ses = sess.ses;
289 if (ioctl(cfd, CIOCGSESSINFO, &siop)) {
290 perror("ioctl(CIOCGSESSINFO)");
291 return 1;
293 // printf("requested cipher CRYPTO_AES_CBC/HMAC-SHA1, got %s with driver %s\n",
294 // siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name);
296 plaintext = (char *)(((unsigned long)plaintext_raw + siop.alignmask) & ~siop.alignmask);
297 ciphertext = (char *)(((unsigned long)ciphertext_raw + siop.alignmask) & ~siop.alignmask);
298 #else
299 plaintext = plaintext_raw;
300 ciphertext = ciphertext_raw;
301 #endif
302 memset(plaintext, 0x15, DATA_SIZE);
304 if (get_sha1_hmac(cfd, sess.mackey, sess.mackeylen, auth, sizeof(auth), plaintext, DATA_SIZE, sha1mac) != 0) {
305 fprintf(stderr, "SHA1 MAC failed\n");
306 return 1;
309 /* Encrypt data.in to data.encrypted */
310 cao.ses = sess.ses;
311 cao.auth_src = auth;
312 cao.auth_len = sizeof(auth);
313 cao.len = DATA_SIZE;
314 cao.src = plaintext;
315 cao.dst = ciphertext;
316 cao.iv = iv;
317 cao.op = COP_ENCRYPT;
318 cao.flags = COP_FLAG_AEAD_TLS_TYPE;
320 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
321 perror("ioctl(CIOCAUTHCRYPT)");
322 return 1;
325 enc_len = cao.len;
326 //printf("Original plaintext size: %d, ciphertext: %d\n", DATA_SIZE, enc_len);
328 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
329 perror("ioctl(CIOCFSESSION)");
330 return 1;
333 /* Get crypto session for AES128 */
334 memset(&sess, 0, sizeof(sess));
335 sess.cipher = CRYPTO_AES_CBC;
336 sess.keylen = KEY_SIZE;
337 sess.key = key;
338 sess.mac = CRYPTO_SHA1_HMAC;
339 sess.mackeylen = 16;
340 sess.mackey = (uint8_t*)"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
342 if (ioctl(cfd, CIOCGSESSION, &sess)) {
343 perror("ioctl(CIOCGSESSION)");
344 return 1;
347 /* Decrypt data.encrypted to data.decrypted */
348 cao.ses = sess.ses;
349 cao.auth_src = auth;
350 cao.auth_len = sizeof(auth);
351 cao.len = enc_len;
352 cao.src = ciphertext;
353 cao.dst = ciphertext;
354 cao.iv = iv;
355 cao.op = COP_DECRYPT;
356 cao.flags = COP_FLAG_AEAD_TLS_TYPE;
357 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
358 perror("ioctl(CIOCAUTHCRYPT)");
359 return 1;
362 if (cao.len != DATA_SIZE) {
363 fprintf(stderr, "decrypted data size incorrect!\n");
364 return 1;
367 /* Verify the result */
368 if (memcmp(plaintext, ciphertext, DATA_SIZE) != 0) {
369 int i;
370 fprintf(stderr,
371 "FAIL: Decrypted data are different from the input data.\n");
372 printf("plaintext:");
373 for (i = 0; i < DATA_SIZE; i++) {
374 if ((i % 30) == 0)
375 printf("\n");
376 printf("%02x ", plaintext[i]);
378 printf("ciphertext:");
379 for (i = 0; i < DATA_SIZE; i++) {
380 if ((i % 30) == 0)
381 printf("\n");
382 printf("%02x ", ciphertext[i]);
384 printf("\n");
385 return 1;
388 printf("Test passed\n");
391 /* Finish crypto session */
392 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
393 perror("ioctl(CIOCFSESSION)");
394 return 1;
397 return 0;
400 static int
401 test_encrypt_decrypt_error(int cfd, int err)
403 char plaintext_raw[DATA_SIZE + 63], *plaintext;
404 char ciphertext_raw[DATA_SIZE + 63], *ciphertext;
405 char iv[BLOCK_SIZE];
406 char key[KEY_SIZE];
407 char auth[AUTH_SIZE];
408 unsigned char sha1mac[20];
409 int pad, i, enc_len;
411 struct session_op sess;
412 struct crypt_op co;
413 struct crypt_auth_op cao;
414 #ifdef CIOCGSESSINFO
415 struct session_info_op siop;
416 #endif
418 memset(&sess, 0, sizeof(sess));
419 memset(&cao, 0, sizeof(cao));
420 memset(&co, 0, sizeof(co));
422 memset(key,0x33, sizeof(key));
423 memset(iv, 0x03, sizeof(iv));
424 memset(auth, 0xf1, sizeof(auth));
426 /* Get crypto session for AES128 */
427 sess.cipher = CRYPTO_AES_CBC;
428 sess.keylen = KEY_SIZE;
429 sess.key = key;
431 sess.mac = CRYPTO_SHA1_HMAC;
432 sess.mackeylen = 16;
433 sess.mackey = (uint8_t*)"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
435 if (ioctl(cfd, CIOCGSESSION, &sess)) {
436 perror("ioctl(CIOCGSESSION)");
437 return 1;
440 #ifdef CIOCGSESSINFO
441 siop.ses = sess.ses;
442 if (ioctl(cfd, CIOCGSESSINFO, &siop)) {
443 perror("ioctl(CIOCGSESSINFO)");
444 return 1;
446 // printf("requested cipher CRYPTO_AES_CBC/HMAC-SHA1, got %s with driver %s\n",
447 // siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name);
449 plaintext = (char *)(((unsigned long)plaintext_raw + siop.alignmask) & ~siop.alignmask);
450 ciphertext = (char *)(((unsigned long)ciphertext_raw + siop.alignmask) & ~siop.alignmask);
451 #else
452 plaintext = plaintext_raw;
453 ciphertext = ciphertext_raw;
454 #endif
455 memset(plaintext, 0x15, DATA_SIZE);
457 if (get_sha1_hmac(cfd, sess.mackey, sess.mackeylen, auth, sizeof(auth), plaintext, DATA_SIZE, sha1mac) != 0) {
458 fprintf(stderr, "SHA1 MAC failed\n");
459 return 1;
462 /* Encrypt data.in to data.encrypted */
463 cao.ses = sess.ses;
464 cao.auth_src = auth;
465 cao.auth_len = sizeof(auth);
466 cao.len = DATA_SIZE;
467 cao.src = plaintext;
468 cao.dst = ciphertext;
469 cao.iv = iv;
470 cao.op = COP_ENCRYPT;
471 cao.flags = COP_FLAG_AEAD_TLS_TYPE;
473 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
474 perror("ioctl(CIOCAUTHCRYPT)");
475 return 1;
478 enc_len = cao.len;
479 //printf("Original plaintext size: %d, ciphertext: %d\n", DATA_SIZE, enc_len);
481 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
482 perror("ioctl(CIOCFSESSION)");
483 return 1;
486 /* Get crypto session for AES128 */
487 memset(&sess, 0, sizeof(sess));
488 sess.cipher = CRYPTO_AES_CBC;
489 sess.keylen = KEY_SIZE;
490 sess.key = key;
491 sess.mac = CRYPTO_SHA1_HMAC;
492 sess.mackeylen = 16;
493 sess.mackey = (uint8_t*)"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
495 if (ioctl(cfd, CIOCGSESSION, &sess)) {
496 perror("ioctl(CIOCGSESSION)");
497 return 1;
500 if (err == 0)
501 auth[2]++;
502 else
503 ciphertext[4]++;
505 /* Decrypt data.encrypted to data.decrypted */
506 cao.ses = sess.ses;
507 cao.auth_src = auth;
508 cao.auth_len = sizeof(auth);
509 cao.len = enc_len;
510 cao.src = ciphertext;
511 cao.dst = ciphertext;
512 cao.iv = iv;
513 cao.op = COP_DECRYPT;
514 cao.flags = COP_FLAG_AEAD_TLS_TYPE;
515 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
516 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
517 perror("ioctl(CIOCFSESSION)");
518 return 1;
521 printf("Test passed\n");
522 return 0;
525 /* Finish crypto session */
526 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
527 perror("ioctl(CIOCFSESSION)");
528 return 1;
532 fprintf(stderr, "Modification to ciphertext was not detected\n");
533 return 1;
537 main()
539 int fd = -1, cfd = -1;
541 /* Open the crypto device */
542 fd = open("/dev/crypto", O_RDWR, 0);
543 if (fd < 0) {
544 perror("open(/dev/crypto)");
545 return 1;
548 /* Clone file descriptor */
549 if (ioctl(fd, CRIOGET, &cfd)) {
550 perror("ioctl(CRIOGET)");
551 return 1;
554 /* Set close-on-exec (not really neede here) */
555 if (fcntl(cfd, F_SETFD, 1) == -1) {
556 perror("fcntl(F_SETFD)");
557 return 1;
560 /* Run the test itself */
562 if (test_crypto(cfd))
563 return 1;
565 if (test_encrypt_decrypt(cfd))
566 return 1;
568 if (test_encrypt_decrypt_error(cfd, 0))
569 return 1;
571 if (test_encrypt_decrypt_error(cfd, 1))
572 return 1;
574 /* Close cloned descriptor */
575 if (close(cfd)) {
576 perror("close(cfd)");
577 return 1;
580 /* Close the original descriptor */
581 if (close(fd)) {
582 perror("close(fd)");
583 return 1;
586 return 0;