2 * Copyright (C) 2009-2013 Free Software Foundation, Inc.
3 * Copyright (C) 2013 Nikos Mavrogiannopoulos
5 * Author: Nikos Mavrogiannopoulos
7 * This file is part of GnuTLS.
9 * The GnuTLS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1 of
12 * the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>
24 #include <gnutls_int.h>
25 #include <gnutls_errors.h>
26 #include <gnutls_cipher_int.h>
27 #include <gnutls_datum.h>
28 #include <gnutls/crypto.h>
31 #include <algorithms.h>
33 #define SR(x, cleanup) if ( (x)<0 ) { \
35 ret = GNUTLS_E_INTERNAL_ERROR; \
39 /* Returns true(non-zero) or false(0) if the
40 * provided cipher exists
42 int _gnutls_cipher_exists(gnutls_cipher_algorithm_t cipher)
44 const gnutls_crypto_cipher_st *cc;
47 /* All the other ciphers are disabled on the back-end library.
48 * The NULL needs to be detected here as it is merely a placeholder
49 * rather than an actual cipher.
51 if (cipher == GNUTLS_CIPHER_NULL) {
52 if (_gnutls_fips_mode_enabled() == 0)
58 cc = _gnutls_get_crypto_cipher(cipher);
62 ret = _gnutls_cipher_ops.exists(cipher);
67 _gnutls_cipher_init(cipher_hd_st * handle, const cipher_entry_st * e,
68 const gnutls_datum_t * key, const gnutls_datum_t * iv,
71 int ret = GNUTLS_E_INTERNAL_ERROR;
72 const gnutls_crypto_cipher_st *cc = NULL;
74 if (unlikely(e == NULL || e->id == GNUTLS_CIPHER_NULL))
75 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
81 /* check if a cipher has been registered
83 cc = _gnutls_get_crypto_cipher(e->id);
85 handle->encrypt = cc->encrypt;
86 handle->decrypt = cc->decrypt;
87 handle->deinit = cc->deinit;
88 handle->auth = cc->auth;
89 handle->tag = cc->tag;
90 handle->setiv = cc->setiv;
92 SR(cc->init(e->id, &handle->handle, enc), cc_cleanup);
93 SR(cc->setkey(handle->handle, key->data, key->size),
96 SR(cc->setiv(handle->handle, iv->data, iv->size),
103 handle->encrypt = _gnutls_cipher_ops.encrypt;
104 handle->decrypt = _gnutls_cipher_ops.decrypt;
105 handle->deinit = _gnutls_cipher_ops.deinit;
106 handle->auth = _gnutls_cipher_ops.auth;
107 handle->tag = _gnutls_cipher_ops.tag;
108 handle->setiv = _gnutls_cipher_ops.setiv;
110 /* otherwise use generic cipher interface
112 ret = _gnutls_cipher_ops.init(e->id, &handle->handle, enc);
119 _gnutls_cipher_ops.setkey(handle->handle, key->data,
128 _gnutls_cipher_ops.setiv(handle->handle, iv->data,
141 handle->deinit(handle->handle);
148 int _gnutls_auth_cipher_init(auth_cipher_hd_st * handle,
149 const cipher_entry_st * e,
150 const gnutls_datum_t * cipher_key,
151 const gnutls_datum_t * iv,
152 const mac_entry_st * me,
153 const gnutls_datum_t * mac_key,
154 int ssl_hmac, int enc)
158 if (unlikely(e == NULL))
159 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
163 memset(handle, 0, sizeof(*handle));
165 if (e->id != GNUTLS_CIPHER_NULL) {
166 handle->non_null = 1;
168 _gnutls_cipher_init(&handle->cipher, e, cipher_key, iv,
171 return gnutls_assert_val(ret);
173 handle->non_null = 0;
175 if (me->id != GNUTLS_MAC_AEAD) {
177 handle->ssl_hmac = ssl_hmac;
181 _gnutls_mac_init_ssl3(&handle->mac.dig, me,
186 _gnutls_mac_init(&handle->mac.mac, me,
187 mac_key->data, mac_key->size);
193 handle->tag_size = _gnutls_mac_get_algo_len(me);
194 } else if (_gnutls_cipher_algo_is_aead(e)) {
195 handle->tag_size = _gnutls_cipher_get_tag_size(e);
198 ret = GNUTLS_E_INVALID_REQUEST;
204 if (handle->non_null != 0)
205 _gnutls_cipher_deinit(&handle->cipher);
210 int _gnutls_auth_cipher_add_auth(auth_cipher_hd_st * handle,
211 const void *text, int textlen)
213 if (handle->is_mac) {
214 if (handle->ssl_hmac)
215 return _gnutls_hash(&handle->mac.dig, text,
218 return _gnutls_mac(&handle->mac.mac, text,
220 } else if (_gnutls_cipher_is_aead(&handle->cipher))
221 return _gnutls_cipher_auth(&handle->cipher, text, textlen);
226 /* The caller must make sure that textlen+pad_size+tag_size is divided by the block size of the cipher */
227 int _gnutls_auth_cipher_encrypt2_tag(auth_cipher_hd_st * handle,
228 const uint8_t * text, int textlen,
229 void *_ciphertext, int ciphertextlen,
233 uint8_t *ciphertext = _ciphertext;
235 _gnutls_cipher_get_block_size(handle->cipher.e);
238 if (handle->is_mac) {
239 if (handle->ssl_hmac)
241 _gnutls_hash(&handle->mac.dig, text, textlen);
243 ret = _gnutls_mac(&handle->mac.mac, text, textlen);
244 if (unlikely(ret < 0))
245 return gnutls_assert_val(ret);
247 if (unlikely(textlen + pad_size + handle->tag_size) >
249 return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
251 if (handle->non_null != 0) {
252 l = (textlen / blocksize) * blocksize;
255 _gnutls_cipher_encrypt2(&handle->cipher, text,
259 return gnutls_assert_val(ret);
267 if (ciphertext != text && textlen > 0)
268 memcpy(ciphertext, text, textlen);
271 _gnutls_auth_cipher_tag(handle,
272 ciphertext + textlen,
275 return gnutls_assert_val(ret);
276 textlen += handle->tag_size;
278 /* TLS 1.0 style padding */
280 memset(ciphertext + textlen, pad_size - 1,
286 _gnutls_cipher_encrypt2(&handle->cipher,
291 return gnutls_assert_val(ret);
292 } else { /* null cipher */
294 if (text != ciphertext)
295 memcpy(ciphertext, text, textlen);
298 _gnutls_auth_cipher_tag(handle,
299 ciphertext + textlen,
302 return gnutls_assert_val(ret);
304 } else if (_gnutls_cipher_is_aead(&handle->cipher)) {
306 _gnutls_cipher_encrypt2(&handle->cipher, text, textlen,
307 ciphertext, ciphertextlen);
308 if (unlikely(ret < 0))
309 return gnutls_assert_val(ret);
312 _gnutls_auth_cipher_tag(handle, ciphertext + textlen,
314 if (unlikely(ret < 0))
315 return gnutls_assert_val(ret);
316 } else if (handle->non_null == 0 && text != ciphertext)
317 memcpy(ciphertext, text, textlen);
322 int _gnutls_auth_cipher_decrypt2(auth_cipher_hd_st * handle,
323 const void *ciphertext, int ciphertextlen,
324 void *text, int textlen)
328 if (unlikely(ciphertextlen > textlen))
329 return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
331 if (handle->non_null != 0) {
333 _gnutls_cipher_decrypt2(&handle->cipher, ciphertext,
334 ciphertextlen, text, textlen);
336 return gnutls_assert_val(ret);
337 } else if (handle->non_null == 0 && text != ciphertext)
338 memcpy(text, ciphertext, ciphertextlen);
340 if (handle->is_mac) {
341 /* The MAC is not to be hashed */
342 ciphertextlen -= handle->tag_size;
344 if (handle->ssl_hmac)
345 return _gnutls_hash(&handle->mac.dig, text,
348 return _gnutls_mac(&handle->mac.mac, text,
355 int _gnutls_auth_cipher_tag(auth_cipher_hd_st * handle, void *tag,
360 if (handle->is_mac) {
361 if (handle->ssl_hmac) {
363 _gnutls_mac_output_ssl3(&handle->mac.dig, tag);
365 return gnutls_assert_val(ret);
367 _gnutls_mac_output(&handle->mac.mac, tag);
369 } else if (_gnutls_cipher_is_aead(&handle->cipher)) {
370 _gnutls_cipher_tag(&handle->cipher, tag, tag_size);
372 memset(tag, 0, tag_size);
377 void _gnutls_auth_cipher_deinit(auth_cipher_hd_st * handle)
379 if (handle->is_mac) {
380 if (handle->ssl_hmac) /* failure here doesn't matter */
381 _gnutls_mac_deinit_ssl3(&handle->mac.dig, NULL);
383 _gnutls_mac_deinit(&handle->mac.mac, NULL);
385 if (handle->non_null != 0)
386 _gnutls_cipher_deinit(&handle->cipher);