Coverage Report

Created: 2025-03-18 06:55

/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