Beispiel #1
0
/* This is the actual encryption 
 * Encrypts the given compressed datum, and puts the result to cipher_data,
 * which has cipher_size size.
 * return the actual encrypted data length.
 */
static int
compressed_to_ciphertext(gnutls_session_t session,
			 uint8_t * cipher_data, int cipher_size,
			 gnutls_datum_t * compressed,
			 size_t min_pad,
			 content_type_t type,
			 record_parameters_st * params)
{
	uint8_t pad;
	int length, ret;
	uint8_t preamble[MAX_PREAMBLE_SIZE];
	int preamble_size;
	int tag_size =
	    _gnutls_auth_cipher_tag_len(&params->write.cipher_state);
	int blocksize = _gnutls_cipher_get_block_size(params->cipher);
	unsigned algo_type = _gnutls_cipher_type(params->cipher);
	uint8_t *data_ptr, *full_cipher_ptr;
	const version_entry_st *ver = get_version(session);
	int explicit_iv = _gnutls_version_has_explicit_iv(ver);
	int auth_cipher =
	    _gnutls_auth_cipher_is_aead(&params->write.cipher_state);
	uint8_t nonce[MAX_CIPHER_BLOCK_SIZE];
	unsigned imp_iv_size = 0, exp_iv_size = 0;
	bool etm = 0;

	if (unlikely(ver == NULL))
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

	if (algo_type == CIPHER_BLOCK && params->etm != 0)
		etm = 1;

	_gnutls_hard_log("ENC[%p]: cipher: %s, MAC: %s, Epoch: %u\n",
			 session, _gnutls_cipher_get_name(params->cipher),
			 _gnutls_mac_get_name(params->mac),
			 (unsigned int) params->epoch);

	/* Calculate the encrypted length (padding etc.)
	 */
	if (algo_type == CIPHER_BLOCK) {
		/* Call _gnutls_rnd() once. Get data used for the IV
		 */
		ret = _gnutls_rnd(GNUTLS_RND_NONCE, nonce, blocksize);
		if (ret < 0)
			return gnutls_assert_val(ret);

		pad = min_pad;

		length =
		    calc_enc_length_block(session, ver, compressed->size,
					  tag_size, &pad, auth_cipher,
					  blocksize, etm);
	} else { /* AEAD + STREAM */
		imp_iv_size = _gnutls_cipher_get_implicit_iv_size(params->cipher);
		exp_iv_size = _gnutls_cipher_get_explicit_iv_size(params->cipher);

		pad = 0;
		length =
		    calc_enc_length_stream(session, compressed->size,
					   tag_size, auth_cipher, exp_iv_size);
	}

	if (length < 0)
		return gnutls_assert_val(length);

	/* copy the encrypted data to cipher_data.
	 */
	if (cipher_size < length)
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

	data_ptr = cipher_data;
	full_cipher_ptr = data_ptr;

	if (algo_type == CIPHER_BLOCK || algo_type == CIPHER_STREAM) {
		if (algo_type == CIPHER_BLOCK && explicit_iv != 0) {
			/* copy the random IV.
			 */
			memcpy(data_ptr, nonce, blocksize);
			_gnutls_auth_cipher_setiv(&params->write.
						  cipher_state, data_ptr,
						  blocksize);

			data_ptr += blocksize;
			cipher_data += blocksize;
		}

	} else { /* AEAD */
		/* Values in AEAD are pretty fixed in TLS 1.2 for 128-bit block
		 */
		if (params->write.IV.data == NULL
		    || params->write.IV.size !=
		    imp_iv_size)
			return
			    gnutls_assert_val
			    (GNUTLS_E_INTERNAL_ERROR);

		/* Instead of generating a new nonce on every packet, we use the
		 * write.sequence_number (It is a MAY on RFC 5288), and safer
		 * as it will never reuse a value.
		 */
		memcpy(nonce, params->write.IV.data,
		       params->write.IV.size);
		memcpy(&nonce[imp_iv_size],
		       UINT64DATA(params->write.sequence_number),
		       8);

		/* copy the explicit part */
		memcpy(data_ptr, &nonce[imp_iv_size],
		       exp_iv_size);

		data_ptr += exp_iv_size;
		cipher_data += exp_iv_size;
	}

	if (etm)
		ret = length-tag_size;
	else
		ret = compressed->size;

	preamble_size =
	    make_preamble(UINT64DATA(params->write.sequence_number),
			  type, ret, ver, preamble);

	if (algo_type == CIPHER_BLOCK || algo_type == CIPHER_STREAM) {
		/* add the authenticated data */
		ret =
		    _gnutls_auth_cipher_add_auth(&params->write.cipher_state,
					 preamble, preamble_size);
		if (ret < 0)
			return gnutls_assert_val(ret);

		if (etm && explicit_iv) {
			/* In EtM we need to hash the IV as well */
			ret =
			    _gnutls_auth_cipher_add_auth(&params->write.cipher_state,
						 full_cipher_ptr, blocksize);
			if (ret < 0)
				return gnutls_assert_val(ret);
		}

		/* Actual encryption.
		 */
		ret =
		    _gnutls_auth_cipher_encrypt2_tag(&params->write.cipher_state,
						     compressed->data,
						     compressed->size, cipher_data,
						     cipher_size, pad);
		if (ret < 0)
			return gnutls_assert_val(ret);
	} else { /* AEAD */
		ret = _gnutls_aead_cipher_encrypt(&params->write.cipher_state.cipher,
						  nonce, imp_iv_size + exp_iv_size,
						  preamble, preamble_size,
						  tag_size,
						  compressed->data, compressed->size,
						  cipher_data, cipher_size);
		if (ret < 0)
			return gnutls_assert_val(ret);
	}

	return length;
}
Beispiel #2
0
/* This is the actual encryption 
 * Encrypts the given compressed datum, and puts the result to cipher_data,
 * which has cipher_size size.
 * return the actual encrypted data length.
 */
static int
compressed_to_ciphertext(gnutls_session_t session,
			 uint8_t * cipher_data, int cipher_size,
			 gnutls_datum_t * compressed,
			 size_t min_pad,
			 content_type_t type,
			 record_parameters_st * params)
{
	uint8_t pad;
	int length, ret;
	uint8_t preamble[MAX_PREAMBLE_SIZE];
	int preamble_size;
	int tag_size =
	    _gnutls_auth_cipher_tag_len(&params->write.cipher_state);
	int blocksize = _gnutls_cipher_get_block_size(params->cipher);
	unsigned block_algo = _gnutls_cipher_is_block(params->cipher);
	uint8_t *data_ptr;
	const version_entry_st *ver = get_version(session);
	int explicit_iv = _gnutls_version_has_explicit_iv(ver);
	int auth_cipher =
	    _gnutls_auth_cipher_is_aead(&params->write.cipher_state);
	uint8_t nonce[MAX_CIPHER_BLOCK_SIZE];
	unsigned iv_size;

	if (unlikely(ver == NULL))
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

	iv_size = _gnutls_cipher_get_implicit_iv_size(params->cipher);

	_gnutls_hard_log("ENC[%p]: cipher: %s, MAC: %s, Epoch: %u\n",
			 session, _gnutls_cipher_get_name(params->cipher),
			 _gnutls_mac_get_name(params->mac),
			 (unsigned int) params->epoch);

	preamble_size =
	    make_preamble(UINT64DATA
			  (params->write.sequence_number),
			  type, compressed->size, ver, preamble);

	/* Calculate the encrypted length (padding etc.)
	 */
	if (block_algo == CIPHER_BLOCK) {
		/* Call _gnutls_rnd() once. Get data used for the IV
		 */
		ret = _gnutls_rnd(GNUTLS_RND_NONCE, nonce, blocksize);
		if (ret < 0)
			return gnutls_assert_val(ret);

		pad = min_pad;

		length =
		    calc_enc_length_block(session, ver, compressed->size,
					  tag_size, &pad, auth_cipher,
					  blocksize);
	} else {
		pad = 0;
		length =
		    calc_enc_length_stream(session, compressed->size,
					   tag_size, auth_cipher);
	}

	if (length < 0)
		return gnutls_assert_val(length);

	/* copy the encrypted data to cipher_data.
	 */
	if (cipher_size < length)
		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

	data_ptr = cipher_data;

	if (explicit_iv) {	/* TLS 1.1 or later */
		if (block_algo == CIPHER_BLOCK) {
			/* copy the random IV.
			 */
			memcpy(data_ptr, nonce, blocksize);
			_gnutls_auth_cipher_setiv(&params->write.
						  cipher_state, data_ptr,
						  blocksize);

			data_ptr += blocksize;
			cipher_data += blocksize;
		} else if (auth_cipher) {
			/* Values in AEAD are pretty fixed in TLS 1.2 for 128-bit block
			 */
			if (params->write.IV.data == NULL
			    || params->write.IV.size !=
			    AEAD_IMPLICIT_DATA_SIZE)
				return
				    gnutls_assert_val
				    (GNUTLS_E_INTERNAL_ERROR);

			/* Instead of generating a new nonce on every packet, we use the
			 * write.sequence_number (It is a MAY on RFC 5288).
			 */
			memcpy(nonce, params->write.IV.data,
			       params->write.IV.size);
			memcpy(&nonce[AEAD_IMPLICIT_DATA_SIZE],
			       UINT64DATA(params->write.sequence_number),
			       8);

			_gnutls_auth_cipher_setiv(&params->write.
						  cipher_state, nonce,
						  AEAD_IMPLICIT_DATA_SIZE +
						  AEAD_EXPLICIT_DATA_SIZE);

			/* copy the explicit part */
			memcpy(data_ptr, &nonce[AEAD_IMPLICIT_DATA_SIZE],
			       AEAD_EXPLICIT_DATA_SIZE);

			data_ptr += AEAD_EXPLICIT_DATA_SIZE;
			cipher_data += AEAD_EXPLICIT_DATA_SIZE;
		} else if (iv_size > 0)
			_gnutls_auth_cipher_setiv(&params->write.
						  cipher_state,
						  UINT64DATA(params->write.
							     sequence_number),
						  8);
	} else {
		/* AEAD ciphers have an explicit IV. Shouldn't be used otherwise.
		 */
		if (auth_cipher)
			return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
		else if (block_algo == CIPHER_STREAM && iv_size > 0)
			_gnutls_auth_cipher_setiv(&params->write.
						  cipher_state,
						  UINT64DATA(params->write.
							     sequence_number),
						  8);
	}

	_gnutls_auth_cipher_set_mac_nonce(&params->write.cipher_state,
					  UINT64DATA(params->write.
						     sequence_number), 8);

	/* add the authenticate data */
	ret =
	    _gnutls_auth_cipher_add_auth(&params->write.cipher_state,
					 preamble, preamble_size);
	if (ret < 0)
		return gnutls_assert_val(ret);

	/* Actual encryption.
	 */
	ret =
	    _gnutls_auth_cipher_encrypt2_tag(&params->write.cipher_state,
					     compressed->data,
					     compressed->size, cipher_data,
					     cipher_size, pad);
	if (ret < 0)
		return gnutls_assert_val(ret);

	return length;
}