set null auth on decr too.
[cryptodev-linux.git] / tests / cipher-aead.c
blob164327f6942c472209b6d747ab483fad9eb8a724
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 debug = 0;
25 static int
26 get_sha1_hmac(int cfd, void* key, int key_size, void* data1, int data1_size, void* data2, int data2_size, void* mac)
28 struct session_op sess;
29 struct crypt_op cryp;
31 memset(&sess, 0, sizeof(sess));
32 memset(&cryp, 0, sizeof(cryp));
34 sess.cipher = 0;
35 sess.mac = CRYPTO_SHA1_HMAC;
36 sess.mackeylen = key_size;
37 sess.mackey = key;
38 if (ioctl(cfd, CIOCGSESSION, &sess)) {
39 perror("ioctl(CIOCGSESSION)");
40 return 1;
43 /* Encrypt data.in to data.encrypted */
44 cryp.ses = sess.ses;
45 cryp.len = data1_size;
46 cryp.src = data1;
47 cryp.dst = NULL;
48 cryp.iv = NULL;
49 cryp.mac = mac;
50 cryp.op = COP_ENCRYPT;
51 cryp.flags = COP_FLAG_UPDATE;
52 if (ioctl(cfd, CIOCCRYPT, &cryp)) {
53 perror("ioctl(CIOCCRYPT)");
54 return 1;
57 cryp.ses = sess.ses;
58 cryp.len = data2_size;
59 cryp.src = data2;
60 cryp.dst = NULL;
61 cryp.iv = NULL;
62 cryp.mac = mac;
63 cryp.op = COP_ENCRYPT;
64 cryp.flags = COP_FLAG_FINAL;
65 if (ioctl(cfd, CIOCCRYPT, &cryp)) {
66 perror("ioctl(CIOCCRYPT)");
67 return 1;
70 /* Finish crypto session */
71 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
72 perror("ioctl(CIOCFSESSION)");
73 return 1;
76 return 0;
79 static void print_buf(char* desc, unsigned char* buf, int size)
81 int i;
82 fputs(desc, stdout);
83 for (i=0;i<size;i++) {
84 printf("%.2x", (uint8_t)buf[i]);
86 fputs("\n", stdout);
89 static int
90 test_crypto(int cfd)
92 char plaintext_raw[DATA_SIZE + 63], *plaintext;
93 char ciphertext_raw[DATA_SIZE + 63], *ciphertext;
94 char iv[BLOCK_SIZE];
95 char key[KEY_SIZE];
96 char auth[AUTH_SIZE];
97 unsigned char sha1mac[20];
98 int pad, i;
100 struct session_op sess;
101 struct crypt_op co;
102 struct crypt_auth_op cao;
103 struct session_info_op siop;
105 memset(&sess, 0, sizeof(sess));
106 memset(&cao, 0, sizeof(cao));
107 memset(&co, 0, sizeof(co));
109 memset(key,0x33, sizeof(key));
110 memset(iv, 0x03, sizeof(iv));
111 memset(auth, 0xf1, sizeof(auth));
113 /* Get crypto session for AES128 */
114 sess.cipher = CRYPTO_AES_CBC;
115 sess.keylen = KEY_SIZE;
116 sess.key = (void*)key;
118 sess.mac = CRYPTO_SHA1_HMAC;
119 sess.mackeylen = 16;
120 sess.mackey = (uint8_t*)"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
122 if (ioctl(cfd, CIOCGSESSION, &sess)) {
123 perror("ioctl(CIOCGSESSION)");
124 return 1;
127 siop.ses = sess.ses;
128 if (ioctl(cfd, CIOCGSESSINFO, &siop)) {
129 perror("ioctl(CIOCGSESSINFO)");
130 return 1;
132 if (debug)
133 printf("requested cipher CRYPTO_AES_CBC/HMAC-SHA1, got %s with driver %s\n",
134 siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name);
136 plaintext = (char *)(((unsigned long)plaintext_raw + siop.alignmask) & ~siop.alignmask);
137 ciphertext = (char *)(((unsigned long)ciphertext_raw + siop.alignmask) & ~siop.alignmask);
138 memset(plaintext, 0x15, DATA_SIZE);
140 if (get_sha1_hmac(cfd, sess.mackey, sess.mackeylen, auth, sizeof(auth), plaintext, DATA_SIZE, sha1mac) != 0) {
141 fprintf(stderr, "SHA1 MAC failed\n");
142 return 1;
145 memcpy(ciphertext, plaintext, DATA_SIZE);
147 /* Encrypt data.in to data.encrypted */
148 cao.ses = sess.ses;
149 cao.auth_src = auth;
150 cao.auth_len = sizeof(auth);
151 cao.len = DATA_SIZE;
152 cao.src = ciphertext;
153 cao.dst = ciphertext;
154 cao.iv = iv;
155 cao.op = COP_ENCRYPT;
156 cao.flags = COP_FLAG_AEAD_TLS_TYPE;
158 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
159 perror("ioctl(CIOCAUTHCRYPT)");
160 return 1;
163 //printf("Original plaintext size: %d, ciphertext: %d\n", DATA_SIZE, cao.len);
165 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
166 perror("ioctl(CIOCFSESSION)");
167 return 1;
170 /* Get crypto session for AES128 */
171 memset(&sess, 0, sizeof(sess));
172 sess.cipher = CRYPTO_AES_CBC;
173 sess.keylen = KEY_SIZE;
174 sess.key = key;
176 if (ioctl(cfd, CIOCGSESSION, &sess)) {
177 perror("ioctl(CIOCGSESSION)");
178 return 1;
181 /* Decrypt data.encrypted to data.decrypted */
182 co.ses = sess.ses;
183 co.len = cao.len;
184 co.src = ciphertext;
185 co.dst = ciphertext;
186 co.iv = iv;
187 co.op = COP_DECRYPT;
188 if (ioctl(cfd, CIOCCRYPT, &co)) {
189 perror("ioctl(CIOCCRYPT)");
190 return 1;
193 /* Verify the result */
194 if (memcmp(plaintext, ciphertext, DATA_SIZE) != 0) {
195 int i;
196 fprintf(stderr,
197 "FAIL: Decrypted data are different from the input data.\n");
198 printf("plaintext:");
199 for (i = 0; i < DATA_SIZE; i++) {
200 if ((i % 30) == 0)
201 printf("\n");
202 printf("%02x ", plaintext[i]);
204 printf("ciphertext:");
205 for (i = 0; i < DATA_SIZE; i++) {
206 if ((i % 30) == 0)
207 printf("\n");
208 printf("%02x ", ciphertext[i]);
210 printf("\n");
211 return 1;
214 pad = ciphertext[cao.len-1];
215 if (memcmp(&ciphertext[cao.len-MAC_SIZE-pad-1], sha1mac, 20) != 0) {
216 fprintf(stderr, "AEAD SHA1 MAC does not match plain MAC\n");
217 print_buf("SHA1: ", sha1mac, 20);
218 print_buf("SHA1-TLS: ", &ciphertext[cao.len-MAC_SIZE-pad-1], 20);
219 return 1;
223 for (i=0;i<pad;i++)
224 if (ciphertext[cao.len-1-i] != pad) {
225 fprintf(stderr, "Pad does not match (expected %d)\n", pad);
226 print_buf("PAD: ", &ciphertext[cao.len-1-pad], pad);
227 return 1;
230 if (debug) printf("Test passed\n");
233 /* Finish crypto session */
234 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
235 perror("ioctl(CIOCFSESSION)");
236 return 1;
239 return 0;
242 static int
243 test_encrypt_decrypt(int cfd)
245 char plaintext_raw[DATA_SIZE + 63], *plaintext;
246 char ciphertext_raw[DATA_SIZE + 63], *ciphertext;
247 char iv[BLOCK_SIZE];
248 char key[KEY_SIZE];
249 char auth[AUTH_SIZE];
250 unsigned char sha1mac[20];
251 int enc_len;
253 struct session_op sess;
254 struct crypt_op co;
255 struct crypt_auth_op cao;
256 struct session_info_op siop;
258 memset(&sess, 0, sizeof(sess));
259 memset(&cao, 0, sizeof(cao));
260 memset(&co, 0, sizeof(co));
262 memset(key,0x33, sizeof(key));
263 memset(iv, 0x03, sizeof(iv));
264 memset(auth, 0xf1, sizeof(auth));
266 /* Get crypto session for AES128 */
267 sess.cipher = CRYPTO_AES_CBC;
268 sess.keylen = KEY_SIZE;
269 sess.key = key;
271 sess.mac = CRYPTO_SHA1_HMAC;
272 sess.mackeylen = 16;
273 sess.mackey = (uint8_t*)"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
275 if (ioctl(cfd, CIOCGSESSION, &sess)) {
276 perror("ioctl(CIOCGSESSION)");
277 return 1;
280 siop.ses = sess.ses;
281 if (ioctl(cfd, CIOCGSESSINFO, &siop)) {
282 perror("ioctl(CIOCGSESSINFO)");
283 return 1;
285 // printf("requested cipher CRYPTO_AES_CBC/HMAC-SHA1, got %s with driver %s\n",
286 // siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name);
288 plaintext = (char *)(((unsigned long)plaintext_raw + siop.alignmask) & ~siop.alignmask);
289 ciphertext = (char *)(((unsigned long)ciphertext_raw + siop.alignmask) & ~siop.alignmask);
291 memset(plaintext, 0x15, DATA_SIZE);
293 if (get_sha1_hmac(cfd, sess.mackey, sess.mackeylen, auth, sizeof(auth), plaintext, DATA_SIZE, sha1mac) != 0) {
294 fprintf(stderr, "SHA1 MAC failed\n");
295 return 1;
298 memcpy(ciphertext, plaintext, DATA_SIZE);
300 /* Encrypt data.in to data.encrypted */
301 cao.ses = sess.ses;
302 cao.auth_src = (void*)auth;
303 cao.auth_len = sizeof(auth);
304 cao.len = DATA_SIZE;
305 cao.src = (void*)ciphertext;
306 cao.dst = (void*)ciphertext;
307 cao.iv = iv;
308 cao.op = COP_ENCRYPT;
309 cao.flags = COP_FLAG_AEAD_TLS_TYPE;
311 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
312 perror("ioctl(CIOCAUTHCRYPT)");
313 return 1;
316 enc_len = cao.len;
317 //printf("Original plaintext size: %d, ciphertext: %d\n", DATA_SIZE, enc_len);
319 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
320 perror("ioctl(CIOCFSESSION)");
321 return 1;
324 /* Get crypto session for AES128 */
325 memset(&sess, 0, sizeof(sess));
326 sess.cipher = CRYPTO_AES_CBC;
327 sess.keylen = KEY_SIZE;
328 sess.key = key;
329 sess.mac = CRYPTO_SHA1_HMAC;
330 sess.mackeylen = 16;
331 sess.mackey = (uint8_t*)"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
333 if (ioctl(cfd, CIOCGSESSION, &sess)) {
334 perror("ioctl(CIOCGSESSION)");
335 return 1;
338 /* Decrypt data.encrypted to data.decrypted */
339 cao.ses = sess.ses;
340 cao.auth_src = auth;
341 cao.auth_len = sizeof(auth);
342 cao.len = enc_len;
343 cao.src = ciphertext;
344 cao.dst = ciphertext;
345 cao.iv = iv;
346 cao.op = COP_DECRYPT;
347 cao.flags = COP_FLAG_AEAD_TLS_TYPE;
348 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
349 perror("ioctl(CIOCAUTHCRYPT)");
350 return 1;
353 if (cao.len != DATA_SIZE) {
354 fprintf(stderr, "decrypted data size incorrect!\n");
355 return 1;
358 /* Verify the result */
359 if (memcmp(plaintext, ciphertext, DATA_SIZE) != 0) {
360 int i;
361 fprintf(stderr,
362 "FAIL: Decrypted data are different from the input data.\n");
363 printf("plaintext:");
364 for (i = 0; i < DATA_SIZE; i++) {
365 if ((i % 30) == 0)
366 printf("\n");
367 printf("%02x ", plaintext[i]);
369 printf("ciphertext:");
370 for (i = 0; i < DATA_SIZE; i++) {
371 if ((i % 30) == 0)
372 printf("\n");
373 printf("%02x ", ciphertext[i]);
375 printf("\n");
376 return 1;
379 if (debug) printf("Test passed\n");
382 /* Finish crypto session */
383 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
384 perror("ioctl(CIOCFSESSION)");
385 return 1;
388 return 0;
391 static int
392 test_encrypt_decrypt_error(int cfd, int err)
394 char plaintext_raw[DATA_SIZE + 63], *plaintext;
395 char ciphertext_raw[DATA_SIZE + 63], *ciphertext;
396 char iv[BLOCK_SIZE];
397 char key[KEY_SIZE];
398 char auth[AUTH_SIZE];
399 unsigned char sha1mac[20];
400 int enc_len;
402 struct session_op sess;
403 struct crypt_op co;
404 struct crypt_auth_op cao;
405 struct session_info_op siop;
407 memset(&sess, 0, sizeof(sess));
408 memset(&cao, 0, sizeof(cao));
409 memset(&co, 0, sizeof(co));
411 memset(key,0x33, sizeof(key));
412 memset(iv, 0x03, sizeof(iv));
413 memset(auth, 0xf1, sizeof(auth));
415 /* Get crypto session for AES128 */
416 sess.cipher = CRYPTO_AES_CBC;
417 sess.keylen = KEY_SIZE;
418 sess.key = key;
420 sess.mac = CRYPTO_SHA1_HMAC;
421 sess.mackeylen = 16;
422 sess.mackey = (uint8_t*)"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
424 if (ioctl(cfd, CIOCGSESSION, &sess)) {
425 perror("ioctl(CIOCGSESSION)");
426 return 1;
429 siop.ses = sess.ses;
430 if (ioctl(cfd, CIOCGSESSINFO, &siop)) {
431 perror("ioctl(CIOCGSESSINFO)");
432 return 1;
434 // printf("requested cipher CRYPTO_AES_CBC/HMAC-SHA1, got %s with driver %s\n",
435 // siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name);
437 plaintext = (char *)(((unsigned long)plaintext_raw + siop.alignmask) & ~siop.alignmask);
438 ciphertext = (char *)(((unsigned long)ciphertext_raw + siop.alignmask) & ~siop.alignmask);
439 memset(plaintext, 0x15, DATA_SIZE);
441 if (get_sha1_hmac(cfd, sess.mackey, sess.mackeylen, auth, sizeof(auth), plaintext, DATA_SIZE, sha1mac) != 0) {
442 fprintf(stderr, "SHA1 MAC failed\n");
443 return 1;
446 memcpy(ciphertext, plaintext, DATA_SIZE);
448 /* Encrypt data.in to data.encrypted */
449 cao.ses = sess.ses;
450 cao.auth_src = auth;
451 cao.auth_len = sizeof(auth);
452 cao.len = DATA_SIZE;
453 cao.src = ciphertext;
454 cao.dst = ciphertext;
455 cao.iv = iv;
456 cao.op = COP_ENCRYPT;
457 cao.flags = COP_FLAG_AEAD_TLS_TYPE;
459 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
460 perror("ioctl(CIOCAUTHCRYPT)");
461 return 1;
464 enc_len = cao.len;
465 //printf("Original plaintext size: %d, ciphertext: %d\n", DATA_SIZE, enc_len);
467 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
468 perror("ioctl(CIOCFSESSION)");
469 return 1;
472 /* Get crypto session for AES128 */
473 memset(&sess, 0, sizeof(sess));
474 sess.cipher = CRYPTO_AES_CBC;
475 sess.keylen = KEY_SIZE;
476 sess.key = key;
477 sess.mac = CRYPTO_SHA1_HMAC;
478 sess.mackeylen = 16;
479 sess.mackey = (uint8_t*)"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
481 if (ioctl(cfd, CIOCGSESSION, &sess)) {
482 perror("ioctl(CIOCGSESSION)");
483 return 1;
486 if (err == 0)
487 auth[2]++;
488 else
489 ciphertext[4]++;
491 /* Decrypt data.encrypted to data.decrypted */
492 cao.ses = sess.ses;
493 cao.auth_src = auth;
494 cao.auth_len = sizeof(auth);
495 cao.len = enc_len;
496 cao.src = ciphertext;
497 cao.dst = ciphertext;
498 cao.iv = iv;
499 cao.op = COP_DECRYPT;
500 cao.flags = COP_FLAG_AEAD_TLS_TYPE;
501 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
502 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
503 perror("ioctl(CIOCFSESSION)");
504 return 1;
507 if (debug) printf("Test passed\n");
508 return 0;
511 /* Finish crypto session */
512 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
513 perror("ioctl(CIOCFSESSION)");
514 return 1;
518 fprintf(stderr, "Modification to ciphertext was not detected\n");
519 return 1;
523 main()
525 int fd = -1, cfd = -1;
527 /* Open the crypto device */
528 fd = open("/dev/crypto", O_RDWR, 0);
529 if (fd < 0) {
530 perror("open(/dev/crypto)");
531 return 1;
534 /* Clone file descriptor */
535 if (ioctl(fd, CRIOGET, &cfd)) {
536 perror("ioctl(CRIOGET)");
537 return 1;
540 /* Set close-on-exec (not really neede here) */
541 if (fcntl(cfd, F_SETFD, 1) == -1) {
542 perror("fcntl(F_SETFD)");
543 return 1;
546 /* Run the test itself */
548 if (test_crypto(cfd))
549 return 1;
551 if (test_encrypt_decrypt(cfd))
552 return 1;
554 if (test_encrypt_decrypt_error(cfd, 0))
555 return 1;
557 if (test_encrypt_decrypt_error(cfd, 1))
558 return 1;
560 /* Close cloned descriptor */
561 if (close(cfd)) {
562 perror("close(cfd)");
563 return 1;
566 /* Close the original descriptor */
567 if (close(fd)) {
568 perror("close(fd)");
569 return 1;
572 return 0;