/src/gnutls/lib/accelerated/x86/aes-ccm-x86-aesni.c
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /*  | 
2  |  |  * Copyright (C) 2014-2015 Red Hat, Inc.  | 
3  |  |  *  | 
4  |  |  * Author: Nikos Mavrogiannopoulos  | 
5  |  |  *  | 
6  |  |  * This file is part of GnuTLS.  | 
7  |  |  *  | 
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 2.1 of  | 
11  |  |  * the License, or (at your option) any later version.  | 
12  |  |  *  | 
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.  | 
17  |  |  *  | 
18  |  |  * You should have received a copy of the GNU Lesser General Public License  | 
19  |  |  * along with this program.  If not, see <https://www.gnu.org/licenses/>  | 
20  |  |  *  | 
21  |  |  */  | 
22  |  |  | 
23  |  | /*  | 
24  |  |  * The following code is an implementation of the AES-128-CCM cipher  | 
25  |  |  * using AESNI (without PCLMUL)  | 
26  |  |  */  | 
27  |  |  | 
28  |  | #include "errors.h"  | 
29  |  | #include "gnutls_int.h"  | 
30  |  |  | 
31  |  | #ifdef HAVE_LIBNETTLE  | 
32  |  |  | 
33  |  | #include <gnutls/crypto.h>  | 
34  |  | #include "errors.h"  | 
35  |  | #include "aes-x86.h"  | 
36  |  | #include "x86-common.h"  | 
37  |  | #include <byteswap.h>  | 
38  |  | #include <nettle/ccm.h>  | 
39  |  | #include "aes-x86.h"  | 
40  |  | #include "fips.h"  | 
41  |  |  | 
42  |  | typedef struct ccm_x86_aes_ctx { | 
43  |  |   AES_KEY key;  | 
44  |  | } ccm_x86_aes_ctx;  | 
45  |  |  | 
46  |  | /* CCM mode   | 
47  |  |  */  | 
48  |  | static void x86_aes_encrypt(const void *_ctx, size_t length, uint8_t *dst,  | 
49  |  |           const uint8_t *src)  | 
50  | 0  | { | 
51  | 0  |   AES_KEY *ctx = (void *)_ctx;  | 
52  | 0  |   aesni_ecb_encrypt(src, dst, length, ctx, 1);  | 
53  | 0  | }  | 
54  |  |  | 
55  |  | static int aes_ccm_cipher_init(gnutls_cipher_algorithm_t algorithm, void **ctx,  | 
56  |  |              int enc)  | 
57  | 0  | { | 
58  |  |   /* we use key size to distinguish */  | 
59  | 0  |   if (algorithm != GNUTLS_CIPHER_AES_128_CCM &&  | 
60  | 0  |       algorithm != GNUTLS_CIPHER_AES_256_CCM &&  | 
61  | 0  |       algorithm != GNUTLS_CIPHER_AES_128_CCM_8 &&  | 
62  | 0  |       algorithm != GNUTLS_CIPHER_AES_256_CCM_8)  | 
63  | 0  |     return GNUTLS_E_INVALID_REQUEST;  | 
64  |  |  | 
65  | 0  |   *ctx = gnutls_calloc(1, sizeof(ccm_x86_aes_ctx));  | 
66  | 0  |   if (*ctx == NULL) { | 
67  | 0  |     gnutls_assert();  | 
68  | 0  |     return GNUTLS_E_MEMORY_ERROR;  | 
69  | 0  |   }  | 
70  |  |  | 
71  | 0  |   return 0;  | 
72  | 0  | }  | 
73  |  |  | 
74  |  | static int aes_ccm_cipher_setkey(void *_ctx, const void *key, size_t length)  | 
75  | 0  | { | 
76  | 0  |   struct ccm_x86_aes_ctx *ctx = _ctx;  | 
77  | 0  |   aesni_set_encrypt_key(key, length * 8, &ctx->key);  | 
78  |  | 
  | 
79  | 0  |   return 0;  | 
80  | 0  | }  | 
81  |  |  | 
82  |  | static int aes_ccm_aead_encrypt(void *_ctx, const void *nonce,  | 
83  |  |         size_t nonce_size, const void *auth,  | 
84  |  |         size_t auth_size, size_t tag_size,  | 
85  |  |         const void *plain, size_t plain_size,  | 
86  |  |         void *encr, size_t encr_size)  | 
87  | 0  | { | 
88  | 0  |   struct ccm_x86_aes_ctx *ctx = _ctx;  | 
89  |  |   /* proper AEAD cipher */  | 
90  |  | 
  | 
91  | 0  |   if (unlikely(encr_size < plain_size + tag_size))  | 
92  | 0  |     return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);  | 
93  |  |  | 
94  |  |   /* SP800-38C A.1 says Tlen must be a multiple of 16 between 32  | 
95  |  |    * and 128.  | 
96  |  |    */  | 
97  | 0  |   switch (tag_size) { | 
98  | 0  |   case 4:  | 
99  | 0  |   case 6:  | 
100  |  |     /* SP800-38C B.2 says Tlen smaller than 64 should not be used  | 
101  |  |      * under sufficient restriction. We simply allow those for now.  | 
102  |  |      */  | 
103  | 0  |     FALLTHROUGH;  | 
104  | 0  |   case 8:  | 
105  | 0  |   case 10:  | 
106  | 0  |   case 12:  | 
107  | 0  |   case 14:  | 
108  | 0  |   case 16:  | 
109  | 0  |     break;  | 
110  | 0  |   default:  | 
111  | 0  |     if (_gnutls_fips_mode_enabled()) { | 
112  | 0  |       _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);  | 
113  | 0  |       return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);  | 
114  | 0  |     }  | 
115  | 0  |     break;  | 
116  | 0  |   }  | 
117  |  |  | 
118  | 0  |   ccm_encrypt_message(&ctx->key, x86_aes_encrypt, nonce_size, nonce,  | 
119  | 0  |           auth_size, auth, tag_size, plain_size + tag_size,  | 
120  | 0  |           encr, plain);  | 
121  | 0  |   return 0;  | 
122  | 0  | }  | 
123  |  |  | 
124  |  | static int aes_ccm_aead_decrypt(void *_ctx, const void *nonce,  | 
125  |  |         size_t nonce_size, const void *auth,  | 
126  |  |         size_t auth_size, size_t tag_size,  | 
127  |  |         const void *encr, size_t encr_size, void *plain,  | 
128  |  |         size_t plain_size)  | 
129  | 0  | { | 
130  | 0  |   struct ccm_x86_aes_ctx *ctx = _ctx;  | 
131  | 0  |   int ret;  | 
132  |  | 
  | 
133  | 0  |   if (unlikely(encr_size < tag_size))  | 
134  | 0  |     return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);  | 
135  |  |  | 
136  | 0  |   if (unlikely(plain_size < encr_size - tag_size))  | 
137  | 0  |     return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);  | 
138  |  |  | 
139  |  |   /* SP800-38C A.1 says Tlen must be a multiple of 16 between 32  | 
140  |  |    * and 128.  | 
141  |  |    */  | 
142  | 0  |   switch (tag_size) { | 
143  | 0  |   case 4:  | 
144  | 0  |   case 6:  | 
145  |  |     /* SP800-38C B.2 says Tlen smaller than 64 should not be used  | 
146  |  |      * under sufficient restriction. We simply allow those for now.  | 
147  |  |      */  | 
148  | 0  |     FALLTHROUGH;  | 
149  | 0  |   case 8:  | 
150  | 0  |   case 10:  | 
151  | 0  |   case 12:  | 
152  | 0  |   case 14:  | 
153  | 0  |   case 16:  | 
154  | 0  |     break;  | 
155  | 0  |   default:  | 
156  | 0  |     if (_gnutls_fips_mode_enabled()) { | 
157  | 0  |       _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);  | 
158  | 0  |       return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);  | 
159  | 0  |     }  | 
160  | 0  |     break;  | 
161  | 0  |   }  | 
162  |  |  | 
163  | 0  |   ret = ccm_decrypt_message(&ctx->key, x86_aes_encrypt, nonce_size, nonce,  | 
164  | 0  |           auth_size, auth, tag_size,  | 
165  | 0  |           encr_size - tag_size, plain, encr);  | 
166  | 0  |   if (unlikely(ret == 0))  | 
167  | 0  |     return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);  | 
168  |  |  | 
169  | 0  |   return 0;  | 
170  | 0  | }  | 
171  |  |  | 
172  |  | static void aes_ccm_deinit(void *_ctx)  | 
173  | 0  | { | 
174  | 0  |   struct ccm_x86_aes_ctx *ctx = _ctx;  | 
175  |  | 
  | 
176  | 0  |   zeroize_temp_key(ctx, sizeof(*ctx));  | 
177  | 0  |   gnutls_free(ctx);  | 
178  | 0  | }  | 
179  |  |  | 
180  |  | const gnutls_crypto_cipher_st _gnutls_aes_ccm_x86_aesni = { | 
181  |  |   .init = aes_ccm_cipher_init,  | 
182  |  |   .setkey = aes_ccm_cipher_setkey,  | 
183  |  |   .aead_encrypt = aes_ccm_aead_encrypt,  | 
184  |  |   .aead_decrypt = aes_ccm_aead_decrypt,  | 
185  |  |   .deinit = aes_ccm_deinit,  | 
186  |  | };  | 
187  |  |  | 
188  |  | #endif  |