2 * Copyright (C) 2012 Free Software Foundation, Inc.
4 * Author: Nikos Mavrogiannopoulos
6 * This file is part of GnuTLS.
8 * The GnuTLS is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 3 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include <gnutls_errors.h>
24 #include <gnutls_int.h>
25 #include <gnutls/crypto.h>
26 #include <gnutls_errors.h>
27 #include <accelerated/cryptodev.h>
29 #ifdef ENABLE_CRYPTODEV
32 #include <sys/ioctl.h>
33 #include <crypto/cryptodev.h>
35 #ifndef CRYPTO_CIPHER_MAX_KEY_LEN
36 #define CRYPTO_CIPHER_MAX_KEY_LEN 64
39 #ifndef EALG_MAX_BLOCK_LEN
40 #define EALG_MAX_BLOCK_LEN 16
46 #define GCM_BLOCK_SIZE 16
48 struct cryptodev_gcm_ctx
50 struct session_op sess
;
51 struct crypt_auth_op cryp
;
52 uint8_t iv
[GCM_BLOCK_SIZE
];
53 uint8_t tag
[GCM_BLOCK_SIZE
];
56 unsigned int auth_data_size
;
58 int op
; /* whether encryption op has been executed */
64 aes_gcm_deinit (void *_ctx
)
66 struct cryptodev_gcm_ctx
*ctx
= _ctx
;
68 ioctl (ctx
->cfd
, CIOCFSESSION
, &ctx
->sess
.ses
);
72 static const int cipher_map
[] = {
73 [GNUTLS_CIPHER_AES_128_GCM
] = CRYPTO_AES_GCM
,
74 [GNUTLS_CIPHER_AES_256_GCM
] = CRYPTO_AES_GCM
,
78 aes_gcm_cipher_init (gnutls_cipher_algorithm_t algorithm
, void **_ctx
, int enc
)
80 struct cryptodev_gcm_ctx
*ctx
;
82 *_ctx
= gnutls_calloc (1, sizeof (struct cryptodev_gcm_ctx
));
86 return GNUTLS_E_MEMORY_ERROR
;
92 ctx
->cfd
= _gnutls_cryptodev_fd
;
93 ctx
->sess
.cipher
= cipher_map
[algorithm
];
94 ctx
->cryp
.iv
= ctx
->iv
;
100 aes_gcm_cipher_setkey (void *_ctx
, const void *userkey
, size_t keysize
)
102 struct cryptodev_gcm_ctx
*ctx
= _ctx
;
104 ctx
->sess
.keylen
= keysize
;
105 ctx
->sess
.key
= (void*)userkey
;
107 if (ioctl (ctx
->cfd
, CIOCGSESSION
, &ctx
->sess
))
110 return GNUTLS_E_CRYPTODEV_IOCTL_ERROR
;
112 ctx
->cryp
.ses
= ctx
->sess
.ses
;
118 aes_gcm_setiv (void *_ctx
, const void *iv
, size_t iv_size
)
120 struct cryptodev_gcm_ctx
*ctx
= _ctx
;
122 if (iv_size
!= GCM_BLOCK_SIZE
- 4)
123 return GNUTLS_E_INVALID_REQUEST
;
125 memcpy (ctx
->iv
, iv
, GCM_BLOCK_SIZE
- 4);
127 ctx
->cryp
.iv
= (void*)ctx
->iv
;
133 aes_gcm_encrypt (void *_ctx
, const void *src
, size_t src_size
,
134 void *dst
, size_t dst_size
)
136 struct cryptodev_gcm_ctx
*ctx
= _ctx
;
138 /* the GCM in kernel will place the tag after the
141 if (dst_size
< src_size
+ GCM_BLOCK_SIZE
)
142 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST
);
144 ctx
->cryp
.len
= src_size
;
145 ctx
->cryp
.src
= (void *) src
;
147 ctx
->cryp
.op
= COP_ENCRYPT
;
149 ctx
->cryp
.auth_len
= ctx
->auth_data_size
;
150 ctx
->cryp
.auth_src
= ctx
->auth_data
;
152 if (ioctl (ctx
->cfd
, CIOCAUTHCRYPT
, &ctx
->cryp
))
155 return GNUTLS_E_CRYPTODEV_IOCTL_ERROR
;
158 ctx
->cryp
.auth_len
= 0;
160 memcpy(ctx
->tag
, &((uint8_t*)dst
)[src_size
], GCM_BLOCK_SIZE
);
165 aes_gcm_decrypt (void *_ctx
, const void *src
, size_t src_size
,
166 void *dst
, size_t dst_size
)
168 struct cryptodev_gcm_ctx
*ctx
= _ctx
;
170 /* the GCM in kernel will place the tag after the
173 ctx
->cryp
.len
= src_size
+ GCM_BLOCK_SIZE
;
174 ctx
->cryp
.src
= (void *) src
;
176 ctx
->cryp
.op
= COP_DECRYPT
;
178 ctx
->cryp
.auth_len
= ctx
->auth_data_size
;
179 ctx
->cryp
.auth_src
= ctx
->auth_data
;
181 if (ioctl (ctx
->cfd
, CIOCAUTHCRYPT
, &ctx
->cryp
))
184 return GNUTLS_E_CRYPTODEV_IOCTL_ERROR
;
187 ctx
->cryp
.auth_len
= 0;
189 memcpy(ctx
->tag
, &((uint8_t*)dst
)[src_size
], GCM_BLOCK_SIZE
);
194 aes_gcm_auth (void *_ctx
, const void *src
, size_t src_size
)
196 struct cryptodev_gcm_ctx
*ctx
= _ctx
;
199 ctx
->auth_data
= (void*)src
;
200 ctx
->auth_data_size
= src_size
;
206 aes_gcm_tag (void *_ctx
, void *tag
, size_t tagsize
)
208 struct cryptodev_gcm_ctx
*ctx
= _ctx
;
213 ctx
->cryp
.src
= NULL
;
214 ctx
->cryp
.dst
= ctx
->tag
;
215 ctx
->cryp
.op
= COP_ENCRYPT
;
217 ctx
->cryp
.auth_len
= ctx
->auth_data_size
;
218 ctx
->cryp
.auth_src
= ctx
->auth_data
;
220 if (ioctl (ctx
->cfd
, CIOCAUTHCRYPT
, &ctx
->cryp
))
227 memcpy(tag
, ctx
->tag
, tagsize
);
231 static const gnutls_crypto_cipher_st cipher_struct
= {
232 .init
= aes_gcm_cipher_init
,
233 .setkey
= aes_gcm_cipher_setkey
,
234 .setiv
= aes_gcm_setiv
,
235 .encrypt
= aes_gcm_encrypt
,
236 .decrypt
= aes_gcm_decrypt
,
237 .deinit
= aes_gcm_deinit
,
239 .auth
= aes_gcm_auth
,
243 _cryptodev_register_gcm_crypto (int cfd
)
245 struct session_op sess
;
246 uint8_t fake_key
[CRYPTO_CIPHER_MAX_KEY_LEN
];
250 struct session_info_op siop
;
252 memset(&siop
, 0, sizeof(siop
));
255 memset (&sess
, 0, sizeof (sess
));
257 for (i
= 0; i
< sizeof (cipher_map
) / sizeof (cipher_map
[0]);
260 if (cipher_map
[i
] == 0)
263 /* test if a cipher is support it and if yes register it */
264 sess
.cipher
= cipher_map
[i
];
265 sess
.keylen
= gnutls_cipher_get_key_size (i
);
268 if (ioctl (cfd
, CIOCGSESSION
, &sess
))
274 siop
.ses
= sess
.ses
; /* do not register ciphers that are not hw accelerated */
275 if (ioctl(cfd
, CIOCGSESSINFO
, &siop
) == 0)
277 if (!(siop
.flags
& SIOP_FLAG_KERNEL_DRIVER_ONLY
))
279 ioctl (cfd
, CIOCFSESSION
, &sess
.ses
);
285 ioctl (cfd
, CIOCFSESSION
, &sess
.ses
);
287 _gnutls_debug_log ("/dev/crypto: registering: %s\n",
288 gnutls_cipher_get_name (i
));
289 ret
= gnutls_crypto_single_cipher_register (i
, 90, &cipher_struct
);
301 #endif /* CIOCAUTHCRYPT */
303 #endif /* ENABLE_CRYPTODEV */