Blame lib/crypto-api.c

Packit aea12f
/*
Packit aea12f
 * Copyright (C) 2000-2016 Free Software Foundation, Inc.
Packit aea12f
 * Copyright (C) 2016 Red Hat, Inc.
Packit aea12f
 *
Packit aea12f
 * Author: Nikos Mavrogiannopoulos
Packit aea12f
 *
Packit aea12f
 * This file is part of GnuTLS.
Packit aea12f
 *
Packit aea12f
 * The GnuTLS is free software; you can redistribute it and/or
Packit aea12f
 * modify it under the terms of the GNU Lesser General Public License
Packit aea12f
 * as published by the Free Software Foundation; either version 2.1 of
Packit aea12f
 * the License, or (at your option) any later version.
Packit aea12f
 *
Packit aea12f
 * This library is distributed in the hope that it will be useful, but
Packit aea12f
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit aea12f
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit aea12f
 * Lesser General Public License for more details.
Packit aea12f
 *
Packit aea12f
 * You should have received a copy of the GNU Lesser General Public License
Packit aea12f
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
Packit aea12f
 *
Packit aea12f
 */
Packit aea12f
Packit aea12f
#include "gnutls_int.h"
Packit aea12f
#include "errors.h"
Packit aea12f
#include <cipher_int.h>
Packit aea12f
#include <datum.h>
Packit aea12f
#include <gnutls/crypto.h>
Packit aea12f
#include <algorithms.h>
Packit aea12f
#include <random.h>
Packit aea12f
#include <crypto.h>
Packit aea12f
#include <fips.h>
Packit aea12f
#include "crypto-api.h"
Packit c36854
#include "iov.h"
Packit aea12f
Packit aea12f
typedef struct api_cipher_hd_st {
Packit aea12f
	cipher_hd_st ctx_enc;
Packit aea12f
	cipher_hd_st ctx_dec;
Packit aea12f
} api_cipher_hd_st;
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_cipher_init:
Packit aea12f
 * @handle: is a #gnutls_cipher_hd_t type
Packit aea12f
 * @cipher: the encryption algorithm to use
Packit aea12f
 * @key: the key to be used for encryption/decryption
Packit aea12f
 * @iv: the IV to use (if not applicable set NULL)
Packit aea12f
 *
Packit aea12f
 * This function will initialize the @handle context to be usable
Packit aea12f
 * for encryption/decryption of data. This will effectively use the
Packit aea12f
 * current crypto backend in use by gnutls or the cryptographic
Packit aea12f
 * accelerator in use.
Packit aea12f
 *
Packit aea12f
 * Returns: Zero or a negative error code on error.
Packit aea12f
 *
Packit aea12f
 * Since: 2.10.0
Packit aea12f
 **/
Packit aea12f
int
Packit aea12f
gnutls_cipher_init(gnutls_cipher_hd_t * handle,
Packit aea12f
		   gnutls_cipher_algorithm_t cipher,
Packit aea12f
		   const gnutls_datum_t * key, const gnutls_datum_t * iv)
Packit aea12f
{
Packit aea12f
	api_cipher_hd_st *h;
Packit aea12f
	int ret;
Packit aea12f
	const cipher_entry_st* e;
Packit aea12f
Packit aea12f
	if (is_cipher_algo_forbidden(cipher))
Packit aea12f
		return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
Packit aea12f
Packit aea12f
	e = cipher_to_entry(cipher);
Packit aea12f
	if (e == NULL || e->only_aead)
Packit aea12f
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
Packit aea12f
Packit aea12f
	*handle = gnutls_calloc(1, sizeof(api_cipher_hd_st));
Packit aea12f
	if (*handle == NULL) {
Packit aea12f
		gnutls_assert();
Packit aea12f
		return GNUTLS_E_MEMORY_ERROR;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	h = *handle;
Packit aea12f
	ret =
Packit aea12f
	    _gnutls_cipher_init(&h->ctx_enc, e, key,
Packit aea12f
				iv, 1);
Packit aea12f
Packit aea12f
	if (ret >= 0 && _gnutls_cipher_type(e) == CIPHER_BLOCK)
Packit aea12f
		ret =
Packit aea12f
		    _gnutls_cipher_init(&h->ctx_dec, e, key, iv, 0);
Packit aea12f
Packit aea12f
	return ret;
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_cipher_tag:
Packit aea12f
 * @handle: is a #gnutls_cipher_hd_t type
Packit aea12f
 * @tag: will hold the tag
Packit aea12f
 * @tag_size: the length of the tag to return
Packit aea12f
 *
Packit aea12f
 * This function operates on authenticated encryption with
Packit aea12f
 * associated data (AEAD) ciphers and will return the
Packit aea12f
 * output tag.
Packit aea12f
 *
Packit aea12f
 * Returns: Zero or a negative error code on error.
Packit aea12f
 *
Packit aea12f
 * Since: 3.0
Packit aea12f
 **/
Packit aea12f
int
Packit aea12f
gnutls_cipher_tag(gnutls_cipher_hd_t handle, void *tag, size_t tag_size)
Packit aea12f
{
Packit aea12f
	api_cipher_hd_st *h = handle;
Packit aea12f
Packit aea12f
	if (_gnutls_cipher_is_aead(&h->ctx_enc) == 0)
Packit aea12f
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
Packit aea12f
Packit aea12f
	_gnutls_cipher_tag(&h->ctx_enc, tag, tag_size);
Packit aea12f
Packit aea12f
	return 0;
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_cipher_add_auth:
Packit aea12f
 * @handle: is a #gnutls_cipher_hd_t type
Packit aea12f
 * @ptext: the data to be authenticated
Packit aea12f
 * @ptext_size: the length of the data
Packit aea12f
 *
Packit aea12f
 * This function operates on authenticated encryption with
Packit aea12f
 * associated data (AEAD) ciphers and authenticate the
Packit aea12f
 * input data. This function can only be called once
Packit aea12f
 * and before any encryption operations.
Packit aea12f
 *
Packit aea12f
 * Returns: Zero or a negative error code on error.
Packit aea12f
 *
Packit aea12f
 * Since: 3.0
Packit aea12f
 **/
Packit aea12f
int
Packit aea12f
gnutls_cipher_add_auth(gnutls_cipher_hd_t handle, const void *ptext,
Packit aea12f
		       size_t ptext_size)
Packit aea12f
{
Packit aea12f
	api_cipher_hd_st *h = handle;
Packit aea12f
Packit aea12f
	if (_gnutls_cipher_is_aead(&h->ctx_enc) == 0)
Packit aea12f
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
Packit aea12f
Packit aea12f
	return _gnutls_cipher_auth(&h->ctx_enc, ptext, ptext_size);
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_cipher_set_iv:
Packit aea12f
 * @handle: is a #gnutls_cipher_hd_t type
Packit aea12f
 * @iv: the IV to set
Packit aea12f
 * @ivlen: the length of the IV
Packit aea12f
 *
Packit aea12f
 * This function will set the IV to be used for the next
Packit aea12f
 * encryption block.
Packit aea12f
 *
Packit aea12f
 * Since: 3.0
Packit aea12f
 **/
Packit aea12f
void
Packit aea12f
gnutls_cipher_set_iv(gnutls_cipher_hd_t handle, void *iv, size_t ivlen)
Packit aea12f
{
Packit aea12f
	api_cipher_hd_st *h = handle;
Packit aea12f
Packit aea12f
	if (_gnutls_cipher_setiv(&h->ctx_enc, iv, ivlen) < 0) {
Packit aea12f
		_gnutls_switch_lib_state(LIB_STATE_ERROR);
Packit aea12f
	}
Packit aea12f
Packit aea12f
	if (_gnutls_cipher_type(h->ctx_enc.e) == CIPHER_BLOCK)
Packit aea12f
		if (_gnutls_cipher_setiv(&h->ctx_dec, iv, ivlen) < 0) {
Packit aea12f
			_gnutls_switch_lib_state(LIB_STATE_ERROR);
Packit aea12f
		}
Packit aea12f
}
Packit aea12f
Packit aea12f
/*-
Packit aea12f
 * _gnutls_cipher_get_iv:
Packit aea12f
 * @handle: is a #gnutls_cipher_hd_t type
Packit aea12f
 * @iv: the IV to set
Packit aea12f
 * @ivlen: the length of the IV
Packit aea12f
 *
Packit aea12f
 * This function will retrieve the internally calculated IV value. It is
Packit aea12f
 * intended to be used  for modes like CFB. @iv must have @ivlen length
Packit aea12f
 * at least.
Packit aea12f
 *
Packit aea12f
 * This is solely for validation purposes of our crypto
Packit aea12f
 * implementation.  For other purposes, the IV can be typically
Packit aea12f
 * calculated from the initial IV value and the subsequent ciphertext
Packit aea12f
 * values.  As such, this function only works with the internally
Packit aea12f
 * registered ciphers.
Packit aea12f
 *
Packit aea12f
 * Returns: The length of IV or a negative error code on error.
Packit aea12f
 *
Packit aea12f
 * Since: 3.6.8
Packit aea12f
 -*/
Packit aea12f
int
Packit aea12f
_gnutls_cipher_get_iv(gnutls_cipher_hd_t handle, void *iv, size_t ivlen)
Packit aea12f
{
Packit aea12f
	api_cipher_hd_st *h = handle;
Packit aea12f
Packit aea12f
	return _gnutls_cipher_getiv(&h->ctx_enc, iv, ivlen);
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_cipher_encrypt:
Packit aea12f
 * @handle: is a #gnutls_cipher_hd_t type
Packit aea12f
 * @ptext: the data to encrypt
Packit aea12f
 * @ptext_len: the length of data to encrypt
Packit aea12f
 *
Packit aea12f
 * This function will encrypt the given data using the algorithm
Packit aea12f
 * specified by the context.
Packit aea12f
 *
Packit aea12f
 * Returns: Zero or a negative error code on error.
Packit aea12f
 *
Packit aea12f
 * Since: 2.10.0
Packit aea12f
 **/
Packit aea12f
int
Packit aea12f
gnutls_cipher_encrypt(gnutls_cipher_hd_t handle, void *ptext,
Packit aea12f
		      size_t ptext_len)
Packit aea12f
{
Packit aea12f
	api_cipher_hd_st *h = handle;
Packit aea12f
Packit aea12f
	return _gnutls_cipher_encrypt(&h->ctx_enc, ptext, ptext_len);
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_cipher_decrypt:
Packit aea12f
 * @handle: is a #gnutls_cipher_hd_t type
Packit aea12f
 * @ctext: the data to decrypt
Packit aea12f
 * @ctext_len: the length of data to decrypt
Packit aea12f
 *
Packit aea12f
 * This function will decrypt the given data using the algorithm
Packit aea12f
 * specified by the context.
Packit aea12f
 *
Packit aea12f
 * Note that in AEAD ciphers, this will not check the tag. You will
Packit aea12f
 * need to compare the tag sent with the value returned from gnutls_cipher_tag().
Packit aea12f
 *
Packit aea12f
 * Returns: Zero or a negative error code on error.
Packit aea12f
 *
Packit aea12f
 * Since: 2.10.0
Packit aea12f
 **/
Packit aea12f
int
Packit aea12f
gnutls_cipher_decrypt(gnutls_cipher_hd_t handle, void *ctext,
Packit aea12f
		      size_t ctext_len)
Packit aea12f
{
Packit aea12f
	api_cipher_hd_st *h = handle;
Packit aea12f
Packit aea12f
	if (_gnutls_cipher_type(h->ctx_enc.e) != CIPHER_BLOCK)
Packit aea12f
		return _gnutls_cipher_decrypt(&h->ctx_enc, ctext,
Packit aea12f
					      ctext_len);
Packit aea12f
	else
Packit aea12f
		return _gnutls_cipher_decrypt(&h->ctx_dec, ctext,
Packit aea12f
					      ctext_len);
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_cipher_encrypt2:
Packit aea12f
 * @handle: is a #gnutls_cipher_hd_t type
Packit aea12f
 * @ptext: the data to encrypt
Packit aea12f
 * @ptext_len: the length of data to encrypt
Packit aea12f
 * @ctext: the encrypted data
Packit aea12f
 * @ctext_len: the available length for encrypted data
Packit aea12f
 *
Packit aea12f
 * This function will encrypt the given data using the algorithm
Packit aea12f
 * specified by the context. For block ciphers the @ptext_len must be
Packit aea12f
 * a multiple of the block size. For the supported ciphers the encrypted
Packit aea12f
 * data length will equal the plaintext size.
Packit aea12f
 *
Packit aea12f
 * Returns: Zero or a negative error code on error.
Packit aea12f
 *
Packit aea12f
 * Since: 2.12.0
Packit aea12f
 **/
Packit aea12f
int
Packit aea12f
gnutls_cipher_encrypt2(gnutls_cipher_hd_t handle, const void *ptext,
Packit aea12f
		       size_t ptext_len, void *ctext,
Packit aea12f
		       size_t ctext_len)
Packit aea12f
{
Packit aea12f
	api_cipher_hd_st *h = handle;
Packit aea12f
Packit aea12f
	return _gnutls_cipher_encrypt2(&h->ctx_enc, ptext, ptext_len,
Packit aea12f
				       ctext, ctext_len);
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_cipher_decrypt2:
Packit aea12f
 * @handle: is a #gnutls_cipher_hd_t type
Packit aea12f
 * @ctext: the data to decrypt
Packit aea12f
 * @ctext_len: the length of data to decrypt
Packit aea12f
 * @ptext: the decrypted data
Packit aea12f
 * @ptext_len: the available length for decrypted data
Packit aea12f
 *
Packit aea12f
 * This function will decrypt the given data using the algorithm
Packit aea12f
 * specified by the context. For block ciphers the @ctext_len must be
Packit aea12f
 * a multiple of the block size. For the supported ciphers the plaintext
Packit aea12f
 * data length will equal the ciphertext size.
Packit aea12f
 *
Packit aea12f
 * Note that in AEAD ciphers, this will not check the tag. You will
Packit aea12f
 * need to compare the tag sent with the value returned from gnutls_cipher_tag().
Packit aea12f
 *
Packit aea12f
 * Returns: Zero or a negative error code on error.
Packit aea12f
 *
Packit aea12f
 * Since: 2.12.0
Packit aea12f
 **/
Packit aea12f
int
Packit aea12f
gnutls_cipher_decrypt2(gnutls_cipher_hd_t handle, const void *ctext,
Packit aea12f
		       size_t ctext_len, void *ptext, size_t ptext_len)
Packit aea12f
{
Packit aea12f
	api_cipher_hd_st *h = handle;
Packit aea12f
Packit aea12f
	if (_gnutls_cipher_type(h->ctx_enc.e) != CIPHER_BLOCK)
Packit aea12f
		return _gnutls_cipher_decrypt2(&h->ctx_enc, ctext,
Packit aea12f
					       ctext_len, ptext,
Packit aea12f
					       ptext_len);
Packit aea12f
	else
Packit aea12f
		return _gnutls_cipher_decrypt2(&h->ctx_dec, ctext,
Packit aea12f
					       ctext_len, ptext,
Packit aea12f
					       ptext_len);
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_cipher_deinit:
Packit aea12f
 * @handle: is a #gnutls_cipher_hd_t type
Packit aea12f
 *
Packit aea12f
 * This function will deinitialize all resources occupied by the given
Packit aea12f
 * encryption context.
Packit aea12f
 *
Packit aea12f
 * Since: 2.10.0
Packit aea12f
 **/
Packit aea12f
void gnutls_cipher_deinit(gnutls_cipher_hd_t handle)
Packit aea12f
{
Packit aea12f
	api_cipher_hd_st *h = handle;
Packit aea12f
Packit aea12f
	_gnutls_cipher_deinit(&h->ctx_enc);
Packit aea12f
	if (_gnutls_cipher_type(h->ctx_enc.e) == CIPHER_BLOCK)
Packit aea12f
		_gnutls_cipher_deinit(&h->ctx_dec);
Packit aea12f
	gnutls_free(handle);
Packit aea12f
}
Packit aea12f
Packit aea12f
Packit aea12f
/* HMAC */
Packit aea12f
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_hmac_init:
Packit aea12f
 * @dig: is a #gnutls_hmac_hd_t type
Packit aea12f
 * @algorithm: the HMAC algorithm to use
Packit aea12f
 * @key: the key to be used for encryption
Packit aea12f
 * @keylen: the length of the key
Packit aea12f
 *
Packit aea12f
 * This function will initialize an context that can be used to
Packit aea12f
 * produce a Message Authentication Code (MAC) of data.  This will
Packit aea12f
 * effectively use the current crypto backend in use by gnutls or the
Packit aea12f
 * cryptographic accelerator in use.
Packit aea12f
 *
Packit aea12f
 * Note that despite the name of this function, it can be used
Packit aea12f
 * for other MAC algorithms than HMAC.
Packit aea12f
 *
Packit aea12f
 * Returns: Zero or a negative error code on error.
Packit aea12f
 *
Packit aea12f
 * Since: 2.10.0
Packit aea12f
 **/
Packit aea12f
int
Packit aea12f
gnutls_hmac_init(gnutls_hmac_hd_t * dig,
Packit aea12f
		 gnutls_mac_algorithm_t algorithm,
Packit aea12f
		 const void *key, size_t keylen)
Packit aea12f
{
Packit aea12f
	/* MD5 is only allowed internally for TLS */
Packit aea12f
	if (is_mac_algo_forbidden(algorithm))
Packit aea12f
		return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
Packit aea12f
Packit aea12f
	*dig = gnutls_malloc(sizeof(mac_hd_st));
Packit aea12f
	if (*dig == NULL) {
Packit aea12f
		gnutls_assert();
Packit aea12f
		return GNUTLS_E_MEMORY_ERROR;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	return _gnutls_mac_init(((mac_hd_st *) * dig),
Packit aea12f
				mac_to_entry(algorithm), key, keylen);
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_hmac_set_nonce:
Packit aea12f
 * @handle: is a #gnutls_hmac_hd_t type
Packit aea12f
 * @nonce: the data to set as nonce
Packit aea12f
 * @nonce_len: the length of data
Packit aea12f
 *
Packit aea12f
 * This function will set the nonce in the MAC algorithm.
Packit aea12f
 *
Packit aea12f
 * Since: 3.2.0
Packit aea12f
 **/
Packit aea12f
void
Packit aea12f
gnutls_hmac_set_nonce(gnutls_hmac_hd_t handle, const void *nonce,
Packit aea12f
		      size_t nonce_len)
Packit aea12f
{
Packit aea12f
	_gnutls_mac_set_nonce((mac_hd_st *) handle, nonce, nonce_len);
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_hmac:
Packit aea12f
 * @handle: is a #gnutls_hmac_hd_t type
Packit aea12f
 * @ptext: the data to hash
Packit aea12f
 * @ptext_len: the length of data to hash
Packit aea12f
 *
Packit aea12f
 * This function will hash the given data using the algorithm
Packit aea12f
 * specified by the context.
Packit aea12f
 *
Packit aea12f
 * Returns: Zero or a negative error code on error.
Packit aea12f
 *
Packit aea12f
 * Since: 2.10.0
Packit aea12f
 **/
Packit aea12f
int gnutls_hmac(gnutls_hmac_hd_t handle, const void *ptext, size_t ptext_len)
Packit aea12f
{
Packit aea12f
	return _gnutls_mac((mac_hd_st *) handle, ptext, ptext_len);
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_hmac_output:
Packit aea12f
 * @handle: is a #gnutls_hmac_hd_t type
Packit aea12f
 * @digest: is the output value of the MAC
Packit aea12f
 *
Packit aea12f
 * This function will output the current MAC value
Packit aea12f
 * and reset the state of the MAC.
Packit aea12f
 *
Packit aea12f
 * Since: 2.10.0
Packit aea12f
 **/
Packit aea12f
void gnutls_hmac_output(gnutls_hmac_hd_t handle, void *digest)
Packit aea12f
{
Packit aea12f
	_gnutls_mac_output((mac_hd_st *) handle, digest);
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_hmac_deinit:
Packit aea12f
 * @handle: is a #gnutls_hmac_hd_t type
Packit aea12f
 * @digest: is the output value of the MAC
Packit aea12f
 *
Packit aea12f
 * This function will deinitialize all resources occupied by
Packit aea12f
 * the given hmac context.
Packit aea12f
 *
Packit aea12f
 * Since: 2.10.0
Packit aea12f
 **/
Packit aea12f
void gnutls_hmac_deinit(gnutls_hmac_hd_t handle, void *digest)
Packit aea12f
{
Packit aea12f
	_gnutls_mac_deinit((mac_hd_st *) handle, digest);
Packit aea12f
	gnutls_free(handle);
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_hmac_get_len:
Packit aea12f
 * @algorithm: the hmac algorithm to use
Packit aea12f
 *
Packit aea12f
 * This function will return the length of the output data
Packit aea12f
 * of the given hmac algorithm.
Packit aea12f
 *
Packit aea12f
 * Returns: The length or zero on error.
Packit aea12f
 *
Packit aea12f
 * Since: 2.10.0
Packit aea12f
 **/
Packit aea12f
unsigned gnutls_hmac_get_len(gnutls_mac_algorithm_t algorithm)
Packit aea12f
{
Packit aea12f
	return _gnutls_mac_get_algo_len(mac_to_entry(algorithm));
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_hmac_fast:
Packit aea12f
 * @algorithm: the hash algorithm to use
Packit aea12f
 * @key: the key to use
Packit aea12f
 * @keylen: the length of the key
Packit aea12f
 * @ptext: the data to hash
Packit aea12f
 * @ptext_len: the length of data to hash
Packit aea12f
 * @digest: is the output value of the hash
Packit aea12f
 *
Packit aea12f
 * This convenience function will hash the given data and return output
Packit aea12f
 * on a single call.
Packit aea12f
 *
Packit aea12f
 * Returns: Zero or a negative error code on error.
Packit aea12f
 *
Packit aea12f
 * Since: 2.10.0
Packit aea12f
 **/
Packit aea12f
int
Packit aea12f
gnutls_hmac_fast(gnutls_mac_algorithm_t algorithm,
Packit aea12f
		 const void *key, size_t keylen,
Packit aea12f
		 const void *ptext, size_t ptext_len, void *digest)
Packit aea12f
{
Packit aea12f
	if (is_mac_algo_forbidden(algorithm))
Packit aea12f
		return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
Packit aea12f
Packit aea12f
	return _gnutls_mac_fast(algorithm, key, keylen, ptext, ptext_len,
Packit aea12f
				digest);
Packit aea12f
}
Packit aea12f
Packit aea12f
/* HASH */
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_hash_init:
Packit aea12f
 * @dig: is a #gnutls_hash_hd_t type
Packit aea12f
 * @algorithm: the hash algorithm to use
Packit aea12f
 *
Packit aea12f
 * This function will initialize an context that can be used to
Packit aea12f
 * produce a Message Digest of data.  This will effectively use the
Packit aea12f
 * current crypto backend in use by gnutls or the cryptographic
Packit aea12f
 * accelerator in use.
Packit aea12f
 *
Packit aea12f
 * Returns: Zero or a negative error code on error.
Packit aea12f
 *
Packit aea12f
 * Since: 2.10.0
Packit aea12f
 **/
Packit aea12f
int
Packit aea12f
gnutls_hash_init(gnutls_hash_hd_t * dig,
Packit aea12f
		 gnutls_digest_algorithm_t algorithm)
Packit aea12f
{
Packit aea12f
	if (is_mac_algo_forbidden(algorithm))
Packit aea12f
		return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
Packit aea12f
Packit aea12f
	*dig = gnutls_malloc(sizeof(digest_hd_st));
Packit aea12f
	if (*dig == NULL) {
Packit aea12f
		gnutls_assert();
Packit aea12f
		return GNUTLS_E_MEMORY_ERROR;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	return _gnutls_hash_init(((digest_hd_st *) * dig),
Packit aea12f
				 hash_to_entry(algorithm));
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_hash:
Packit aea12f
 * @handle: is a #gnutls_hash_hd_t type
Packit aea12f
 * @ptext: the data to hash
Packit aea12f
 * @ptext_len: the length of data to hash
Packit aea12f
 *
Packit aea12f
 * This function will hash the given data using the algorithm
Packit aea12f
 * specified by the context.
Packit aea12f
 *
Packit aea12f
 * Returns: Zero or a negative error code on error.
Packit aea12f
 *
Packit aea12f
 * Since: 2.10.0
Packit aea12f
 **/
Packit aea12f
int gnutls_hash(gnutls_hash_hd_t handle, const void *ptext, size_t ptext_len)
Packit aea12f
{
Packit aea12f
	return _gnutls_hash((digest_hd_st *) handle, ptext, ptext_len);
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_hash_output:
Packit aea12f
 * @handle: is a #gnutls_hash_hd_t type
Packit aea12f
 * @digest: is the output value of the hash
Packit aea12f
 *
Packit aea12f
 * This function will output the current hash value
Packit aea12f
 * and reset the state of the hash.
Packit aea12f
 *
Packit aea12f
 * Since: 2.10.0
Packit aea12f
 **/
Packit aea12f
void gnutls_hash_output(gnutls_hash_hd_t handle, void *digest)
Packit aea12f
{
Packit aea12f
	_gnutls_hash_output((digest_hd_st *) handle, digest);
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_hash_deinit:
Packit aea12f
 * @handle: is a #gnutls_hash_hd_t type
Packit aea12f
 * @digest: is the output value of the hash
Packit aea12f
 *
Packit aea12f
 * This function will deinitialize all resources occupied by
Packit aea12f
 * the given hash context.
Packit aea12f
 *
Packit aea12f
 * Since: 2.10.0
Packit aea12f
 **/
Packit aea12f
void gnutls_hash_deinit(gnutls_hash_hd_t handle, void *digest)
Packit aea12f
{
Packit aea12f
	_gnutls_hash_deinit((digest_hd_st *) handle, digest);
Packit aea12f
	gnutls_free(handle);
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_hash_get_len:
Packit aea12f
 * @algorithm: the hash algorithm to use
Packit aea12f
 *
Packit aea12f
 * This function will return the length of the output data
Packit aea12f
 * of the given hash algorithm.
Packit aea12f
 *
Packit aea12f
 * Returns: The length or zero on error.
Packit aea12f
 *
Packit aea12f
 * Since: 2.10.0
Packit aea12f
 **/
Packit aea12f
unsigned gnutls_hash_get_len(gnutls_digest_algorithm_t algorithm)
Packit aea12f
{
Packit aea12f
	return _gnutls_hash_get_algo_len(hash_to_entry(algorithm));
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_hash_fast:
Packit aea12f
 * @algorithm: the hash algorithm to use
Packit aea12f
 * @ptext: the data to hash
Packit aea12f
 * @ptext_len: the length of data to hash
Packit aea12f
 * @digest: is the output value of the hash
Packit aea12f
 *
Packit aea12f
 * This convenience function will hash the given data and return output
Packit aea12f
 * on a single call.
Packit aea12f
 *
Packit aea12f
 * Returns: Zero or a negative error code on error.
Packit aea12f
 *
Packit aea12f
 * Since: 2.10.0
Packit aea12f
 **/
Packit aea12f
int
Packit aea12f
gnutls_hash_fast(gnutls_digest_algorithm_t algorithm,
Packit aea12f
		 const void *ptext, size_t ptext_len, void *digest)
Packit aea12f
{
Packit aea12f
	if (is_mac_algo_forbidden(algorithm))
Packit aea12f
		return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
Packit aea12f
Packit aea12f
	return _gnutls_hash_fast(algorithm, ptext, ptext_len, digest);
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_key_generate:
Packit aea12f
 * @key: is a pointer to a #gnutls_datum_t which will contain a newly
Packit aea12f
 * created key
Packit aea12f
 * @key_size: the number of bytes of the key
Packit aea12f
 *
Packit aea12f
 * Generates a random key of @key_size bytes.
Packit aea12f
 *
Packit aea12f
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or an
Packit aea12f
 * error code.
Packit aea12f
 *
Packit aea12f
 * Since: 3.0
Packit aea12f
 **/
Packit aea12f
int gnutls_key_generate(gnutls_datum_t * key, unsigned int key_size)
Packit aea12f
{
Packit aea12f
	int ret;
Packit aea12f
Packit aea12f
	FAIL_IF_LIB_ERROR;
Packit aea12f
Packit aea12f
#ifdef ENABLE_FIPS140
Packit aea12f
	/* The FIPS140 approved RNGs are not allowed to be used
Packit aea12f
	 * to extract key sizes longer than their original seed.
Packit aea12f
	 */
Packit aea12f
	if (_gnutls_fips_mode_enabled() != 0 &&
Packit aea12f
	    key_size > FIPS140_RND_KEY_SIZE)
Packit aea12f
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
Packit aea12f
#endif
Packit aea12f
Packit aea12f
	key->size = key_size;
Packit aea12f
	key->data = gnutls_malloc(key->size);
Packit aea12f
	if (!key->data) {
Packit aea12f
		gnutls_assert();
Packit aea12f
		return GNUTLS_E_MEMORY_ERROR;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	ret = gnutls_rnd(GNUTLS_RND_RANDOM, key->data, key->size);
Packit aea12f
	if (ret < 0) {
Packit aea12f
		gnutls_assert();
Packit aea12f
		_gnutls_free_datum(key);
Packit aea12f
		return ret;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	return 0;
Packit aea12f
}
Packit aea12f
Packit aea12f
/* AEAD API */
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_aead_cipher_init:
Packit aea12f
 * @handle: is a #gnutls_aead_cipher_hd_t type.
Packit aea12f
 * @cipher: the authenticated-encryption algorithm to use
Packit aea12f
 * @key: The key to be used for encryption
Packit aea12f
 *
Packit aea12f
 * This function will initialize an context that can be used for
Packit aea12f
 * encryption/decryption of data. This will effectively use the
Packit aea12f
 * current crypto backend in use by gnutls or the cryptographic
Packit aea12f
 * accelerator in use.
Packit aea12f
 *
Packit aea12f
 * Returns: Zero or a negative error code on error.
Packit aea12f
 *
Packit aea12f
 * Since: 3.4.0
Packit aea12f
 **/
Packit aea12f
int gnutls_aead_cipher_init(gnutls_aead_cipher_hd_t *handle,
Packit aea12f
			    gnutls_cipher_algorithm_t cipher,
Packit aea12f
			    const gnutls_datum_t *key)
Packit aea12f
{
Packit aea12f
	api_aead_cipher_hd_st *h;
Packit aea12f
	const cipher_entry_st *e;
Packit aea12f
Packit aea12f
	if (is_cipher_algo_forbidden(cipher))
Packit aea12f
		return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
Packit aea12f
Packit aea12f
	e = cipher_to_entry(cipher);
Packit aea12f
	if (e == NULL || e->type != CIPHER_AEAD)
Packit aea12f
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
Packit aea12f
Packit aea12f
	*handle = gnutls_calloc(1, sizeof(api_aead_cipher_hd_st));
Packit aea12f
	if (*handle == NULL) {
Packit aea12f
		gnutls_assert();
Packit aea12f
		return GNUTLS_E_MEMORY_ERROR;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	h = *handle;
Packit aea12f
Packit aea12f
	return _gnutls_aead_cipher_init(h, cipher, key);
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_aead_cipher_decrypt:
Packit aea12f
 * @handle: is a #gnutls_aead_cipher_hd_t type.
Packit aea12f
 * @nonce: the nonce to set
Packit aea12f
 * @nonce_len: The length of the nonce
Packit aea12f
 * @auth: additional data to be authenticated
Packit aea12f
 * @auth_len: The length of the data
Packit aea12f
 * @tag_size: The size of the tag to use (use zero for the default)
Packit aea12f
 * @ctext: the data to decrypt (including the authentication tag)
Packit aea12f
 * @ctext_len: the length of data to decrypt (includes tag size)
Packit aea12f
 * @ptext: the decrypted data
Packit aea12f
 * @ptext_len: the length of decrypted data (initially must hold the maximum available size)
Packit aea12f
 *
Packit aea12f
 * This function will decrypt the given data using the algorithm
Packit aea12f
 * specified by the context. This function must be provided the complete
Packit aea12f
 * data to be decrypted, including the authentication tag. On several
Packit aea12f
 * AEAD ciphers, the authentication tag is appended to the ciphertext,
Packit aea12f
 * though this is not a general rule. This function will fail if
Packit aea12f
 * the tag verification fails.
Packit aea12f
 *
Packit aea12f
 * Returns: Zero or a negative error code on verification failure or other error.
Packit aea12f
 *
Packit aea12f
 * Since: 3.4.0
Packit aea12f
 **/
Packit aea12f
int
Packit aea12f
gnutls_aead_cipher_decrypt(gnutls_aead_cipher_hd_t handle,
Packit aea12f
			   const void *nonce, size_t nonce_len,
Packit aea12f
			   const void *auth, size_t auth_len,
Packit aea12f
			   size_t tag_size,
Packit aea12f
			   const void *ctext, size_t ctext_len,
Packit aea12f
			   void *ptext, size_t *ptext_len)
Packit aea12f
{
Packit aea12f
	int ret;
Packit aea12f
	api_aead_cipher_hd_st *h = handle;
Packit aea12f
Packit aea12f
	if (tag_size == 0)
Packit aea12f
		tag_size = _gnutls_cipher_get_tag_size(h->ctx_enc.e);
Packit aea12f
	else if (tag_size > (unsigned)_gnutls_cipher_get_tag_size(h->ctx_enc.e))
Packit aea12f
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
Packit aea12f
Packit aea12f
	if (unlikely(ctext_len < tag_size))
Packit aea12f
		return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
Packit aea12f
Packit aea12f
	ret = _gnutls_aead_cipher_decrypt(&h->ctx_enc,
Packit aea12f
					  nonce, nonce_len,
Packit aea12f
					  auth, auth_len,
Packit aea12f
					  tag_size,
Packit aea12f
					  ctext, ctext_len,
Packit aea12f
					  ptext, *ptext_len);
Packit aea12f
	if (unlikely(ret < 0))
Packit aea12f
		return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
	/* That assumes that AEAD ciphers are stream */
Packit aea12f
	*ptext_len = ctext_len - tag_size;
Packit aea12f
Packit aea12f
	return 0;
Packit aea12f
}
Packit aea12f
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_aead_cipher_encrypt:
Packit aea12f
 * @handle: is a #gnutls_aead_cipher_hd_t type.
Packit aea12f
 * @nonce: the nonce to set
Packit aea12f
 * @nonce_len: The length of the nonce
Packit aea12f
 * @auth: additional data to be authenticated
Packit aea12f
 * @auth_len: The length of the data
Packit aea12f
 * @tag_size: The size of the tag to use (use zero for the default)
Packit aea12f
 * @ptext: the data to encrypt
Packit aea12f
 * @ptext_len: The length of data to encrypt
Packit aea12f
 * @ctext: the encrypted data including authentication tag
Packit aea12f
 * @ctext_len: the length of encrypted data (initially must hold the maximum available size, including space for tag)
Packit aea12f
 *
Packit aea12f
 * This function will encrypt the given data using the algorithm
Packit aea12f
 * specified by the context. The output data will contain the
Packit aea12f
 * authentication tag.
Packit aea12f
 *
Packit aea12f
 * Returns: Zero or a negative error code on error.
Packit aea12f
 *
Packit aea12f
 * Since: 3.4.0
Packit aea12f
 **/
Packit aea12f
int
Packit aea12f
gnutls_aead_cipher_encrypt(gnutls_aead_cipher_hd_t handle,
Packit aea12f
			   const void *nonce, size_t nonce_len,
Packit aea12f
			   const void *auth, size_t auth_len,
Packit aea12f
			   size_t tag_size,
Packit aea12f
			   const void *ptext, size_t ptext_len,
Packit aea12f
			   void *ctext, size_t *ctext_len)
Packit aea12f
{
Packit aea12f
	api_aead_cipher_hd_st *h = handle;
Packit aea12f
	int ret;
Packit aea12f
Packit aea12f
	if (tag_size == 0)
Packit aea12f
		tag_size = _gnutls_cipher_get_tag_size(h->ctx_enc.e);
Packit aea12f
	else if (tag_size > (unsigned)_gnutls_cipher_get_tag_size(h->ctx_enc.e))
Packit aea12f
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
Packit aea12f
Packit aea12f
	if (unlikely(*ctext_len < ptext_len + tag_size))
Packit aea12f
		return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
Packit aea12f
Packit aea12f
	ret = _gnutls_aead_cipher_encrypt(&h->ctx_enc,
Packit aea12f
					  nonce, nonce_len,
Packit aea12f
					  auth, auth_len,
Packit aea12f
					  tag_size,
Packit aea12f
					  ptext, ptext_len,
Packit aea12f
					  ctext, *ctext_len);
Packit aea12f
	if (unlikely(ret < 0))
Packit aea12f
		return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
	/* That assumes that AEAD ciphers are stream */
Packit aea12f
	*ctext_len = ptext_len + tag_size;
Packit aea12f
Packit aea12f
	return 0;
Packit aea12f
}
Packit aea12f
Packit aea12f
struct iov_store_st {
Packit aea12f
	void *data;
Packit aea12f
	size_t size;
Packit aea12f
	unsigned allocated;
Packit aea12f
};
Packit aea12f
Packit aea12f
static void iov_store_free(struct iov_store_st *s)
Packit aea12f
{
Packit aea12f
	if (s->allocated) {
Packit aea12f
		gnutls_free(s->data);
Packit aea12f
		s->allocated = 0;
Packit aea12f
	}
Packit aea12f
}
Packit aea12f
Packit c36854
static int iov_store_grow(struct iov_store_st *s, size_t length)
Packit c36854
{
Packit c36854
	if (s->allocated || s->data == NULL) {
Packit c36854
		s->size += length;
Packit c36854
		s->data = gnutls_realloc(s->data, s->size);
Packit c36854
		if (s->data == NULL)
Packit c36854
			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
Packit c36854
		s->allocated = 1;
Packit c36854
	} else {
Packit c36854
		void *data = s->data;
Packit c36854
		size_t size = s->size + length;
Packit c36854
		s->data = gnutls_malloc(size);
Packit c36854
		memcpy(s->data, data, s->size);
Packit c36854
		s->size += length;
Packit c36854
	}
Packit c36854
	return 0;
Packit c36854
}
Packit c36854
Packit c36854
static int
Packit c36854
copy_from_iov(struct iov_store_st *dst, const giovec_t *iov, int iovcnt)
Packit aea12f
{
Packit aea12f
	memset(dst, 0, sizeof(*dst));
Packit aea12f
	if (iovcnt == 0) {
Packit aea12f
		return 0;
Packit aea12f
	} else if (iovcnt == 1) {
Packit aea12f
		dst->data = iov[0].iov_base;
Packit aea12f
		dst->size = iov[0].iov_len;
Packit aea12f
		/* implies: dst->allocated = 0; */
Packit aea12f
		return 0;
Packit aea12f
	} else {
Packit aea12f
		int i;
Packit aea12f
		uint8_t *p;
Packit aea12f
Packit aea12f
		dst->size = 0;
Packit aea12f
		for (i=0;i
Packit aea12f
			dst->size += iov[i].iov_len;
Packit aea12f
		dst->data = gnutls_malloc(dst->size);
Packit aea12f
		if (dst->data == NULL)
Packit aea12f
			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
Packit aea12f
Packit aea12f
		p = dst->data;
Packit aea12f
		for (i=0;i
Packit aea12f
			memcpy(p, iov[i].iov_base, iov[i].iov_len);
Packit aea12f
			p += iov[i].iov_len;
Packit aea12f
		}
Packit aea12f
Packit aea12f
		dst->allocated = 1;
Packit aea12f
		return 0;
Packit aea12f
	}
Packit aea12f
}
Packit aea12f
Packit c36854
static int
Packit c36854
copy_to_iov(struct iov_store_st *src, size_t size,
Packit c36854
	    const giovec_t *iov, int iovcnt)
Packit c36854
{
Packit c36854
	size_t offset = 0;
Packit c36854
	int i;
Packit c36854
Packit c36854
	if (unlikely(src->size < size))
Packit c36854
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
Packit c36854
Packit c36854
	for (i = 0; i < iovcnt && size > 0; i++) {
Packit c36854
		size_t to_copy = MIN(size, iov[i].iov_len);
Packit c36854
		memcpy(iov[i].iov_base, (uint8_t *) src->data + offset, to_copy);
Packit c36854
		offset += to_copy;
Packit c36854
		size -= to_copy;
Packit c36854
	}
Packit c36854
	if (size > 0)
Packit c36854
		return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
Packit c36854
	return 0;
Packit c36854
}
Packit aea12f
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * gnutls_aead_cipher_encryptv:
Packit aea12f
 * @handle: is a #gnutls_aead_cipher_hd_t type.
Packit aea12f
 * @nonce: the nonce to set
Packit aea12f
 * @nonce_len: The length of the nonce
Packit aea12f
 * @auth_iov: additional data to be authenticated
Packit aea12f
 * @auth_iovcnt: The number of buffers in @auth_iov
Packit aea12f
 * @tag_size: The size of the tag to use (use zero for the default)
Packit aea12f
 * @iov: the data to be encrypted
Packit aea12f
 * @iovcnt: The number of buffers in @iov
Packit aea12f
 * @ctext: the encrypted data including authentication tag
Packit aea12f
 * @ctext_len: the length of encrypted data (initially must hold the maximum available size, including space for tag)
Packit aea12f
 *
Packit aea12f
 * This function will encrypt the provided data buffers using the algorithm
Packit aea12f
 * specified by the context. The output data will contain the
Packit aea12f
 * authentication tag.
Packit aea12f
 *
Packit aea12f
 * Returns: Zero or a negative error code on error.
Packit aea12f
 *
Packit aea12f
 * Since: 3.6.3
Packit aea12f
 **/
Packit aea12f
int
Packit aea12f
gnutls_aead_cipher_encryptv(gnutls_aead_cipher_hd_t handle,
Packit aea12f
			    const void *nonce, size_t nonce_len,
Packit aea12f
			    const giovec_t *auth_iov, int auth_iovcnt,
Packit aea12f
			    size_t tag_size,
Packit aea12f
			    const giovec_t *iov, int iovcnt,
Packit aea12f
			    void *ctext, size_t *ctext_len)
Packit aea12f
{
Packit aea12f
	api_aead_cipher_hd_st *h = handle;
Packit c36854
	ssize_t ret;
Packit aea12f
	uint8_t *dst;
Packit c36854
	ssize_t dst_size, total = 0;
Packit aea12f
	uint8_t *p;
Packit aea12f
	ssize_t blocksize = handle->ctx_enc.e->blocksize;
Packit c36854
	struct iov_iter_st iter;
Packit c36854
	size_t blocks;
Packit aea12f
Packit aea12f
	/* Limitation: this function provides an optimization under the internally registered
Packit aea12f
	 * AEAD ciphers. When an AEAD cipher is used registered with gnutls_crypto_register_aead_cipher(),
Packit aea12f
	 * then this becomes a convenience function as it missed the lower-level primitives
Packit aea12f
	 * necessary for piecemeal encryption. */
Packit aea12f
Packit aea12f
	if (tag_size == 0)
Packit aea12f
		tag_size = _gnutls_cipher_get_tag_size(h->ctx_enc.e);
Packit aea12f
	else if (tag_size > (unsigned)_gnutls_cipher_get_tag_size(h->ctx_enc.e))
Packit aea12f
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
Packit aea12f
Packit aea12f
	if (handle->ctx_enc.e->only_aead || handle->ctx_enc.encrypt == NULL) {
Packit aea12f
		/* ciphertext cannot be produced in a piecemeal approach */
Packit aea12f
		struct iov_store_st auth;
Packit aea12f
		struct iov_store_st ptext;
Packit aea12f
Packit c36854
		ret = copy_from_iov(&auth, auth_iov, auth_iovcnt);
Packit aea12f
		if (ret < 0)
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
Packit c36854
		ret = copy_from_iov(&ptext, iov, iovcnt);
Packit aea12f
		if (ret < 0) {
Packit aea12f
			iov_store_free(&auth);
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
		}
Packit aea12f
Packit aea12f
		ret = gnutls_aead_cipher_encrypt(handle, nonce, nonce_len,
Packit aea12f
						 auth.data, auth.size,
Packit aea12f
						 tag_size,
Packit aea12f
						 ptext.data, ptext.size,
Packit aea12f
						 ctext, ctext_len);
Packit aea12f
		iov_store_free(&auth);
Packit aea12f
		iov_store_free(&ptext);
Packit aea12f
Packit aea12f
		return ret;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	ret = _gnutls_cipher_setiv(&handle->ctx_enc, nonce, nonce_len);
Packit aea12f
	if (unlikely(ret < 0))
Packit aea12f
		return gnutls_assert_val(ret);
Packit aea12f
Packit c36854
	ret = _gnutls_iov_iter_init(&iter, auth_iov, auth_iovcnt, blocksize);
Packit c36854
	if (unlikely(ret < 0))
Packit c36854
		return gnutls_assert_val(ret);
Packit c36854
	while (1) {
Packit c36854
		ret = _gnutls_iov_iter_next(&iter, &p);
Packit c36854
		if (unlikely(ret < 0))
Packit c36854
			return gnutls_assert_val(ret);
Packit c36854
		if (ret == 0)
Packit c36854
			break;
Packit c36854
		blocks = ret;
Packit c36854
		ret = _gnutls_cipher_auth(&handle->ctx_enc, p,
Packit c36854
					  blocksize * blocks);
Packit c36854
		if (unlikely(ret < 0))
Packit c36854
			return gnutls_assert_val(ret);
Packit c36854
	}
Packit c36854
	if (iter.block_offset > 0) {
Packit c36854
		ret = _gnutls_cipher_auth(&handle->ctx_enc,
Packit c36854
					  iter.block, iter.block_offset);
Packit c36854
		if (unlikely(ret < 0))
Packit c36854
			return gnutls_assert_val(ret);
Packit aea12f
	}
Packit aea12f
Packit aea12f
	dst = ctext;
Packit aea12f
	dst_size = *ctext_len;
Packit aea12f
Packit c36854
	ret = _gnutls_iov_iter_init(&iter, iov, iovcnt, blocksize);
Packit c36854
	if (unlikely(ret < 0))
Packit c36854
		return gnutls_assert_val(ret);
Packit c36854
	while (1) {
Packit c36854
		ret = _gnutls_iov_iter_next(&iter, &p);
Packit c36854
		if (unlikely(ret < 0))
Packit c36854
			return gnutls_assert_val(ret);
Packit c36854
		if (ret == 0)
Packit c36854
			break;
Packit c36854
		blocks = ret;
Packit c36854
		if (unlikely((size_t) dst_size < blocksize * blocks))
Packit c36854
			return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
Packit c36854
		ret = _gnutls_cipher_encrypt2(&handle->ctx_enc, p,
Packit c36854
					      blocksize * blocks,
Packit c36854
					      dst, dst_size);
Packit c36854
		if (unlikely(ret < 0))
Packit c36854
			return gnutls_assert_val(ret);
Packit c36854
		DECR_LEN(dst_size, blocksize * blocks);
Packit c36854
		dst += blocksize * blocks;
Packit c36854
		total += blocksize * blocks;
Packit c36854
	}
Packit c36854
	if (iter.block_offset > 0) {
Packit c36854
		if (unlikely((size_t) dst_size < iter.block_offset))
Packit c36854
			return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
Packit c36854
		ret = _gnutls_cipher_encrypt2(&handle->ctx_enc,
Packit c36854
					      iter.block, iter.block_offset,
Packit c36854
					      dst, dst_size);
Packit c36854
		if (unlikely(ret < 0))
Packit c36854
			return gnutls_assert_val(ret);
Packit c36854
		DECR_LEN(dst_size, iter.block_offset);
Packit c36854
		dst += iter.block_offset;
Packit c36854
		total += iter.block_offset;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	if ((size_t)dst_size < tag_size)
Packit aea12f
		return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
Packit aea12f
Packit aea12f
	_gnutls_cipher_tag(&handle->ctx_enc, dst, tag_size);
Packit aea12f
Packit aea12f
	total += tag_size;
Packit aea12f
	*ctext_len = total;
Packit aea12f
Packit aea12f
	return 0;
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit c36854
 * gnutls_aead_cipher_encryptv2:
Packit c36854
 * @handle: is a #gnutls_aead_cipher_hd_t type.
Packit c36854
 * @nonce: the nonce to set
Packit c36854
 * @nonce_len: The length of the nonce
Packit c36854
 * @auth_iov: additional data to be authenticated
Packit c36854
 * @auth_iovcnt: The number of buffers in @auth_iov
Packit c36854
 * @iov: the data to be encrypted
Packit c36854
 * @iovcnt: The number of buffers in @iov
Packit c36854
 * @tag: The authentication tag
Packit c36854
 * @tag_size: The size of the tag to use (use zero for the default)
Packit c36854
 *
Packit c36854
 * This is similar to gnutls_aead_cipher_encrypt(), but it performs
Packit c36854
 * in-place encryption on the provided data buffers.
Packit c36854
 *
Packit c36854
 * Returns: Zero or a negative error code on error.
Packit c36854
 *
Packit c36854
 * Since: 3.6.10
Packit c36854
 **/
Packit c36854
int
Packit c36854
gnutls_aead_cipher_encryptv2(gnutls_aead_cipher_hd_t handle,
Packit c36854
			     const void *nonce, size_t nonce_len,
Packit c36854
			     const giovec_t *auth_iov, int auth_iovcnt,
Packit c36854
			     const giovec_t *iov, int iovcnt,
Packit c36854
			     void *tag, size_t *tag_size)
Packit c36854
{
Packit c36854
	api_aead_cipher_hd_st *h = handle;
Packit c36854
	ssize_t ret;
Packit c36854
	uint8_t *p;
Packit c36854
	ssize_t blocksize = handle->ctx_enc.e->blocksize;
Packit c36854
	struct iov_iter_st iter;
Packit c36854
	size_t blocks;
Packit c36854
	size_t _tag_size;
Packit c36854
Packit c36854
	if (tag_size == NULL || *tag_size == 0)
Packit c36854
		_tag_size = _gnutls_cipher_get_tag_size(h->ctx_enc.e);
Packit c36854
	else
Packit c36854
		_tag_size = *tag_size;
Packit c36854
Packit c36854
	if (_tag_size > (unsigned)_gnutls_cipher_get_tag_size(h->ctx_enc.e))
Packit c36854
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
Packit c36854
Packit c36854
	/* Limitation: this function provides an optimization under the internally registered
Packit c36854
	 * AEAD ciphers. When an AEAD cipher is used registered with gnutls_crypto_register_aead_cipher(),
Packit c36854
	 * then this becomes a convenience function as it missed the lower-level primitives
Packit c36854
	 * necessary for piecemeal encryption. */
Packit c36854
	if (handle->ctx_enc.e->only_aead || handle->ctx_enc.encrypt == NULL) {
Packit c36854
		/* ciphertext cannot be produced in a piecemeal approach */
Packit c36854
		struct iov_store_st auth;
Packit c36854
		struct iov_store_st ptext;
Packit c36854
		size_t ptext_size;
Packit c36854
Packit c36854
		ret = copy_from_iov(&auth, auth_iov, auth_iovcnt);
Packit c36854
		if (ret < 0)
Packit c36854
			return gnutls_assert_val(ret);
Packit c36854
Packit c36854
		ret = copy_from_iov(&ptext, iov, iovcnt);
Packit c36854
		if (ret < 0) {
Packit c36854
			gnutls_assert();
Packit c36854
			goto fallback_fail;
Packit c36854
		}
Packit c36854
Packit c36854
		ptext_size = ptext.size;
Packit c36854
Packit c36854
		/* append space for tag */
Packit c36854
		ret = iov_store_grow(&ptext, _tag_size);
Packit c36854
		if (ret < 0) {
Packit c36854
			gnutls_assert();
Packit c36854
			goto fallback_fail;
Packit c36854
		}
Packit c36854
Packit c36854
		ret = gnutls_aead_cipher_encrypt(handle, nonce, nonce_len,
Packit c36854
						 auth.data, auth.size,
Packit c36854
						 _tag_size,
Packit c36854
						 ptext.data, ptext_size,
Packit c36854
						 ptext.data, &ptext.size);
Packit c36854
		if (ret < 0) {
Packit c36854
			gnutls_assert();
Packit c36854
			goto fallback_fail;
Packit c36854
		}
Packit c36854
Packit c36854
		ret = copy_to_iov(&ptext, ptext_size, iov, iovcnt);
Packit c36854
		if (ret < 0) {
Packit c36854
			gnutls_assert();
Packit c36854
			goto fallback_fail;
Packit c36854
		}
Packit c36854
Packit c36854
		if (tag != NULL)
Packit c36854
			memcpy(tag,
Packit c36854
			       (uint8_t *) ptext.data + ptext_size,
Packit c36854
			       _tag_size);
Packit c36854
		if (tag_size != NULL)
Packit c36854
			*tag_size = _tag_size;
Packit c36854
Packit c36854
	fallback_fail:
Packit c36854
		iov_store_free(&auth);
Packit c36854
		iov_store_free(&ptext);
Packit c36854
Packit c36854
		return ret;
Packit c36854
	}
Packit c36854
Packit c36854
	ret = _gnutls_cipher_setiv(&handle->ctx_enc, nonce, nonce_len);
Packit c36854
	if (unlikely(ret < 0))
Packit c36854
		return gnutls_assert_val(ret);
Packit c36854
Packit c36854
	ret = _gnutls_iov_iter_init(&iter, auth_iov, auth_iovcnt, blocksize);
Packit c36854
	if (unlikely(ret < 0))
Packit c36854
		return gnutls_assert_val(ret);
Packit c36854
	while (1) {
Packit c36854
		ret = _gnutls_iov_iter_next(&iter, &p);
Packit c36854
		if (unlikely(ret < 0))
Packit c36854
			return gnutls_assert_val(ret);
Packit c36854
		if (ret == 0)
Packit c36854
			break;
Packit c36854
		blocks = ret;
Packit c36854
		ret = _gnutls_cipher_auth(&handle->ctx_enc, p,
Packit c36854
					  blocksize * blocks);
Packit c36854
		if (unlikely(ret < 0))
Packit c36854
			return gnutls_assert_val(ret);
Packit c36854
	}
Packit c36854
	if (iter.block_offset > 0) {
Packit c36854
		ret = _gnutls_cipher_auth(&handle->ctx_enc,
Packit c36854
					  iter.block, iter.block_offset);
Packit c36854
		if (unlikely(ret < 0))
Packit c36854
			return gnutls_assert_val(ret);
Packit c36854
	}
Packit c36854
Packit c36854
	ret = _gnutls_iov_iter_init(&iter, iov, iovcnt, blocksize);
Packit c36854
	if (unlikely(ret < 0))
Packit c36854
		return gnutls_assert_val(ret);
Packit c36854
	while (1) {
Packit c36854
		ret = _gnutls_iov_iter_next(&iter, &p);
Packit c36854
		if (unlikely(ret < 0))
Packit c36854
			return gnutls_assert_val(ret);
Packit c36854
		if (ret == 0)
Packit c36854
			break;
Packit c36854
		blocks = ret;
Packit c36854
		ret = _gnutls_cipher_encrypt2(&handle->ctx_enc,
Packit c36854
					      p, blocksize * blocks,
Packit c36854
					      p, blocksize * blocks);
Packit c36854
		if (unlikely(ret < 0))
Packit c36854
			return gnutls_assert_val(ret);
Packit c36854
	}
Packit c36854
	if (iter.block_offset > 0) {
Packit c36854
		ret = _gnutls_cipher_encrypt2(&handle->ctx_enc,
Packit c36854
					      iter.block, iter.block_offset,
Packit c36854
					      iter.block, iter.block_offset);
Packit c36854
		if (unlikely(ret < 0))
Packit c36854
			return gnutls_assert_val(ret);
Packit c36854
	}
Packit c36854
Packit c36854
	if (tag != NULL)
Packit c36854
		_gnutls_cipher_tag(&handle->ctx_enc, tag, _tag_size);
Packit c36854
	if (tag_size != NULL)
Packit c36854
		*tag_size = _tag_size;
Packit c36854
Packit c36854
	return 0;
Packit c36854
}
Packit c36854
Packit c36854
/**
Packit c36854
 * gnutls_aead_cipher_decryptv2:
Packit c36854
 * @handle: is a #gnutls_aead_cipher_hd_t type.
Packit c36854
 * @nonce: the nonce to set
Packit c36854
 * @nonce_len: The length of the nonce
Packit c36854
 * @auth_iov: additional data to be authenticated
Packit c36854
 * @auth_iovcnt: The number of buffers in @auth_iov
Packit c36854
 * @iov: the data to decrypt
Packit c36854
 * @iovcnt: The number of buffers in @iov
Packit c36854
 * @tag: The authentication tag
Packit c36854
 * @tag_size: The size of the tag to use (use zero for the default)
Packit c36854
 *
Packit c36854
 * This is similar to gnutls_aead_cipher_decrypt(), but it performs
Packit c36854
 * in-place encryption on the provided data buffers.
Packit c36854
 *
Packit c36854
 * Returns: Zero or a negative error code on error.
Packit c36854
 *
Packit c36854
 * Since: 3.6.10
Packit c36854
 **/
Packit c36854
int
Packit c36854
gnutls_aead_cipher_decryptv2(gnutls_aead_cipher_hd_t handle,
Packit c36854
			     const void *nonce, size_t nonce_len,
Packit c36854
			     const giovec_t *auth_iov, int auth_iovcnt,
Packit c36854
			     const giovec_t *iov, int iovcnt,
Packit c36854
			     void *tag, size_t tag_size)
Packit c36854
{
Packit c36854
	api_aead_cipher_hd_st *h = handle;
Packit c36854
	ssize_t ret;
Packit c36854
	uint8_t *p;
Packit c36854
	ssize_t blocksize = handle->ctx_enc.e->blocksize;
Packit c36854
	struct iov_iter_st iter;
Packit c36854
	size_t blocks;
Packit c36854
	uint8_t _tag[MAX_HASH_SIZE];
Packit c36854
Packit c36854
	if (tag_size == 0)
Packit c36854
		tag_size = _gnutls_cipher_get_tag_size(h->ctx_enc.e);
Packit c36854
	else if (tag_size > (unsigned)_gnutls_cipher_get_tag_size(h->ctx_enc.e))
Packit c36854
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
Packit c36854
Packit c36854
	/* Limitation: this function provides an optimization under the internally registered
Packit c36854
	 * AEAD ciphers. When an AEAD cipher is used registered with gnutls_crypto_register_aead_cipher(),
Packit c36854
	 * then this becomes a convenience function as it missed the lower-level primitives
Packit c36854
	 * necessary for piecemeal encryption. */
Packit c36854
	if (handle->ctx_enc.e->only_aead || handle->ctx_enc.encrypt == NULL) {
Packit c36854
		/* ciphertext cannot be produced in a piecemeal approach */
Packit c36854
		struct iov_store_st auth;
Packit c36854
		struct iov_store_st ctext;
Packit c36854
		size_t ctext_size;
Packit c36854
Packit c36854
		ret = copy_from_iov(&auth, auth_iov, auth_iovcnt);
Packit c36854
		if (ret < 0)
Packit c36854
			return gnutls_assert_val(ret);
Packit c36854
Packit c36854
		ret = copy_from_iov(&ctext, iov, iovcnt);
Packit c36854
		if (ret < 0) {
Packit c36854
			gnutls_assert();
Packit c36854
			goto fallback_fail;
Packit c36854
		}
Packit c36854
Packit c36854
		ctext_size = ctext.size;
Packit c36854
Packit c36854
		/* append tag */
Packit c36854
		ret = iov_store_grow(&ctext, tag_size);
Packit c36854
		if (ret < 0) {
Packit c36854
			gnutls_assert();
Packit c36854
			goto fallback_fail;
Packit c36854
		}
Packit c36854
		memcpy((uint8_t *) ctext.data + ctext_size, tag, tag_size);
Packit c36854
Packit c36854
		ret = gnutls_aead_cipher_decrypt(handle, nonce, nonce_len,
Packit c36854
						 auth.data, auth.size,
Packit c36854
						 tag_size,
Packit c36854
						 ctext.data, ctext.size,
Packit c36854
						 ctext.data, &ctext_size);
Packit c36854
		if (ret < 0) {
Packit c36854
			gnutls_assert();
Packit c36854
			goto fallback_fail;
Packit c36854
		}
Packit c36854
Packit c36854
		ret = copy_to_iov(&ctext, ctext_size, iov, iovcnt);
Packit c36854
		if (ret < 0) {
Packit c36854
			gnutls_assert();
Packit c36854
			goto fallback_fail;
Packit c36854
		}
Packit c36854
Packit c36854
	fallback_fail:
Packit c36854
		iov_store_free(&auth);
Packit c36854
		iov_store_free(&ctext);
Packit c36854
Packit c36854
		return ret;
Packit c36854
	}
Packit c36854
Packit c36854
	ret = _gnutls_cipher_setiv(&handle->ctx_enc, nonce, nonce_len);
Packit c36854
	if (unlikely(ret < 0))
Packit c36854
		return gnutls_assert_val(ret);
Packit c36854
Packit c36854
	ret = _gnutls_iov_iter_init(&iter, auth_iov, auth_iovcnt, blocksize);
Packit c36854
	if (unlikely(ret < 0))
Packit c36854
		return gnutls_assert_val(ret);
Packit c36854
	while (1) {
Packit c36854
		ret = _gnutls_iov_iter_next(&iter, &p);
Packit c36854
		if (unlikely(ret < 0))
Packit c36854
			return gnutls_assert_val(ret);
Packit c36854
		if (ret == 0)
Packit c36854
			break;
Packit c36854
		blocks = ret;
Packit c36854
		ret = _gnutls_cipher_auth(&handle->ctx_enc, p,
Packit c36854
					  blocksize * blocks);
Packit c36854
		if (unlikely(ret < 0))
Packit c36854
			return gnutls_assert_val(ret);
Packit c36854
	}
Packit c36854
	if (iter.block_offset > 0) {
Packit c36854
		ret = _gnutls_cipher_auth(&handle->ctx_enc,
Packit c36854
					  iter.block, iter.block_offset);
Packit c36854
		if (unlikely(ret < 0))
Packit c36854
			return gnutls_assert_val(ret);
Packit c36854
	}
Packit c36854
Packit c36854
	ret = _gnutls_iov_iter_init(&iter, iov, iovcnt, blocksize);
Packit c36854
	if (unlikely(ret < 0))
Packit c36854
		return gnutls_assert_val(ret);
Packit c36854
	while (1) {
Packit c36854
		ret = _gnutls_iov_iter_next(&iter, &p);
Packit c36854
		if (unlikely(ret < 0))
Packit c36854
			return gnutls_assert_val(ret);
Packit c36854
		if (ret == 0)
Packit c36854
			break;
Packit c36854
		blocks = ret;
Packit c36854
		ret = _gnutls_cipher_decrypt2(&handle->ctx_enc,
Packit c36854
					      p, blocksize * blocks,
Packit c36854
					      p, blocksize * blocks);
Packit c36854
		if (unlikely(ret < 0))
Packit c36854
			return gnutls_assert_val(ret);
Packit c36854
	}
Packit c36854
	if (iter.block_offset > 0) {
Packit c36854
		ret = _gnutls_cipher_decrypt2(&handle->ctx_enc,
Packit c36854
					      iter.block, iter.block_offset,
Packit c36854
					      iter.block, iter.block_offset);
Packit c36854
		if (unlikely(ret < 0))
Packit c36854
			return gnutls_assert_val(ret);
Packit c36854
	}
Packit c36854
Packit c36854
	if (tag != NULL) {
Packit c36854
		_gnutls_cipher_tag(&handle->ctx_enc, _tag, tag_size);
Packit c36854
		if (gnutls_memcmp(_tag, tag, tag_size) != 0)
Packit c36854
			return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
Packit c36854
	}
Packit c36854
Packit c36854
	return 0;
Packit c36854
}
Packit c36854
Packit c36854
/**
Packit aea12f
 * gnutls_aead_cipher_deinit:
Packit aea12f
 * @handle: is a #gnutls_aead_cipher_hd_t type.
Packit aea12f
 *
Packit aea12f
 * This function will deinitialize all resources occupied by the given
Packit aea12f
 * authenticated-encryption context.
Packit aea12f
 *
Packit aea12f
 * Since: 3.4.0
Packit aea12f
 **/
Packit aea12f
void gnutls_aead_cipher_deinit(gnutls_aead_cipher_hd_t handle)
Packit aea12f
{
Packit aea12f
	_gnutls_aead_cipher_deinit(handle);
Packit aea12f
	gnutls_free(handle);
Packit aea12f
}