corrected copyright notices
[gnutls.git] / lib / accelerated / cryptodev-gcm.c
blobfcd75bbcb4b5ded44256ca1778e1886050aaa99f
1 /*
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
31 #include <fcntl.h>
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
37 #endif
39 #ifndef EALG_MAX_BLOCK_LEN
40 #define EALG_MAX_BLOCK_LEN 16
41 #endif
44 #ifdef CIOCAUTHCRYPT
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];
55 void* auth_data;
56 unsigned int auth_data_size;
58 int op; /* whether encryption op has been executed */
60 int cfd;
63 static void
64 aes_gcm_deinit (void *_ctx)
66 struct cryptodev_gcm_ctx *ctx = _ctx;
68 ioctl (ctx->cfd, CIOCFSESSION, &ctx->sess.ses);
69 gnutls_free (ctx);
72 static const int cipher_map[] = {
73 [GNUTLS_CIPHER_AES_128_GCM] = CRYPTO_AES_GCM,
74 [GNUTLS_CIPHER_AES_256_GCM] = CRYPTO_AES_GCM,
77 static int
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));
83 if (*_ctx == NULL)
85 gnutls_assert ();
86 return GNUTLS_E_MEMORY_ERROR;
90 ctx = *_ctx;
92 ctx->cfd = _gnutls_cryptodev_fd;
93 ctx->sess.cipher = cipher_map[algorithm];
94 ctx->cryp.iv = ctx->iv;
96 return 0;
99 static int
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))
109 gnutls_assert ();
110 return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
112 ctx->cryp.ses = ctx->sess.ses;
114 return 0;
117 static int
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;
129 return 0;
132 static int
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
139 * encrypted data.
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;
146 ctx->cryp.dst = dst;
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))
154 gnutls_assert ();
155 return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
158 ctx->cryp.auth_len = 0;
159 ctx->op = 1;
160 memcpy(ctx->tag, &((uint8_t*)dst)[src_size], GCM_BLOCK_SIZE);
161 return 0;
164 static int
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
171 * encrypted data.
173 ctx->cryp.len = src_size + GCM_BLOCK_SIZE;
174 ctx->cryp.src = (void *) src;
175 ctx->cryp.dst = dst;
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))
183 gnutls_assert ();
184 return GNUTLS_E_CRYPTODEV_IOCTL_ERROR;
187 ctx->cryp.auth_len = 0;
188 ctx->op = 1;
189 memcpy(ctx->tag, &((uint8_t*)dst)[src_size], GCM_BLOCK_SIZE);
190 return 0;
193 static int
194 aes_gcm_auth (void *_ctx, const void *src, size_t src_size)
196 struct cryptodev_gcm_ctx *ctx = _ctx;
198 ctx->op = 0;
199 ctx->auth_data = (void*)src;
200 ctx->auth_data_size = src_size;
202 return 0;
205 static void
206 aes_gcm_tag (void *_ctx, void *tag, size_t tagsize)
208 struct cryptodev_gcm_ctx *ctx = _ctx;
210 if (ctx->op == 0)
212 ctx->cryp.len = 0;
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))
222 gnutls_assert ();
223 return;
227 memcpy(tag, ctx->tag, tagsize);
228 ctx->op = 0;
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,
238 .tag = aes_gcm_tag,
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];
247 unsigned int i;
248 int ret;
249 #ifdef CIOCGSESSINFO
250 struct session_info_op siop;
252 memset(&siop, 0, sizeof(siop));
253 #endif
255 memset (&sess, 0, sizeof (sess));
257 for (i = 0; i < sizeof (cipher_map) / sizeof (cipher_map[0]);
258 i++)
260 if (cipher_map[i] == 0)
261 continue;
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);
266 sess.key = fake_key;
268 if (ioctl (cfd, CIOCGSESSION, &sess))
270 continue;
273 #ifdef CIOCGSESSINFO
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);
280 continue;
283 #endif
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);
290 if (ret < 0)
292 gnutls_assert ();
293 return ret;
298 return 0;
301 #endif /* CIOCAUTHCRYPT */
303 #endif /* ENABLE_CRYPTODEV */