set by default public permissions for the device
[cryptodev-linux.git] / tests / cipher-aead.c
blobeba5ddcfa6cc27c0701fa77752ca22b48c065b41
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;
29 memset(&sess, 0, sizeof(sess));
30 memset(&cryp, 0, sizeof(cryp));
32 sess.cipher = 0;
33 sess.mac = CRYPTO_SHA1_HMAC;
34 sess.mackeylen = key_size;
35 sess.mackey = key;
36 if (ioctl(cfd, CIOCGSESSION, &sess)) {
37 perror("ioctl(CIOCGSESSION)");
38 return 1;
41 /* Encrypt data.in to data.encrypted */
42 cryp.ses = sess.ses;
43 cryp.len = data1_size;
44 cryp.src = data1;
45 cryp.dst = NULL;
46 cryp.iv = NULL;
47 cryp.mac = mac;
48 cryp.op = COP_ENCRYPT;
49 cryp.flags = COP_FLAG_UPDATE;
50 if (ioctl(cfd, CIOCCRYPT, &cryp)) {
51 perror("ioctl(CIOCCRYPT)");
52 return 1;
55 cryp.ses = sess.ses;
56 cryp.len = data2_size;
57 cryp.src = data2;
58 cryp.dst = NULL;
59 cryp.iv = NULL;
60 cryp.mac = mac;
61 cryp.op = COP_ENCRYPT;
62 cryp.flags = COP_FLAG_FINAL;
63 if (ioctl(cfd, CIOCCRYPT, &cryp)) {
64 perror("ioctl(CIOCCRYPT)");
65 return 1;
68 /* Finish crypto session */
69 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
70 perror("ioctl(CIOCFSESSION)");
71 return 1;
74 return 0;
77 static void print_buf(char* desc, unsigned char* buf, int size)
79 int i;
80 fputs(desc, stdout);
81 for (i=0;i<size;i++) {
82 printf("%.2x", (uint8_t)buf[i]);
84 fputs("\n", stdout);
87 static int
88 test_crypto(int cfd)
90 char plaintext_raw[DATA_SIZE + 63], *plaintext;
91 char ciphertext_raw[DATA_SIZE + 63], *ciphertext;
92 char iv[BLOCK_SIZE];
93 char key[KEY_SIZE];
94 char auth[AUTH_SIZE];
95 unsigned char sha1mac[20];
96 int pad, i;
98 struct session_op sess;
99 struct crypt_op co;
100 struct crypt_auth_op cao;
101 struct session_info_op siop;
103 memset(&sess, 0, sizeof(sess));
104 memset(&cao, 0, sizeof(cao));
105 memset(&co, 0, sizeof(co));
107 memset(key,0x33, sizeof(key));
108 memset(iv, 0x03, sizeof(iv));
109 memset(auth, 0xf1, sizeof(auth));
111 /* Get crypto session for AES128 */
112 sess.cipher = CRYPTO_AES_CBC;
113 sess.keylen = KEY_SIZE;
114 sess.key = (void*)key;
116 sess.mac = CRYPTO_SHA1_HMAC;
117 sess.mackeylen = 16;
118 sess.mackey = (uint8_t*)"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
120 if (ioctl(cfd, CIOCGSESSION, &sess)) {
121 perror("ioctl(CIOCGSESSION)");
122 return 1;
125 siop.ses = sess.ses;
126 if (ioctl(cfd, CIOCGSESSINFO, &siop)) {
127 perror("ioctl(CIOCGSESSINFO)");
128 return 1;
130 printf("requested cipher CRYPTO_AES_CBC/HMAC-SHA1, got %s with driver %s\n",
131 siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name);
133 plaintext = (char *)(((unsigned long)plaintext_raw + siop.alignmask) & ~siop.alignmask);
134 ciphertext = (char *)(((unsigned long)ciphertext_raw + siop.alignmask) & ~siop.alignmask);
135 memset(plaintext, 0x15, DATA_SIZE);
137 if (get_sha1_hmac(cfd, sess.mackey, sess.mackeylen, auth, sizeof(auth), plaintext, DATA_SIZE, sha1mac) != 0) {
138 fprintf(stderr, "SHA1 MAC failed\n");
139 return 1;
142 memcpy(ciphertext, plaintext, DATA_SIZE);
144 /* Encrypt data.in to data.encrypted */
145 cao.ses = sess.ses;
146 cao.auth_src = auth;
147 cao.auth_len = sizeof(auth);
148 cao.len = DATA_SIZE;
149 cao.src = ciphertext;
150 cao.dst = ciphertext;
151 cao.iv = iv;
152 cao.op = COP_ENCRYPT;
153 cao.flags = COP_FLAG_AEAD_TLS_TYPE;
155 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
156 perror("ioctl(CIOCAUTHCRYPT)");
157 return 1;
160 //printf("Original plaintext size: %d, ciphertext: %d\n", DATA_SIZE, cao.len);
162 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
163 perror("ioctl(CIOCFSESSION)");
164 return 1;
167 /* Get crypto session for AES128 */
168 memset(&sess, 0, sizeof(sess));
169 sess.cipher = CRYPTO_AES_CBC;
170 sess.keylen = KEY_SIZE;
171 sess.key = key;
173 if (ioctl(cfd, CIOCGSESSION, &sess)) {
174 perror("ioctl(CIOCGSESSION)");
175 return 1;
178 /* Decrypt data.encrypted to data.decrypted */
179 co.ses = sess.ses;
180 co.len = cao.len;
181 co.src = ciphertext;
182 co.dst = ciphertext;
183 co.iv = iv;
184 co.op = COP_DECRYPT;
185 if (ioctl(cfd, CIOCCRYPT, &co)) {
186 perror("ioctl(CIOCCRYPT)");
187 return 1;
190 /* Verify the result */
191 if (memcmp(plaintext, ciphertext, DATA_SIZE) != 0) {
192 int i;
193 fprintf(stderr,
194 "FAIL: Decrypted data are different from the input data.\n");
195 printf("plaintext:");
196 for (i = 0; i < DATA_SIZE; i++) {
197 if ((i % 30) == 0)
198 printf("\n");
199 printf("%02x ", plaintext[i]);
201 printf("ciphertext:");
202 for (i = 0; i < DATA_SIZE; i++) {
203 if ((i % 30) == 0)
204 printf("\n");
205 printf("%02x ", ciphertext[i]);
207 printf("\n");
208 return 1;
211 pad = ciphertext[cao.len-1];
212 if (memcmp(&ciphertext[cao.len-MAC_SIZE-pad-1], sha1mac, 20) != 0) {
213 fprintf(stderr, "AEAD SHA1 MAC does not match plain MAC\n");
214 print_buf("SHA1: ", sha1mac, 20);
215 print_buf("SHA1-TLS: ", &ciphertext[cao.len-MAC_SIZE-pad-1], 20);
216 return 1;
220 for (i=0;i<pad;i++)
221 if (ciphertext[cao.len-1-i] != pad) {
222 fprintf(stderr, "Pad does not match (expected %d)\n", pad);
223 print_buf("PAD: ", &ciphertext[cao.len-1-pad], pad);
224 return 1;
227 printf("Test passed\n");
230 /* Finish crypto session */
231 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
232 perror("ioctl(CIOCFSESSION)");
233 return 1;
236 return 0;
239 static int
240 test_encrypt_decrypt(int cfd)
242 char plaintext_raw[DATA_SIZE + 63], *plaintext;
243 char ciphertext_raw[DATA_SIZE + 63], *ciphertext;
244 char iv[BLOCK_SIZE];
245 char key[KEY_SIZE];
246 char auth[AUTH_SIZE];
247 unsigned char sha1mac[20];
248 int enc_len;
250 struct session_op sess;
251 struct crypt_op co;
252 struct crypt_auth_op cao;
253 struct session_info_op siop;
255 memset(&sess, 0, sizeof(sess));
256 memset(&cao, 0, sizeof(cao));
257 memset(&co, 0, sizeof(co));
259 memset(key,0x33, sizeof(key));
260 memset(iv, 0x03, sizeof(iv));
261 memset(auth, 0xf1, sizeof(auth));
263 /* Get crypto session for AES128 */
264 sess.cipher = CRYPTO_AES_CBC;
265 sess.keylen = KEY_SIZE;
266 sess.key = key;
268 sess.mac = CRYPTO_SHA1_HMAC;
269 sess.mackeylen = 16;
270 sess.mackey = (uint8_t*)"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
272 if (ioctl(cfd, CIOCGSESSION, &sess)) {
273 perror("ioctl(CIOCGSESSION)");
274 return 1;
277 siop.ses = sess.ses;
278 if (ioctl(cfd, CIOCGSESSINFO, &siop)) {
279 perror("ioctl(CIOCGSESSINFO)");
280 return 1;
282 // printf("requested cipher CRYPTO_AES_CBC/HMAC-SHA1, got %s with driver %s\n",
283 // siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name);
285 plaintext = (char *)(((unsigned long)plaintext_raw + siop.alignmask) & ~siop.alignmask);
286 ciphertext = (char *)(((unsigned long)ciphertext_raw + siop.alignmask) & ~siop.alignmask);
288 memset(plaintext, 0x15, DATA_SIZE);
290 if (get_sha1_hmac(cfd, sess.mackey, sess.mackeylen, auth, sizeof(auth), plaintext, DATA_SIZE, sha1mac) != 0) {
291 fprintf(stderr, "SHA1 MAC failed\n");
292 return 1;
295 memcpy(ciphertext, plaintext, DATA_SIZE);
297 /* Encrypt data.in to data.encrypted */
298 cao.ses = sess.ses;
299 cao.auth_src = (void*)auth;
300 cao.auth_len = sizeof(auth);
301 cao.len = DATA_SIZE;
302 cao.src = (void*)ciphertext;
303 cao.dst = (void*)ciphertext;
304 cao.iv = iv;
305 cao.op = COP_ENCRYPT;
306 cao.flags = COP_FLAG_AEAD_TLS_TYPE;
308 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
309 perror("ioctl(CIOCAUTHCRYPT)");
310 return 1;
313 enc_len = cao.len;
314 //printf("Original plaintext size: %d, ciphertext: %d\n", DATA_SIZE, enc_len);
316 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
317 perror("ioctl(CIOCFSESSION)");
318 return 1;
321 /* Get crypto session for AES128 */
322 memset(&sess, 0, sizeof(sess));
323 sess.cipher = CRYPTO_AES_CBC;
324 sess.keylen = KEY_SIZE;
325 sess.key = key;
326 sess.mac = CRYPTO_SHA1_HMAC;
327 sess.mackeylen = 16;
328 sess.mackey = (uint8_t*)"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
330 if (ioctl(cfd, CIOCGSESSION, &sess)) {
331 perror("ioctl(CIOCGSESSION)");
332 return 1;
335 /* Decrypt data.encrypted to data.decrypted */
336 cao.ses = sess.ses;
337 cao.auth_src = auth;
338 cao.auth_len = sizeof(auth);
339 cao.len = enc_len;
340 cao.src = ciphertext;
341 cao.dst = ciphertext;
342 cao.iv = iv;
343 cao.op = COP_DECRYPT;
344 cao.flags = COP_FLAG_AEAD_TLS_TYPE;
345 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
346 perror("ioctl(CIOCAUTHCRYPT)");
347 return 1;
350 if (cao.len != DATA_SIZE) {
351 fprintf(stderr, "decrypted data size incorrect!\n");
352 return 1;
355 /* Verify the result */
356 if (memcmp(plaintext, ciphertext, DATA_SIZE) != 0) {
357 int i;
358 fprintf(stderr,
359 "FAIL: Decrypted data are different from the input data.\n");
360 printf("plaintext:");
361 for (i = 0; i < DATA_SIZE; i++) {
362 if ((i % 30) == 0)
363 printf("\n");
364 printf("%02x ", plaintext[i]);
366 printf("ciphertext:");
367 for (i = 0; i < DATA_SIZE; i++) {
368 if ((i % 30) == 0)
369 printf("\n");
370 printf("%02x ", ciphertext[i]);
372 printf("\n");
373 return 1;
376 printf("Test passed\n");
379 /* Finish crypto session */
380 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
381 perror("ioctl(CIOCFSESSION)");
382 return 1;
385 return 0;
388 static int
389 test_encrypt_decrypt_error(int cfd, int err)
391 char plaintext_raw[DATA_SIZE + 63], *plaintext;
392 char ciphertext_raw[DATA_SIZE + 63], *ciphertext;
393 char iv[BLOCK_SIZE];
394 char key[KEY_SIZE];
395 char auth[AUTH_SIZE];
396 unsigned char sha1mac[20];
397 int enc_len;
399 struct session_op sess;
400 struct crypt_op co;
401 struct crypt_auth_op cao;
402 struct session_info_op siop;
404 memset(&sess, 0, sizeof(sess));
405 memset(&cao, 0, sizeof(cao));
406 memset(&co, 0, sizeof(co));
408 memset(key,0x33, sizeof(key));
409 memset(iv, 0x03, sizeof(iv));
410 memset(auth, 0xf1, sizeof(auth));
412 /* Get crypto session for AES128 */
413 sess.cipher = CRYPTO_AES_CBC;
414 sess.keylen = KEY_SIZE;
415 sess.key = key;
417 sess.mac = CRYPTO_SHA1_HMAC;
418 sess.mackeylen = 16;
419 sess.mackey = (uint8_t*)"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
421 if (ioctl(cfd, CIOCGSESSION, &sess)) {
422 perror("ioctl(CIOCGSESSION)");
423 return 1;
426 siop.ses = sess.ses;
427 if (ioctl(cfd, CIOCGSESSINFO, &siop)) {
428 perror("ioctl(CIOCGSESSINFO)");
429 return 1;
431 // printf("requested cipher CRYPTO_AES_CBC/HMAC-SHA1, got %s with driver %s\n",
432 // siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name);
434 plaintext = (char *)(((unsigned long)plaintext_raw + siop.alignmask) & ~siop.alignmask);
435 ciphertext = (char *)(((unsigned long)ciphertext_raw + siop.alignmask) & ~siop.alignmask);
436 memset(plaintext, 0x15, DATA_SIZE);
438 if (get_sha1_hmac(cfd, sess.mackey, sess.mackeylen, auth, sizeof(auth), plaintext, DATA_SIZE, sha1mac) != 0) {
439 fprintf(stderr, "SHA1 MAC failed\n");
440 return 1;
443 memcpy(ciphertext, plaintext, DATA_SIZE);
445 /* Encrypt data.in to data.encrypted */
446 cao.ses = sess.ses;
447 cao.auth_src = auth;
448 cao.auth_len = sizeof(auth);
449 cao.len = DATA_SIZE;
450 cao.src = ciphertext;
451 cao.dst = ciphertext;
452 cao.iv = iv;
453 cao.op = COP_ENCRYPT;
454 cao.flags = COP_FLAG_AEAD_TLS_TYPE;
456 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
457 perror("ioctl(CIOCAUTHCRYPT)");
458 return 1;
461 enc_len = cao.len;
462 //printf("Original plaintext size: %d, ciphertext: %d\n", DATA_SIZE, enc_len);
464 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
465 perror("ioctl(CIOCFSESSION)");
466 return 1;
469 /* Get crypto session for AES128 */
470 memset(&sess, 0, sizeof(sess));
471 sess.cipher = CRYPTO_AES_CBC;
472 sess.keylen = KEY_SIZE;
473 sess.key = key;
474 sess.mac = CRYPTO_SHA1_HMAC;
475 sess.mackeylen = 16;
476 sess.mackey = (uint8_t*)"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
478 if (ioctl(cfd, CIOCGSESSION, &sess)) {
479 perror("ioctl(CIOCGSESSION)");
480 return 1;
483 if (err == 0)
484 auth[2]++;
485 else
486 ciphertext[4]++;
488 /* Decrypt data.encrypted to data.decrypted */
489 cao.ses = sess.ses;
490 cao.auth_src = auth;
491 cao.auth_len = sizeof(auth);
492 cao.len = enc_len;
493 cao.src = ciphertext;
494 cao.dst = ciphertext;
495 cao.iv = iv;
496 cao.op = COP_DECRYPT;
497 cao.flags = COP_FLAG_AEAD_TLS_TYPE;
498 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
499 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
500 perror("ioctl(CIOCFSESSION)");
501 return 1;
504 printf("Test passed\n");
505 return 0;
508 /* Finish crypto session */
509 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
510 perror("ioctl(CIOCFSESSION)");
511 return 1;
515 fprintf(stderr, "Modification to ciphertext was not detected\n");
516 return 1;
520 main()
522 int fd = -1, cfd = -1;
524 /* Open the crypto device */
525 fd = open("/dev/crypto", O_RDWR, 0);
526 if (fd < 0) {
527 perror("open(/dev/crypto)");
528 return 1;
531 /* Clone file descriptor */
532 if (ioctl(fd, CRIOGET, &cfd)) {
533 perror("ioctl(CRIOGET)");
534 return 1;
537 /* Set close-on-exec (not really neede here) */
538 if (fcntl(cfd, F_SETFD, 1) == -1) {
539 perror("fcntl(F_SETFD)");
540 return 1;
543 /* Run the test itself */
545 if (test_crypto(cfd))
546 return 1;
548 if (test_encrypt_decrypt(cfd))
549 return 1;
551 if (test_encrypt_decrypt_error(cfd, 0))
552 return 1;
554 if (test_encrypt_decrypt_error(cfd, 1))
555 return 1;
557 /* Close cloned descriptor */
558 if (close(cfd)) {
559 perror("close(cfd)");
560 return 1;
563 /* Close the original descriptor */
564 if (close(fd)) {
565 perror("close(fd)");
566 return 1;
569 return 0;