doc update
[cryptodev-linux.git] / tests / cipher-gcm.c
blob599e70c98971ef147750e2cdc4c4dc6ed895545a
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 int debug = 0;
25 static void print_buf(char *desc, const unsigned char *buf, int size)
27 int i;
28 fputs(desc, stdout);
29 for (i = 0; i < size; i++) {
30 printf("%.2x", (uint8_t) buf[i]);
32 fputs("\n", stdout);
35 struct aes_gcm_vectors_st {
36 const uint8_t *key;
37 const uint8_t *auth;
38 int auth_size;
39 const uint8_t *plaintext;
40 int plaintext_size;
41 const uint8_t *iv;
42 const uint8_t *ciphertext;
43 const uint8_t *tag;
46 struct aes_gcm_vectors_st aes_gcm_vectors[] = {
48 .key =
49 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
50 .auth = NULL,
51 .auth_size = 0,
52 .plaintext =
53 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
54 .plaintext_size = 16,
55 .ciphertext =
56 "\x03\x88\xda\xce\x60\xb6\xa3\x92\xf3\x28\xc2\xb9\x71\xb2\xfe\x78",
57 .iv = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
58 .tag =
59 "\xab\x6e\x47\xd4\x2c\xec\x13\xbd\xf5\x3a\x67\xb2\x12\x57\xbd\xdf"
62 .key =
63 "\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08",
64 .auth = NULL,
65 .auth_size = 0,
66 .plaintext =
67 "\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",
68 .plaintext_size = 64,
69 .ciphertext =
70 "\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",
71 .iv = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad\xde\xca\xf8\x88",
72 .tag = "\x4d\x5c\x2a\xf3\x27\xcd\x64\xa6\x2c\xf3\x5a\xbd\x2b\xa6\xfa\xb4"
75 .key =
76 "\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08",
77 .auth =
78 "\xfe\xed\xfa\xce\xde\xad\xbe\xef\xfe\xed\xfa\xce\xde\xad\xbe\xef\xab\xad\xda\xd2",
79 .auth_size = 20,
80 .plaintext =
81 "\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",
82 .plaintext_size = 60,
83 .ciphertext =
84 "\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",
85 .iv = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad\xde\xca\xf8\x88",
86 .tag =
87 "\x5b\xc9\x4f\xbc\x32\x21\xa5\xdb\x94\xfa\xe9\x5a\xe7\x12\x1a\x47"
92 /* Test against AES-GCM test vectors.
94 static int test_crypto(int cfd)
96 int i;
97 int8_t tmp[128];
99 struct session_op sess;
100 struct crypt_auth_op cao;
102 /* Get crypto session for AES128 */
104 if (debug) {
105 fprintf(stdout, "Tests on AES-GCM vectors: ");
106 fflush(stdout);
108 for (i = 0;
109 i < sizeof(aes_gcm_vectors) / sizeof(aes_gcm_vectors[0]);
110 i++) {
111 memset(&sess, 0, sizeof(sess));
112 memset(tmp, 0, sizeof(tmp));
114 sess.cipher = CRYPTO_AES_GCM;
115 sess.keylen = 16;
116 sess.key = (void *) aes_gcm_vectors[i].key;
118 if (ioctl(cfd, CIOCGSESSION, &sess)) {
119 my_perror("ioctl(CIOCGSESSION)");
120 return 1;
123 memset(&cao, 0, sizeof(cao));
125 cao.ses = sess.ses;
126 cao.dst = tmp;
127 cao.iv = (void *) aes_gcm_vectors[i].iv;
128 cao.iv_len = 12;
129 cao.op = COP_ENCRYPT;
130 cao.flags = 0;
132 if (aes_gcm_vectors[i].auth_size > 0) {
133 cao.auth_src = (void *) aes_gcm_vectors[i].auth;
134 cao.auth_len = aes_gcm_vectors[i].auth_size;
137 if (aes_gcm_vectors[i].plaintext_size > 0) {
138 cao.src = (void *) aes_gcm_vectors[i].plaintext;
139 cao.len = aes_gcm_vectors[i].plaintext_size;
142 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
143 my_perror("ioctl(CIOCAUTHCRYPT)");
144 return 1;
147 if (aes_gcm_vectors[i].plaintext_size > 0)
148 if (memcmp
149 (tmp, aes_gcm_vectors[i].ciphertext,
150 aes_gcm_vectors[i].plaintext_size) != 0) {
151 fprintf(stderr,
152 "AES-GCM test vector %d failed!\n",
155 print_buf("Cipher: ", tmp, aes_gcm_vectors[i].plaintext_size);
156 print_buf("Expected: ", aes_gcm_vectors[i].ciphertext, aes_gcm_vectors[i].plaintext_size);
157 return 1;
160 if (memcmp
161 (&tmp[cao.len - cao.tag_len], aes_gcm_vectors[i].tag,
162 16) != 0) {
163 fprintf(stderr,
164 "AES-GCM test vector %d failed (tag)!\n",
167 print_buf("Tag: ", tmp, cao.tag_len);
168 print_buf("Expected tag: ",
169 aes_gcm_vectors[i].tag, 16);
170 return 1;
175 if (debug) {
176 fprintf(stdout, "ok\n");
177 fprintf(stdout, "\n");
180 /* Finish crypto session */
181 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
182 my_perror("ioctl(CIOCFSESSION)");
183 return 1;
186 return 0;
189 /* Checks if encryption and subsequent decryption
190 * produces the same data.
192 static int test_encrypt_decrypt(int cfd)
194 char plaintext_raw[DATA_SIZE + 63], *plaintext;
195 char ciphertext_raw[DATA_SIZE + 63], *ciphertext;
196 char iv[BLOCK_SIZE];
197 char key[KEY_SIZE];
198 char auth[AUTH_SIZE];
199 int enc_len;
201 struct session_op sess;
202 struct crypt_auth_op cao;
203 struct session_info_op siop;
205 if (debug) {
206 fprintf(stdout, "Tests on AES-GCM encryption/decryption: ");
207 fflush(stdout);
210 memset(&sess, 0, sizeof(sess));
211 memset(&cao, 0, sizeof(cao));
213 memset(key, 0x33, sizeof(key));
214 memset(iv, 0x03, sizeof(iv));
215 memset(auth, 0xf1, sizeof(auth));
217 /* Get crypto session for AES128 */
218 sess.cipher = CRYPTO_AES_GCM;
219 sess.keylen = KEY_SIZE;
220 sess.key = key;
222 if (ioctl(cfd, CIOCGSESSION, &sess)) {
223 my_perror("ioctl(CIOCGSESSION)");
224 return 1;
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);
242 memset(plaintext, 0x15, DATA_SIZE);
244 /* Encrypt data.in to data.encrypted */
245 cao.ses = sess.ses;
246 cao.auth_src = auth;
247 cao.auth_len = sizeof(auth);
248 cao.len = DATA_SIZE;
249 cao.src = plaintext;
250 cao.dst = ciphertext;
251 cao.iv = iv;
252 cao.iv_len = 12;
253 cao.op = COP_ENCRYPT;
254 cao.flags = 0;
256 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
257 my_perror("ioctl(CIOCAUTHCRYPT)");
258 return 1;
261 enc_len = cao.len;
262 //printf("Original plaintext size: %d, ciphertext: %d\n", DATA_SIZE, enc_len);
264 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
265 my_perror("ioctl(CIOCFSESSION)");
266 return 1;
269 /* Get crypto session for AES128 */
270 memset(&sess, 0, sizeof(sess));
271 sess.cipher = CRYPTO_AES_GCM;
272 sess.keylen = KEY_SIZE;
273 sess.key = key;
275 if (ioctl(cfd, CIOCGSESSION, &sess)) {
276 my_perror("ioctl(CIOCGSESSION)");
277 return 1;
280 /* Decrypt data.encrypted to data.decrypted */
281 cao.ses = sess.ses;
282 cao.auth_src = auth;
283 cao.auth_len = sizeof(auth);
284 cao.len = enc_len;
285 cao.src = ciphertext;
286 cao.dst = ciphertext;
287 cao.iv = iv;
288 cao.iv_len = 12;
289 cao.op = COP_DECRYPT;
290 cao.flags = 0;
292 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
293 my_perror("ioctl(CIOCAUTHCRYPT)");
294 return 1;
297 if (cao.len != DATA_SIZE) {
298 fprintf(stderr, "decrypted data size incorrect!\n");
299 return 1;
302 /* Verify the result */
303 if (memcmp(plaintext, ciphertext, DATA_SIZE) != 0) {
304 int i;
305 fprintf(stderr,
306 "FAIL: Decrypted data are different from the input data.\n");
307 printf("plaintext:");
308 for (i = 0; i < DATA_SIZE; i++) {
309 if ((i % 30) == 0)
310 printf("\n");
311 printf("%02x ", plaintext[i]);
313 printf("ciphertext:");
314 for (i = 0; i < DATA_SIZE; i++) {
315 if ((i % 30) == 0)
316 printf("\n");
317 printf("%02x ", ciphertext[i]);
319 printf("\n");
320 return 1;
323 /* Finish crypto session */
324 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
325 my_perror("ioctl(CIOCFSESSION)");
326 return 1;
329 if (debug) {
330 fprintf(stdout, "ok\n");
331 fprintf(stdout, "\n");
334 return 0;
337 static int test_encrypt_decrypt_error(int cfd, int err)
339 char plaintext_raw[DATA_SIZE + 63], *plaintext;
340 char ciphertext_raw[DATA_SIZE + 63], *ciphertext;
341 char iv[BLOCK_SIZE];
342 char key[KEY_SIZE];
343 char auth[AUTH_SIZE];
344 int enc_len;
346 struct session_op sess;
347 struct crypt_op co;
348 struct crypt_auth_op cao;
349 struct session_info_op siop;
351 if (debug) {
352 fprintf(stdout, "Tests on AES-GCM tag verification: ");
353 fflush(stdout);
356 memset(&sess, 0, sizeof(sess));
357 memset(&cao, 0, sizeof(cao));
358 memset(&co, 0, sizeof(co));
360 memset(key, 0x33, sizeof(key));
361 memset(iv, 0x03, sizeof(iv));
362 memset(auth, 0xf1, sizeof(auth));
364 /* Get crypto session for AES128 */
365 sess.cipher = CRYPTO_AES_CBC;
366 sess.keylen = KEY_SIZE;
367 sess.key = key;
369 sess.mac = CRYPTO_SHA1_HMAC;
370 sess.mackeylen = 16;
371 sess.mackey =
372 (uint8_t *)
373 "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
375 if (ioctl(cfd, CIOCGSESSION, &sess)) {
376 my_perror("ioctl(CIOCGSESSION)");
377 return 1;
380 siop.ses = sess.ses;
381 if (ioctl(cfd, CIOCGSESSINFO, &siop)) {
382 my_perror("ioctl(CIOCGSESSINFO)");
383 return 1;
385 // printf("requested cipher CRYPTO_AES_CBC/HMAC-SHA1, got %s with driver %s\n",
386 // siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name);
388 plaintext =
389 (char *) (((unsigned long) plaintext_raw + siop.alignmask) &
390 ~siop.alignmask);
391 ciphertext =
392 (char *) (((unsigned long) ciphertext_raw + siop.alignmask) &
393 ~siop.alignmask);
395 memset(plaintext, 0x15, DATA_SIZE);
396 memcpy(ciphertext, plaintext, DATA_SIZE);
398 /* Encrypt data.in to data.encrypted */
399 cao.ses = sess.ses;
400 cao.auth_src = auth;
401 cao.auth_len = sizeof(auth);
402 cao.len = DATA_SIZE;
403 cao.src = ciphertext;
404 cao.dst = ciphertext;
405 cao.iv = iv;
406 cao.op = COP_ENCRYPT;
407 cao.flags = COP_FLAG_AEAD_TLS_TYPE;
409 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
410 my_perror("ioctl(CIOCAUTHCRYPT)");
411 return 1;
414 enc_len = cao.len;
415 //printf("Original plaintext size: %d, ciphertext: %d\n", DATA_SIZE, enc_len);
417 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
418 my_perror("ioctl(CIOCFSESSION)");
419 return 1;
422 /* Get crypto session for AES128 */
423 memset(&sess, 0, sizeof(sess));
424 sess.cipher = CRYPTO_AES_CBC;
425 sess.keylen = KEY_SIZE;
426 sess.key = key;
427 sess.mac = CRYPTO_SHA1_HMAC;
428 sess.mackeylen = 16;
429 sess.mackey =
430 (uint8_t *)
431 "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
433 if (ioctl(cfd, CIOCGSESSION, &sess)) {
434 my_perror("ioctl(CIOCGSESSION)");
435 return 1;
438 if (err == 0)
439 auth[2]++;
440 else
441 ciphertext[4]++;
443 /* Decrypt data.encrypted to data.decrypted */
444 cao.ses = sess.ses;
445 cao.auth_src = auth;
446 cao.auth_len = sizeof(auth);
447 cao.len = enc_len;
448 cao.src = ciphertext;
449 cao.dst = ciphertext;
450 cao.iv = iv;
451 cao.op = COP_DECRYPT;
452 cao.flags = COP_FLAG_AEAD_TLS_TYPE;
453 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
454 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
455 my_perror("ioctl(CIOCFSESSION)");
456 return 1;
459 if (debug) {
460 fprintf(stdout, "ok\n");
461 fprintf(stdout, "\n");
463 return 0;
466 /* Finish crypto session */
467 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
468 my_perror("ioctl(CIOCFSESSION)");
469 return 1;
473 fprintf(stderr, "Modification to ciphertext was not detected\n");
474 return 1;
477 int main(int argc, char** argv)
479 int fd = -1, cfd = -1;
481 if (argc > 1) debug = 1;
483 /* Open the crypto device */
484 fd = open("/dev/crypto", O_RDWR, 0);
485 if (fd < 0) {
486 my_perror("open(/dev/crypto)");
487 return 1;
490 /* Clone file descriptor */
491 if (ioctl(fd, CRIOGET, &cfd)) {
492 my_perror("ioctl(CRIOGET)");
493 return 1;
496 /* Set close-on-exec (not really neede here) */
497 if (fcntl(cfd, F_SETFD, 1) == -1) {
498 my_perror("fcntl(F_SETFD)");
499 return 1;
502 /* Run the test itself */
504 if (test_crypto(cfd))
505 return 1;
507 if (test_encrypt_decrypt(cfd))
508 return 1;
510 if (test_encrypt_decrypt_error(cfd, 0))
511 return 1;
513 if (test_encrypt_decrypt_error(cfd, 1))
514 return 1;
516 /* Close cloned descriptor */
517 if (close(cfd)) {
518 my_perror("close(cfd)");
519 return 1;
522 /* Close the original descriptor */
523 if (close(fd)) {
524 my_perror("close(fd)");
525 return 1;
528 return 0;