corrected bug when having additional data in TLS.
[cryptodev-linux.git] / examples / cipher-aead.c
blobd04c6af537ce78d91869c271ad131a5bc2f46658
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+11)
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;
28 int i;
30 memset(&sess, 0, sizeof(sess));
31 memset(&cryp, 0, sizeof(cryp));
33 sess.cipher = 0;
34 sess.mac = CRYPTO_SHA1_HMAC;
35 sess.mackeylen = key_size;
36 sess.mackey = key;
37 if (ioctl(cfd, CIOCGSESSION, &sess)) {
38 perror("ioctl(CIOCGSESSION)");
39 return 1;
42 /* Encrypt data.in to data.encrypted */
43 cryp.ses = sess.ses;
44 cryp.len = data1_size;
45 cryp.src = data1;
46 cryp.dst = NULL;
47 cryp.iv = NULL;
48 cryp.mac = mac;
49 cryp.op = COP_ENCRYPT;
50 cryp.flags = COP_FLAG_UPDATE;
51 if (ioctl(cfd, CIOCCRYPT, &cryp)) {
52 perror("ioctl(CIOCCRYPT)");
53 return 1;
56 cryp.ses = sess.ses;
57 cryp.len = data2_size;
58 cryp.src = data2;
59 cryp.dst = NULL;
60 cryp.iv = NULL;
61 cryp.mac = mac;
62 cryp.op = COP_ENCRYPT;
63 cryp.flags = COP_FLAG_FINAL;
64 if (ioctl(cfd, CIOCCRYPT, &cryp)) {
65 perror("ioctl(CIOCCRYPT)");
66 return 1;
69 /* Finish crypto session */
70 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
71 perror("ioctl(CIOCFSESSION)");
72 return 1;
75 return 0;
78 static void print_buf(char* desc, unsigned char* buf, int size)
80 int i;
81 fputs(desc, stdout);
82 for (i=0;i<size;i++) {
83 printf("%.2x", (uint8_t)buf[i]);
85 fputs("\n", stdout);
88 static int
89 test_crypto(int cfd)
91 char plaintext_raw[DATA_SIZE + 63], *plaintext;
92 char ciphertext_raw[DATA_SIZE + 63], *ciphertext;
93 char iv[BLOCK_SIZE];
94 char key[KEY_SIZE];
95 char auth[AUTH_SIZE];
96 unsigned char sha1mac[20];
97 int pad, i;
99 struct session_op sess;
100 struct crypt_op co;
101 struct crypt_auth_op cao;
102 #ifdef CIOCGSESSINFO
103 struct session_info_op siop;
104 #endif
106 memset(&sess, 0, sizeof(sess));
107 memset(&cao, 0, sizeof(cao));
108 memset(&co, 0, sizeof(co));
110 memset(key,0x33, sizeof(key));
111 memset(iv, 0x03, sizeof(iv));
112 memset(auth, 0xf1, sizeof(auth));
114 /* Get crypto session for AES128 */
115 sess.cipher = CRYPTO_AES_CBC;
116 sess.keylen = KEY_SIZE;
117 sess.key = key;
119 sess.mac = CRYPTO_SHA1_HMAC;
120 sess.mackeylen = 16;
121 sess.mackey = (uint8_t*)"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
123 if (ioctl(cfd, CIOCGSESSION, &sess)) {
124 perror("ioctl(CIOCGSESSION)");
125 return 1;
128 #ifdef CIOCGSESSINFO
129 siop.ses = sess.ses;
130 if (ioctl(cfd, CIOCGSESSINFO, &siop)) {
131 perror("ioctl(CIOCGSESSINFO)");
132 return 1;
134 printf("requested cipher CRYPTO_AES_CBC/HMAC-SHA1, got %s with driver %s\n",
135 siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name);
137 plaintext = (char *)(((unsigned long)plaintext_raw + siop.alignmask) & ~siop.alignmask);
138 ciphertext = (char *)(((unsigned long)ciphertext_raw + siop.alignmask) & ~siop.alignmask);
139 #else
140 plaintext = plaintext_raw;
141 ciphertext = ciphertext_raw;
142 #endif
143 memset(plaintext, 0x15, DATA_SIZE);
145 if (get_sha1_hmac(cfd, sess.mackey, sess.mackeylen, auth, sizeof(auth), plaintext, DATA_SIZE, sha1mac) != 0) {
146 fprintf(stderr, "SHA1 MAC failed\n");
147 return 1;
150 //memcpy(ciphertext, plaintext, DATA_SIZE);
152 /* Encrypt data.in to data.encrypted */
153 cao.ses = sess.ses;
154 cao.auth_src = auth;
155 cao.auth_len = sizeof(auth);
156 cao.len = DATA_SIZE;
157 cao.src = plaintext;
158 cao.dst = ciphertext;
159 cao.iv = iv;
160 cao.op = COP_ENCRYPT;
161 cao.flags = COP_FLAG_AEAD_TLS_TYPE;
163 if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) {
164 perror("ioctl(CIOCAUTHCRYPT)");
165 return 1;
168 printf("Original plaintext size: %d, ciphertext: %d\n", DATA_SIZE, cao.len);
170 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
171 perror("ioctl(CIOCFSESSION)");
172 return 1;
175 /* Get crypto session for AES128 */
176 memset(&sess, 0, sizeof(sess));
177 sess.cipher = CRYPTO_AES_CBC;
178 sess.keylen = KEY_SIZE;
179 sess.key = key;
181 if (ioctl(cfd, CIOCGSESSION, &sess)) {
182 perror("ioctl(CIOCGSESSION)");
183 return 1;
186 /* Decrypt data.encrypted to data.decrypted */
187 co.ses = sess.ses;
188 co.len = cao.len;
189 co.src = ciphertext;
190 co.dst = ciphertext;
191 co.iv = iv;
192 co.op = COP_DECRYPT;
193 if (ioctl(cfd, CIOCCRYPT, &co)) {
194 perror("ioctl(CIOCCRYPT)");
195 return 1;
198 /* Verify the result */
199 if (memcmp(plaintext, ciphertext, DATA_SIZE) != 0) {
200 int i;
201 fprintf(stderr,
202 "FAIL: Decrypted data are different from the input data.\n");
203 printf("plaintext:");
204 for (i = 0; i < DATA_SIZE; i++) {
205 if ((i % 30) == 0)
206 printf("\n");
207 printf("%02x ", plaintext[i]);
209 printf("ciphertext:");
210 for (i = 0; i < DATA_SIZE; i++) {
211 if ((i % 30) == 0)
212 printf("\n");
213 printf("%02x ", ciphertext[i]);
215 printf("\n");
216 return 1;
219 if (memcmp(&ciphertext[cao.len-MAC_SIZE-1], sha1mac, 20) != 0) {
220 fprintf(stderr, "AEAD SHA1 MAC does not match plain MAC\n");
221 print_buf("SHA1: ", sha1mac, 20);
222 print_buf("SHA1-TLS: ", &ciphertext[cao.len-MAC_SIZE-1], 20);
223 return 1;
226 pad = ciphertext[cao.len-1];
228 for (i=0;i<pad;i++)
229 if (ciphertext[cao.len-MAC_SIZE-1-i] != pad) {
230 fprintf(stderr, "Pad does not match (expected %d)\n", pad);
231 print_buf("PAD", &ciphertext[cao.len-MAC_SIZE-1-pad], pad);
232 return 1;
235 printf("Test passed\n");
238 /* Finish crypto session */
239 if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
240 perror("ioctl(CIOCFSESSION)");
241 return 1;
244 return 0;
248 main()
250 int fd = -1, cfd = -1;
252 /* Open the crypto device */
253 fd = open("/dev/crypto", O_RDWR, 0);
254 if (fd < 0) {
255 perror("open(/dev/crypto)");
256 return 1;
259 /* Clone file descriptor */
260 if (ioctl(fd, CRIOGET, &cfd)) {
261 perror("ioctl(CRIOGET)");
262 return 1;
265 /* Set close-on-exec (not really neede here) */
266 if (fcntl(cfd, F_SETFD, 1) == -1) {
267 perror("fcntl(F_SETFD)");
268 return 1;
271 /* Run the test itself */
273 if (test_crypto(cfd))
274 return 1;
276 /* Close cloned descriptor */
277 if (close(cfd)) {
278 perror("close(cfd)");
279 return 1;
282 /* Close the original descriptor */
283 if (close(fd)) {
284 perror("close(fd)");
285 return 1;
288 return 0;