Removed the guards against empty PT and empty AAD. It's an edge case that -- while...
[cryptodev-linux.git] / tests / cipher-aead-srtp.c
blobfae04e7367509f7f4aa56f2f2baaf3971392bda3
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 HEADER_SIZE 193
18 #define PLAINTEXT_SIZE 1021
19 #define FOOTER_SIZE 15
20 #define BLOCK_SIZE 16
21 #define KEY_SIZE 16
23 #define MAC_SIZE 20 /* SHA1 */
25 static int debug = 0;
27 static int
28 get_sha1_hmac(int cfd, void* key, int key_size, void* data, int data_size, void* mac)
30 struct session_op sess;
31 struct crypt_op cryp;
33 memset(&sess, 0, sizeof(sess));
34 memset(&cryp, 0, sizeof(cryp));
36 sess.cipher = 0;
37 sess.mac = CRYPTO_SHA1_HMAC;
38 sess.mackeylen = key_size;
39 sess.mackey = key;
40 if (ioctl(cfd, CIOCGSESSION, &sess)) {
41 perror("ioctl(CIOCGSESSION)");
42 return 1;
45 /* Encrypt data.in to data.encrypted */
46 cryp.ses = sess.ses;
47 cryp.len = data_size;
48 cryp.src = data;
49 cryp.dst = NULL;
50 cryp.iv = NULL;
51 cryp.mac = mac;
52 cryp.op = COP_ENCRYPT;
53 if (ioctl(cfd, CIOCCRYPT, &cryp)) {
54 perror("ioctl(CIOCCRYPT)");
55 return 1;
58 /* Finish crypto session */
59 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
60 perror("ioctl(CIOCFSESSION)");
61 return 1;
64 return 0;
67 static void print_buf(char* desc, unsigned char* buf, int size)
69 int i;
70 fputs(desc, stderr);
71 for (i=0;i<size;i++) {
72 fprintf(stderr, "%.2x", (uint8_t)buf[i]);
74 fputs("\n", stderr);
77 static int
78 test_crypto(int cfd)
80 char plaintext_raw[DATA_SIZE + 63], *plaintext;
81 char ciphertext_raw[DATA_SIZE + 63], *ciphertext;
82 char iv[BLOCK_SIZE];
83 char key[KEY_SIZE];
84 unsigned char sha1mac[20];
85 unsigned char tag[20];
86 unsigned char mackey[] = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
87 int mackey_len = 16;
89 struct session_op sess;
90 struct crypt_op co;
91 struct crypt_auth_op cao;
92 struct session_info_op siop;
94 memset(&sess, 0, sizeof(sess));
95 memset(&cao, 0, sizeof(cao));
96 memset(&co, 0, sizeof(co));
98 memset(key,0x33, sizeof(key));
99 memset(iv, 0x03, sizeof(iv));
101 /* Get crypto session for AES128 */
102 sess.cipher = CRYPTO_AES_CTR;
103 sess.keylen = KEY_SIZE;
104 sess.key = key;
106 sess.mac = CRYPTO_SHA1_HMAC;
107 sess.mackeylen = mackey_len;
108 sess.mackey = mackey;
110 if (ioctl(cfd, CIOCGSESSION, &sess)) {
111 perror("ioctl(CIOCGSESSION)");
112 return 1;
115 siop.ses = sess.ses;
116 if (ioctl(cfd, CIOCGSESSINFO, &siop)) {
117 perror("ioctl(CIOCGSESSINFO)");
118 return 1;
121 if (debug)
122 printf("requested cipher CRYPTO_AES_CBC/HMAC-SHA1, got %s with driver %s\n",
123 siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name);
125 plaintext = (char *)(((unsigned long)plaintext_raw + siop.alignmask) & ~siop.alignmask);
126 ciphertext = (char *)(((unsigned long)ciphertext_raw + siop.alignmask) & ~siop.alignmask);
128 memset(plaintext, 0x15, HEADER_SIZE); /* header */
129 memset(&plaintext[HEADER_SIZE], 0x17, PLAINTEXT_SIZE); /* payload */
130 memset(&plaintext[HEADER_SIZE+PLAINTEXT_SIZE], 0x22, FOOTER_SIZE);
132 memcpy(ciphertext, plaintext, DATA_SIZE);
134 /* Encrypt data.in to data.encrypted */
135 cao.ses = sess.ses;
136 cao.len = PLAINTEXT_SIZE;
137 cao.auth_len = HEADER_SIZE+PLAINTEXT_SIZE+FOOTER_SIZE;
138 cao.auth_src = ciphertext;
139 cao.src = ciphertext+HEADER_SIZE;
140 cao.dst = cao.src;
141 cao.iv = iv;
142 cao.op = COP_ENCRYPT;
143 cao.flags = COP_FLAG_AEAD_SRTP_TYPE;
144 cao.tag = tag;
145 cao.tag_len = 20;
147 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
148 perror("ioctl(CIOCAUTHCRYPT)");
149 return 1;
153 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
154 perror("ioctl(CIOCFSESSION)");
155 return 1;
158 /* Get crypto session for AES128 */
159 memset(&sess, 0, sizeof(sess));
160 sess.cipher = CRYPTO_AES_CTR;
161 sess.keylen = KEY_SIZE;
162 sess.key = key;
164 if (ioctl(cfd, CIOCGSESSION, &sess)) {
165 perror("ioctl(CIOCGSESSION)");
166 return 1;
169 if (get_sha1_hmac(cfd, mackey, mackey_len, ciphertext, HEADER_SIZE + PLAINTEXT_SIZE + FOOTER_SIZE, sha1mac) != 0) {
170 fprintf(stderr, "SHA1 MAC failed\n");
171 return 1;
174 if (memcmp(tag, sha1mac, 20) != 0) {
175 fprintf(stderr, "AEAD SHA1 MAC does not match plain MAC\n");
176 print_buf("SHA1: ", sha1mac, 20);
177 print_buf("SHA1-SRTP: ", tag, 20);
178 return 1;
181 /* Decrypt data.encrypted to data.decrypted */
182 co.ses = sess.ses;
183 co.len = PLAINTEXT_SIZE;
184 co.src = ciphertext+HEADER_SIZE;
185 co.dst = ciphertext+HEADER_SIZE;
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+HEADER_SIZE, ciphertext+HEADER_SIZE, PLAINTEXT_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 ", (unsigned int)plaintext[i]);
204 printf("ciphertext:");
205 for (i = 0; i < DATA_SIZE; i++) {
206 if ((i % 30) == 0)
207 printf("\n");
208 printf("%02x ", (unsigned int)ciphertext[i]);
210 printf("\n");
211 return 1;
214 if (debug) printf("Test passed\n");
216 /* Finish crypto session */
217 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
218 perror("ioctl(CIOCFSESSION)");
219 return 1;
222 return 0;
225 static int
226 test_encrypt_decrypt(int cfd)
228 char plaintext_raw[DATA_SIZE + 63], *plaintext;
229 char ciphertext_raw[DATA_SIZE + 63], *ciphertext;
230 char iv[BLOCK_SIZE];
231 char key[KEY_SIZE];
232 unsigned char tag[20];
233 unsigned char mackey[] = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
234 int mackey_len = 16;
236 struct session_op sess;
237 struct crypt_auth_op cao;
238 struct session_info_op siop;
240 memset(&sess, 0, sizeof(sess));
241 memset(&cao, 0, sizeof(cao));
243 memset(key,0x33, sizeof(key));
244 memset(iv, 0x03, sizeof(iv));
246 /* Get crypto session for AES128 */
247 sess.cipher = CRYPTO_AES_CTR;
248 sess.keylen = KEY_SIZE;
249 sess.key = key;
251 sess.mac = CRYPTO_SHA1_HMAC;
252 sess.mackeylen = mackey_len;
253 sess.mackey = mackey;
255 if (ioctl(cfd, CIOCGSESSION, &sess)) {
256 perror("ioctl(CIOCGSESSION)");
257 return 1;
260 siop.ses = sess.ses;
261 if (ioctl(cfd, CIOCGSESSINFO, &siop)) {
262 perror("ioctl(CIOCGSESSINFO)");
263 return 1;
265 // printf("requested cipher CRYPTO_AES_CBC/HMAC-SHA1, got %s with driver %s\n",
266 // siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name);
268 plaintext = (char *)(((unsigned long)plaintext_raw + siop.alignmask) & ~siop.alignmask);
269 ciphertext = (char *)(((unsigned long)ciphertext_raw + siop.alignmask) & ~siop.alignmask);
271 memset(plaintext, 0x15, HEADER_SIZE); /* header */
272 memset(&plaintext[HEADER_SIZE], 0x17, PLAINTEXT_SIZE); /* payload */
273 memset(&plaintext[HEADER_SIZE+PLAINTEXT_SIZE], 0x22, FOOTER_SIZE);
275 memcpy(ciphertext, plaintext, DATA_SIZE);
277 /* Encrypt data.in to data.encrypted */
278 cao.ses = sess.ses;
279 cao.len = PLAINTEXT_SIZE;
280 cao.auth_len = HEADER_SIZE+PLAINTEXT_SIZE+FOOTER_SIZE;
281 cao.auth_src = ciphertext;
282 cao.src = ciphertext+HEADER_SIZE;
283 cao.dst = cao.src;
284 cao.iv = iv;
285 cao.op = COP_ENCRYPT;
286 cao.flags = COP_FLAG_AEAD_SRTP_TYPE;
287 cao.tag = tag;
288 cao.tag_len = 20;
290 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
291 perror("ioctl(CIOCAUTHCRYPT)");
292 return 1;
296 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
297 perror("ioctl(CIOCFSESSION)");
298 return 1;
301 /* Get crypto session for AES128 */
302 memset(&sess, 0, sizeof(sess));
303 sess.cipher = CRYPTO_AES_CTR;
304 sess.keylen = KEY_SIZE;
305 sess.key = key;
307 sess.mac = CRYPTO_SHA1_HMAC;
308 sess.mackeylen = mackey_len;
309 sess.mackey = mackey;
311 if (ioctl(cfd, CIOCGSESSION, &sess)) {
312 perror("ioctl(CIOCGSESSION)");
313 return 1;
316 /* Decrypt data.encrypted to data.decrypted */
317 /* Encrypt data.in to data.encrypted */
318 cao.ses = sess.ses;
319 cao.len = PLAINTEXT_SIZE;
320 cao.auth_len = HEADER_SIZE+PLAINTEXT_SIZE+FOOTER_SIZE;
321 cao.auth_src = ciphertext;
322 cao.src = ciphertext+HEADER_SIZE;
323 cao.dst = cao.src;
324 cao.iv = iv;
325 cao.op = COP_DECRYPT;
326 cao.flags = COP_FLAG_AEAD_SRTP_TYPE;
327 cao.tag = tag;
328 cao.tag_len = 20;
329 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
330 perror("ioctl(CIOCCRYPT)");
331 return 1;
334 /* Verify the result */
335 if (memcmp(plaintext+HEADER_SIZE, ciphertext+HEADER_SIZE, PLAINTEXT_SIZE) != 0) {
336 int i;
337 fprintf(stderr,
338 "FAIL: Decrypted data are different from the input data.\n");
339 printf("plaintext:");
340 for (i = 0; i < DATA_SIZE; i++) {
341 if ((i % 30) == 0)
342 printf("\n");
343 printf("%02x ", (unsigned int)plaintext[i]);
345 printf("ciphertext:");
346 for (i = 0; i < DATA_SIZE; i++) {
347 if ((i % 30) == 0)
348 printf("\n");
349 printf("%02x ", (unsigned int)ciphertext[i]);
351 printf("\n");
352 return 1;
355 if (debug) printf("Test passed\n");
358 /* Finish crypto session */
359 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
360 perror("ioctl(CIOCFSESSION)");
361 return 1;
364 return 0;
367 static int
368 test_encrypt_decrypt_error(int cfd, int err)
370 char plaintext_raw[DATA_SIZE + 63], *plaintext;
371 char ciphertext_raw[DATA_SIZE + 63], *ciphertext;
372 char iv[BLOCK_SIZE];
373 char key[KEY_SIZE];
374 unsigned char tag[20];
375 unsigned char mackey[] = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
376 int mackey_len = 16;
378 struct session_op sess;
379 struct crypt_auth_op cao;
380 struct session_info_op siop;
382 memset(&sess, 0, sizeof(sess));
383 memset(&cao, 0, sizeof(cao));
385 memset(key,0x33, sizeof(key));
386 memset(iv, 0x03, sizeof(iv));
388 /* Get crypto session for AES128 */
389 sess.cipher = CRYPTO_AES_CTR;
390 sess.keylen = KEY_SIZE;
391 sess.key = key;
393 sess.mac = CRYPTO_SHA1_HMAC;
394 sess.mackeylen = mackey_len;
395 sess.mackey = mackey;
397 if (ioctl(cfd, CIOCGSESSION, &sess)) {
398 perror("ioctl(CIOCGSESSION)");
399 return 1;
402 siop.ses = sess.ses;
403 if (ioctl(cfd, CIOCGSESSINFO, &siop)) {
404 perror("ioctl(CIOCGSESSINFO)");
405 return 1;
407 // printf("requested cipher CRYPTO_AES_CBC/HMAC-SHA1, got %s with driver %s\n",
408 // siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name);
410 plaintext = (char *)(((unsigned long)plaintext_raw + siop.alignmask) & ~siop.alignmask);
411 ciphertext = (char *)(((unsigned long)ciphertext_raw + siop.alignmask) & ~siop.alignmask);
413 memset(plaintext, 0x15, HEADER_SIZE); /* header */
414 memset(&plaintext[HEADER_SIZE], 0x17, PLAINTEXT_SIZE); /* payload */
415 memset(&plaintext[HEADER_SIZE+PLAINTEXT_SIZE], 0x22, FOOTER_SIZE);
417 memcpy(ciphertext, plaintext, DATA_SIZE);
419 /* Encrypt data.in to data.encrypted */
420 cao.ses = sess.ses;
421 cao.len = PLAINTEXT_SIZE;
422 cao.auth_len = HEADER_SIZE+PLAINTEXT_SIZE+FOOTER_SIZE;
423 cao.auth_src = ciphertext;
424 cao.src = ciphertext+HEADER_SIZE;
425 cao.dst = cao.src;
426 cao.iv = iv;
427 cao.op = COP_ENCRYPT;
428 cao.flags = COP_FLAG_AEAD_SRTP_TYPE;
429 cao.tag = tag;
430 cao.tag_len = 20;
432 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
433 perror("ioctl(CIOCAUTHCRYPT)");
434 return 1;
438 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
439 perror("ioctl(CIOCFSESSION)");
440 return 1;
443 /* Get crypto session for AES128 */
444 memset(&sess, 0, sizeof(sess));
445 sess.cipher = CRYPTO_AES_CTR;
446 sess.keylen = KEY_SIZE;
447 sess.key = key;
449 sess.mac = CRYPTO_SHA1_HMAC;
450 sess.mackeylen = mackey_len;
451 sess.mackey = mackey;
453 if (ioctl(cfd, CIOCGSESSION, &sess)) {
454 perror("ioctl(CIOCGSESSION)");
455 return 1;
458 /* Decrypt data.encrypted to data.decrypted */
459 /* Encrypt data.in to data.encrypted */
460 if (err == 0)
461 ciphertext[1]++;
462 else
463 ciphertext[HEADER_SIZE+3]++;
464 cao.ses = sess.ses;
465 cao.len = PLAINTEXT_SIZE;
466 cao.auth_len = HEADER_SIZE+PLAINTEXT_SIZE+FOOTER_SIZE;
467 cao.auth_src = ciphertext;
468 cao.src = ciphertext+HEADER_SIZE;
469 cao.dst = cao.src;
470 cao.iv = iv;
471 cao.op = COP_DECRYPT;
472 cao.flags = COP_FLAG_AEAD_SRTP_TYPE;
473 cao.tag = tag;
474 cao.tag_len = 20;
475 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
476 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
477 perror("ioctl(CIOCFSESSION)");
478 return 1;
481 if (debug) printf("Test passed\n");
482 return 0;
485 /* Verify the result */
486 if (memcmp(plaintext+HEADER_SIZE, ciphertext+HEADER_SIZE, PLAINTEXT_SIZE) != 0) {
487 int i;
488 fprintf(stderr,
489 "FAIL: Decrypted data are different from the input data.\n");
490 printf("plaintext:");
491 for (i = 0; i < DATA_SIZE; i++) {
492 if ((i % 30) == 0)
493 printf("\n");
494 printf("%02x ", (unsigned int)plaintext[i]);
496 printf("ciphertext:");
497 for (i = 0; i < DATA_SIZE; i++) {
498 if ((i % 30) == 0)
499 printf("\n");
500 printf("%02x ", (unsigned int)ciphertext[i]);
502 printf("\n");
503 return 1;
506 printf("Test failed\n");
509 /* Finish crypto session */
510 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
511 perror("ioctl(CIOCFSESSION)");
512 return 1;
515 return 1;
519 main(int argc, char** argv)
521 int fd = -1, cfd = -1;
523 if (argc > 1) debug = 1;
525 /* Open the crypto device */
526 fd = open("/dev/crypto", O_RDWR, 0);
527 if (fd < 0) {
528 perror("open(/dev/crypto)");
529 return 1;
532 /* Clone file descriptor */
533 if (ioctl(fd, CRIOGET, &cfd)) {
534 perror("ioctl(CRIOGET)");
535 return 1;
538 /* Set close-on-exec (not really neede here) */
539 if (fcntl(cfd, F_SETFD, 1) == -1) {
540 perror("fcntl(F_SETFD)");
541 return 1;
544 /* Run the test itself */
546 if (test_crypto(cfd))
547 return 1;
549 if (test_encrypt_decrypt(cfd))
550 return 1;
552 if (test_encrypt_decrypt_error(cfd,0))
553 return 1;
555 if (test_encrypt_decrypt_error(cfd,1))
556 return 1;
558 /* Close cloned descriptor */
559 if (close(cfd)) {
560 perror("close(cfd)");
561 return 1;
564 /* Close the original descriptor */
565 if (close(fd)) {
566 perror("close(fd)");
567 return 1;
570 return 0;