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); }
25 static void print_buf(char *desc
, const unsigned char *buf
, int size
)
29 for (i
= 0; i
< size
; i
++) {
30 printf("%.2x", (uint8_t) buf
[i
]);
35 struct aes_gcm_vectors_st
{
39 const uint8_t *plaintext
;
42 const uint8_t *ciphertext
;
46 struct aes_gcm_vectors_st aes_gcm_vectors
[] = {
49 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
53 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
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",
59 "\xab\x6e\x47\xd4\x2c\xec\x13\xbd\xf5\x3a\x67\xb2\x12\x57\xbd\xdf"
63 "\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08",
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",
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"
76 "\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08",
78 "\xfe\xed\xfa\xce\xde\xad\xbe\xef\xfe\xed\xfa\xce\xde\xad\xbe\xef\xab\xad\xda\xd2",
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",
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",
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
)
99 struct session_op sess
;
100 struct crypt_auth_op cao
;
102 /* Get crypto session for AES128 */
105 fprintf(stdout
, "Tests on AES-GCM vectors: ");
109 i
< sizeof(aes_gcm_vectors
) / sizeof(aes_gcm_vectors
[0]);
111 memset(&sess
, 0, sizeof(sess
));
112 memset(tmp
, 0, sizeof(tmp
));
114 sess
.cipher
= CRYPTO_AES_GCM
;
116 sess
.key
= (void *) aes_gcm_vectors
[i
].key
;
118 if (ioctl(cfd
, CIOCGSESSION
, &sess
)) {
119 my_perror("ioctl(CIOCGSESSION)");
123 memset(&cao
, 0, sizeof(cao
));
127 cao
.iv
= (void *) aes_gcm_vectors
[i
].iv
;
129 cao
.op
= COP_ENCRYPT
;
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)");
147 if (aes_gcm_vectors
[i
].plaintext_size
> 0)
149 (tmp
, aes_gcm_vectors
[i
].ciphertext
,
150 aes_gcm_vectors
[i
].plaintext_size
) != 0) {
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
);
161 (&tmp
[cao
.len
- cao
.tag_len
], aes_gcm_vectors
[i
].tag
,
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);
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)");
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
;
198 char auth
[AUTH_SIZE
];
201 struct session_op sess
;
202 struct crypt_auth_op cao
;
203 struct session_info_op siop
;
206 fprintf(stdout
, "Tests on AES-GCM encryption/decryption: ");
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
;
222 if (ioctl(cfd
, CIOCGSESSION
, &sess
)) {
223 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 memset(plaintext
, 0x15, DATA_SIZE
);
244 /* Encrypt data.in to data.encrypted */
247 cao
.auth_len
= sizeof(auth
);
250 cao
.dst
= ciphertext
;
253 cao
.op
= COP_ENCRYPT
;
256 if (ioctl(cfd
, CIOCAUTHCRYPT
, &cao
)) {
257 my_perror("ioctl(CIOCAUTHCRYPT)");
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)");
269 /* Get crypto session for AES128 */
270 memset(&sess
, 0, sizeof(sess
));
271 sess
.cipher
= CRYPTO_AES_GCM
;
272 sess
.keylen
= KEY_SIZE
;
275 if (ioctl(cfd
, CIOCGSESSION
, &sess
)) {
276 my_perror("ioctl(CIOCGSESSION)");
280 /* Decrypt data.encrypted to data.decrypted */
283 cao
.auth_len
= sizeof(auth
);
285 cao
.src
= ciphertext
;
286 cao
.dst
= ciphertext
;
289 cao
.op
= COP_DECRYPT
;
292 if (ioctl(cfd
, CIOCAUTHCRYPT
, &cao
)) {
293 my_perror("ioctl(CIOCAUTHCRYPT)");
297 if (cao
.len
!= DATA_SIZE
) {
298 fprintf(stderr
, "decrypted data size incorrect!\n");
302 /* Verify the result */
303 if (memcmp(plaintext
, ciphertext
, DATA_SIZE
) != 0) {
306 "FAIL: Decrypted data are different from the input data.\n");
307 printf("plaintext:");
308 for (i
= 0; i
< DATA_SIZE
; i
++) {
311 printf("%02x ", plaintext
[i
]);
313 printf("ciphertext:");
314 for (i
= 0; i
< DATA_SIZE
; i
++) {
317 printf("%02x ", ciphertext
[i
]);
323 /* Finish crypto session */
324 if (ioctl(cfd
, CIOCFSESSION
, &sess
.ses
)) {
325 my_perror("ioctl(CIOCFSESSION)");
330 fprintf(stdout
, "ok\n");
331 fprintf(stdout
, "\n");
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
;
343 char auth
[AUTH_SIZE
];
346 struct session_op sess
;
348 struct crypt_auth_op cao
;
349 struct session_info_op siop
;
352 fprintf(stdout
, "Tests on AES-GCM tag verification: ");
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
;
369 sess
.mac
= CRYPTO_SHA1_HMAC
;
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)");
381 if (ioctl(cfd
, CIOCGSESSINFO
, &siop
)) {
382 my_perror("ioctl(CIOCGSESSINFO)");
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);
389 (char *) (((unsigned long) plaintext_raw
+ siop
.alignmask
) &
392 (char *) (((unsigned long) ciphertext_raw
+ siop
.alignmask
) &
395 memset(plaintext
, 0x15, DATA_SIZE
);
396 memcpy(ciphertext
, plaintext
, DATA_SIZE
);
398 /* Encrypt data.in to data.encrypted */
401 cao
.auth_len
= sizeof(auth
);
403 cao
.src
= ciphertext
;
404 cao
.dst
= ciphertext
;
406 cao
.op
= COP_ENCRYPT
;
407 cao
.flags
= COP_FLAG_AEAD_TLS_TYPE
;
409 if (ioctl(cfd
, CIOCAUTHCRYPT
, &cao
)) {
410 my_perror("ioctl(CIOCAUTHCRYPT)");
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)");
422 /* Get crypto session for AES128 */
423 memset(&sess
, 0, sizeof(sess
));
424 sess
.cipher
= CRYPTO_AES_CBC
;
425 sess
.keylen
= KEY_SIZE
;
427 sess
.mac
= CRYPTO_SHA1_HMAC
;
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)");
443 /* Decrypt data.encrypted to data.decrypted */
446 cao
.auth_len
= sizeof(auth
);
448 cao
.src
= ciphertext
;
449 cao
.dst
= ciphertext
;
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)");
460 fprintf(stdout
, "ok\n");
461 fprintf(stdout
, "\n");
466 /* Finish crypto session */
467 if (ioctl(cfd
, CIOCFSESSION
, &sess
.ses
)) {
468 my_perror("ioctl(CIOCFSESSION)");
473 fprintf(stderr
, "Modification to ciphertext was not detected\n");
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);
486 my_perror("open(/dev/crypto)");
490 /* Clone file descriptor */
491 if (ioctl(fd
, CRIOGET
, &cfd
)) {
492 my_perror("ioctl(CRIOGET)");
496 /* Set close-on-exec (not really neede here) */
497 if (fcntl(cfd
, F_SETFD
, 1) == -1) {
498 my_perror("fcntl(F_SETFD)");
502 /* Run the test itself */
504 if (test_crypto(cfd
))
507 if (test_encrypt_decrypt(cfd
))
510 if (test_encrypt_decrypt_error(cfd
, 0))
513 if (test_encrypt_decrypt_error(cfd
, 1))
516 /* Close cloned descriptor */
518 my_perror("close(cfd)");
522 /* Close the original descriptor */
524 my_perror("close(fd)");