2 * Demo on how to use /dev/crypto device for ciphering.
4 * Placed under public domain.
13 #include <sys/ioctl.h>
14 #include <crypto/cryptodev.h>
16 #define DATA_SIZE (8*1024)
21 #define my_perror(x) {fprintf(stderr, "%s: %d\n", __func__, __LINE__); perror(x); }
23 static void print_buf(char *desc
, const unsigned char *buf
, int size
)
27 for (i
= 0; i
< size
; i
++) {
28 printf("%.2x", (uint8_t) buf
[i
]);
33 struct aes_gcm_vectors_st
{
37 const uint8_t *plaintext
;
40 const uint8_t *ciphertext
;
44 struct aes_gcm_vectors_st aes_gcm_vectors
[] = {
47 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
51 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
54 "\x03\x88\xda\xce\x60\xb6\xa3\x92\xf3\x28\xc2\xb9\x71\xb2\xfe\x78",
55 .iv
= "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
57 "\xab\x6e\x47\xd4\x2c\xec\x13\xbd\xf5\x3a\x67\xb2\x12\x57\xbd\xdf"
61 "\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08",
65 "\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 "\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",
69 .iv
= "\xca\xfe\xba\xbe\xfa\xce\xdb\xad\xde\xca\xf8\x88",
70 .tag
= "\x4d\x5c\x2a\xf3\x27\xcd\x64\xa6\x2c\xf3\x5a\xbd\x2b\xa6\xfa\xb4"
74 "\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08",
76 "\xfe\xed\xfa\xce\xde\xad\xbe\xef\xfe\xed\xfa\xce\xde\xad\xbe\xef\xab\xad\xda\xd2",
79 "\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 "\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",
83 .iv
= "\xca\xfe\xba\xbe\xfa\xce\xdb\xad\xde\xca\xf8\x88",
85 "\x5b\xc9\x4f\xbc\x32\x21\xa5\xdb\x94\xfa\xe9\x5a\xe7\x12\x1a\x47"
90 /* Test against AES-GCM test vectors.
92 static int test_crypto(int cfd
)
95 unsigned char tag
[16];
99 struct session_op sess
;
100 struct crypt_auth_op cao
;
102 struct session_info_op siop
;
105 /* Get crypto session for AES128 */
107 fprintf(stdout
, "Tests on AES-GCM vectors: ");
110 i
< sizeof(aes_gcm_vectors
) / sizeof(aes_gcm_vectors
[0]);
112 memset(&sess
, 0, sizeof(sess
));
113 memset(tmp
, 0, sizeof(tmp
));
115 sess
.cipher
= CRYPTO_AES_GCM
;
117 sess
.key
= (void *) aes_gcm_vectors
[i
].key
;
119 if (ioctl(cfd
, CIOCGSESSION
, &sess
)) {
120 my_perror("ioctl(CIOCGSESSION)");
124 memset(&cao
, 0, sizeof(cao
));
128 cao
.iv
= (void *) aes_gcm_vectors
[i
].iv
;
130 cao
.op
= COP_ENCRYPT
;
133 if (aes_gcm_vectors
[i
].auth_size
> 0) {
134 cao
.auth_src
= (void *) aes_gcm_vectors
[i
].auth
;
135 cao
.auth_len
= aes_gcm_vectors
[i
].auth_size
;
138 if (aes_gcm_vectors
[i
].plaintext_size
> 0) {
139 cao
.src
= (void *) aes_gcm_vectors
[i
].plaintext
;
140 cao
.len
= aes_gcm_vectors
[i
].plaintext_size
;
143 if (ioctl(cfd
, CIOCAUTHCRYPT
, &cao
)) {
144 my_perror("ioctl(CIOCAUTHCRYPT)");
148 if (aes_gcm_vectors
[i
].plaintext_size
> 0)
150 (tmp
, aes_gcm_vectors
[i
].ciphertext
,
151 aes_gcm_vectors
[i
].plaintext_size
) != 0) {
153 "AES-GCM test vector %d failed!\n",
156 print_buf("Cipher: ", tmp
, aes_gcm_vectors
[i
].plaintext_size
);
157 print_buf("Expected: ", aes_gcm_vectors
[i
].ciphertext
, aes_gcm_vectors
[i
].plaintext_size
);
162 (&tmp
[cao
.len
- cao
.tag_len
], aes_gcm_vectors
[i
].tag
,
165 "AES-GCM test vector %d failed (tag)!\n",
168 print_buf("Tag: ", tmp
, cao
.tag_len
);
169 print_buf("Expected tag: ",
170 aes_gcm_vectors
[i
].tag
, 16);
175 fprintf(stdout
, "ok\n");
176 fprintf(stdout
, "\n");
178 /* Finish crypto session */
179 if (ioctl(cfd
, CIOCFSESSION
, &sess
.ses
)) {
180 my_perror("ioctl(CIOCFSESSION)");
187 /* Checks if encryption and subsequent decryption
188 * produces the same data.
190 static int test_encrypt_decrypt(int cfd
)
192 char plaintext_raw
[DATA_SIZE
+ 63], *plaintext
;
193 char ciphertext_raw
[DATA_SIZE
+ 63], *ciphertext
;
196 char auth
[AUTH_SIZE
];
197 unsigned char sha1mac
[20];
200 struct session_op sess
;
201 struct crypt_auth_op cao
;
203 struct session_info_op siop
;
206 fprintf(stdout
, "Tests on AES-GCM encryption/decryption: ");
209 memset(&sess
, 0, sizeof(sess
));
210 memset(&cao
, 0, sizeof(cao
));
212 memset(key
, 0x33, sizeof(key
));
213 memset(iv
, 0x03, sizeof(iv
));
214 memset(auth
, 0xf1, sizeof(auth
));
216 /* Get crypto session for AES128 */
217 sess
.cipher
= CRYPTO_AES_GCM
;
218 sess
.keylen
= KEY_SIZE
;
221 if (ioctl(cfd
, CIOCGSESSION
, &sess
)) {
222 my_perror("ioctl(CIOCGSESSION)");
228 if (ioctl(cfd
, CIOCGSESSINFO
, &siop
)) {
229 my_perror("ioctl(CIOCGSESSINFO)");
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);
236 (char *) (((unsigned long) plaintext_raw
+ siop
.alignmask
) &
239 (char *) (((unsigned long) ciphertext_raw
+ siop
.alignmask
) &
242 plaintext
= plaintext_raw
;
243 ciphertext
= ciphertext_raw
;
245 memset(plaintext
, 0x15, DATA_SIZE
);
247 /* Encrypt data.in to data.encrypted */
250 cao
.auth_len
= sizeof(auth
);
253 cao
.dst
= ciphertext
;
256 cao
.op
= COP_ENCRYPT
;
259 if (ioctl(cfd
, CIOCAUTHCRYPT
, &cao
)) {
260 my_perror("ioctl(CIOCAUTHCRYPT)");
265 //printf("Original plaintext size: %d, ciphertext: %d\n", DATA_SIZE, enc_len);
267 if (ioctl(cfd
, CIOCFSESSION
, &sess
.ses
)) {
268 my_perror("ioctl(CIOCFSESSION)");
272 /* Get crypto session for AES128 */
273 memset(&sess
, 0, sizeof(sess
));
274 sess
.cipher
= CRYPTO_AES_GCM
;
275 sess
.keylen
= KEY_SIZE
;
278 if (ioctl(cfd
, CIOCGSESSION
, &sess
)) {
279 my_perror("ioctl(CIOCGSESSION)");
283 /* Decrypt data.encrypted to data.decrypted */
286 cao
.auth_len
= sizeof(auth
);
288 cao
.src
= ciphertext
;
289 cao
.dst
= ciphertext
;
292 cao
.op
= COP_DECRYPT
;
295 if (ioctl(cfd
, CIOCAUTHCRYPT
, &cao
)) {
296 my_perror("ioctl(CIOCAUTHCRYPT)");
300 if (cao
.len
!= DATA_SIZE
) {
301 fprintf(stderr
, "decrypted data size incorrect!\n");
305 /* Verify the result */
306 if (memcmp(plaintext
, ciphertext
, DATA_SIZE
) != 0) {
309 "FAIL: Decrypted data are different from the input data.\n");
310 printf("plaintext:");
311 for (i
= 0; i
< DATA_SIZE
; i
++) {
314 printf("%02x ", plaintext
[i
]);
316 printf("ciphertext:");
317 for (i
= 0; i
< DATA_SIZE
; i
++) {
320 printf("%02x ", ciphertext
[i
]);
326 /* Finish crypto session */
327 if (ioctl(cfd
, CIOCFSESSION
, &sess
.ses
)) {
328 my_perror("ioctl(CIOCFSESSION)");
332 fprintf(stdout
, "ok\n");
333 fprintf(stdout
, "\n");
338 static int test_encrypt_decrypt_error(int cfd
, int err
)
340 char plaintext_raw
[DATA_SIZE
+ 63], *plaintext
;
341 char ciphertext_raw
[DATA_SIZE
+ 63], *ciphertext
;
344 char auth
[AUTH_SIZE
];
347 struct session_op sess
;
349 struct crypt_auth_op cao
;
351 struct session_info_op siop
;
354 fprintf(stdout
, "Tests on AES-GCM tag verification: ");
357 memset(&sess
, 0, sizeof(sess
));
358 memset(&cao
, 0, sizeof(cao
));
359 memset(&co
, 0, sizeof(co
));
361 memset(key
, 0x33, sizeof(key
));
362 memset(iv
, 0x03, sizeof(iv
));
363 memset(auth
, 0xf1, sizeof(auth
));
365 /* Get crypto session for AES128 */
366 sess
.cipher
= CRYPTO_AES_CBC
;
367 sess
.keylen
= KEY_SIZE
;
370 sess
.mac
= CRYPTO_SHA1_HMAC
;
374 "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
376 if (ioctl(cfd
, CIOCGSESSION
, &sess
)) {
377 my_perror("ioctl(CIOCGSESSION)");
382 if (ioctl(cfd
, CIOCGSESSINFO
, &siop
)) {
383 my_perror("ioctl(CIOCGSESSINFO)");
386 // printf("requested cipher CRYPTO_AES_CBC/HMAC-SHA1, got %s with driver %s\n",
387 // siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name);
390 (char *) (((unsigned long) plaintext_raw
+ siop
.alignmask
) &
393 (char *) (((unsigned long) ciphertext_raw
+ siop
.alignmask
) &
396 plaintext
= plaintext_raw
;
397 ciphertext
= ciphertext_raw
;
399 memset(plaintext
, 0x15, DATA_SIZE
);
401 /* Encrypt data.in to data.encrypted */
404 cao
.auth_len
= sizeof(auth
);
407 cao
.dst
= ciphertext
;
409 cao
.op
= COP_ENCRYPT
;
410 cao
.flags
= COP_FLAG_AEAD_TLS_TYPE
;
412 if (ioctl(cfd
, CIOCAUTHCRYPT
, &cao
)) {
413 my_perror("ioctl(CIOCAUTHCRYPT)");
418 //printf("Original plaintext size: %d, ciphertext: %d\n", DATA_SIZE, enc_len);
420 if (ioctl(cfd
, CIOCFSESSION
, &sess
.ses
)) {
421 my_perror("ioctl(CIOCFSESSION)");
425 /* Get crypto session for AES128 */
426 memset(&sess
, 0, sizeof(sess
));
427 sess
.cipher
= CRYPTO_AES_CBC
;
428 sess
.keylen
= KEY_SIZE
;
430 sess
.mac
= CRYPTO_SHA1_HMAC
;
434 "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
436 if (ioctl(cfd
, CIOCGSESSION
, &sess
)) {
437 my_perror("ioctl(CIOCGSESSION)");
446 /* Decrypt data.encrypted to data.decrypted */
449 cao
.auth_len
= sizeof(auth
);
451 cao
.src
= ciphertext
;
452 cao
.dst
= ciphertext
;
454 cao
.op
= COP_DECRYPT
;
455 cao
.flags
= COP_FLAG_AEAD_TLS_TYPE
;
456 if (ioctl(cfd
, CIOCAUTHCRYPT
, &cao
)) {
457 if (ioctl(cfd
, CIOCFSESSION
, &sess
.ses
)) {
458 my_perror("ioctl(CIOCFSESSION)");
462 fprintf(stdout
, "ok\n");
463 fprintf(stdout
, "\n");
467 /* Finish crypto session */
468 if (ioctl(cfd
, CIOCFSESSION
, &sess
.ses
)) {
469 my_perror("ioctl(CIOCFSESSION)");
474 fprintf(stderr
, "Modification to ciphertext was not detected\n");
480 int fd
= -1, cfd
= -1;
482 /* Open the crypto device */
483 fd
= open("/dev/crypto", O_RDWR
, 0);
485 my_perror("open(/dev/crypto)");
489 /* Clone file descriptor */
490 if (ioctl(fd
, CRIOGET
, &cfd
)) {
491 my_perror("ioctl(CRIOGET)");
495 /* Set close-on-exec (not really neede here) */
496 if (fcntl(cfd
, F_SETFD
, 1) == -1) {
497 my_perror("fcntl(F_SETFD)");
501 /* Run the test itself */
503 if (test_crypto(cfd
))
506 if (test_encrypt_decrypt(cfd
))
509 if (test_encrypt_decrypt_error(cfd
, 0))
512 if (test_encrypt_decrypt_error(cfd
, 1))
515 /* Close cloned descriptor */
517 my_perror("close(cfd)");
521 /* Close the original descriptor */
523 my_perror("close(fd)");