Coverage Report

Created: 2023-03-26 08:33

/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,
49
          size_t length, uint8_t * dst, 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
56
aes_ccm_cipher_init(gnutls_cipher_algorithm_t algorithm, void **ctx, 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
83
aes_ccm_aead_encrypt(void *_ctx,
84
         const void *nonce, size_t nonce_size,
85
         const void *auth, size_t auth_size,
86
         size_t tag_size,
87
         const void *plain, size_t plain_size,
88
         void *encr, size_t encr_size)
89
0
{
90
0
  struct ccm_x86_aes_ctx *ctx = _ctx;
91
  /* proper AEAD cipher */
92
93
0
  if (unlikely(encr_size < plain_size + tag_size))
94
0
    return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
95
96
  /* SP800-38C A.1 says Tlen must be a multiple of 16 between 32
97
   * and 128.
98
   */
99
0
  switch (tag_size) {
100
0
  case 4:
101
0
  case 6:
102
    /* SP800-38C B.2 says Tlen smaller than 64 should not be used
103
     * under sufficient restriction. We simply allow those for now.
104
     */
105
0
    FALLTHROUGH;
106
0
  case 8:
107
0
  case 10:
108
0
  case 12:
109
0
  case 14:
110
0
  case 16:
111
0
    break;
112
0
  default:
113
0
    if (_gnutls_fips_mode_enabled()) {
114
0
      _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
115
0
      return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
116
0
    }
117
0
    break;
118
0
  }
119
120
0
  ccm_encrypt_message(&ctx->key, x86_aes_encrypt,
121
0
          nonce_size, nonce,
122
0
          auth_size, auth,
123
0
          tag_size, plain_size + tag_size, encr, plain);
124
0
  return 0;
125
0
}
126
127
static int
128
aes_ccm_aead_decrypt(void *_ctx,
129
         const void *nonce, size_t nonce_size,
130
         const void *auth, size_t auth_size,
131
         size_t tag_size,
132
         const void *encr, size_t encr_size,
133
         void *plain, size_t plain_size)
134
0
{
135
0
  struct ccm_x86_aes_ctx *ctx = _ctx;
136
0
  int ret;
137
138
0
  if (unlikely(encr_size < tag_size))
139
0
    return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
140
141
0
  if (unlikely(plain_size < encr_size - tag_size))
142
0
    return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
143
144
  /* SP800-38C A.1 says Tlen must be a multiple of 16 between 32
145
   * and 128.
146
   */
147
0
  switch (tag_size) {
148
0
  case 4:
149
0
  case 6:
150
    /* SP800-38C B.2 says Tlen smaller than 64 should not be used
151
     * under sufficient restriction. We simply allow those for now.
152
     */
153
0
    FALLTHROUGH;
154
0
  case 8:
155
0
  case 10:
156
0
  case 12:
157
0
  case 14:
158
0
  case 16:
159
0
    break;
160
0
  default:
161
0
    if (_gnutls_fips_mode_enabled()) {
162
0
      _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
163
0
      return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
164
0
    }
165
0
    break;
166
0
  }
167
168
0
  ret = ccm_decrypt_message(&ctx->key, x86_aes_encrypt,
169
0
          nonce_size, nonce,
170
0
          auth_size, auth,
171
0
          tag_size, encr_size - tag_size, plain, encr);
172
0
  if (unlikely(ret == 0))
173
0
    return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
174
175
0
  return 0;
176
0
}
177
178
static void aes_ccm_deinit(void *_ctx)
179
0
{
180
0
  struct ccm_x86_aes_ctx *ctx = _ctx;
181
182
0
  zeroize_temp_key(ctx, sizeof(*ctx));
183
0
  gnutls_free(ctx);
184
0
}
185
186
const gnutls_crypto_cipher_st _gnutls_aes_ccm_x86_aesni = {
187
  .init = aes_ccm_cipher_init,
188
  .setkey = aes_ccm_cipher_setkey,
189
  .aead_encrypt = aes_ccm_aead_encrypt,
190
  .aead_decrypt = aes_ccm_aead_decrypt,
191
  .deinit = aes_ccm_deinit,
192
};
193
194
#endif