Exemplo n.º 1
0
static void dummy_wait(record_parameters_st * params,
		       gnutls_datum_t * plaintext, unsigned pad_failed,
		       unsigned int pad, unsigned total)
{
	/* this hack is only needed on CBC ciphers */
	if (_gnutls_cipher_is_block(params->cipher) == CIPHER_BLOCK) {
		unsigned len;

		/* force an additional hash compression function evaluation to prevent timing 
		 * attacks that distinguish between wrong-mac + correct pad, from wrong-mac + incorrect pad.
		 */
		if (pad_failed == 0 && pad > 0) {
			len = _gnutls_mac_block_size(params->mac);
			if (len > 0) {
				/* This is really specific to the current hash functions.
				 * It should be removed once a protocol fix is in place.
				 */
				if ((pad + total) % len > len - 9
				    && total % len <= len - 9) {
					if (len < plaintext->size)
						_gnutls_auth_cipher_add_auth
						    (&params->read.
						     cipher_state,
						     plaintext->data, len);
					else
						_gnutls_auth_cipher_add_auth
						    (&params->read.
						     cipher_state,
						     plaintext->data,
						     plaintext->size);
				}
			}
		}
	}
}
Exemplo n.º 2
0
/* returns overhead imposed by the record layer (encryption/compression)
 * etc. It does not include the record layer headers, since the caller
 * needs to cope with rounding to multiples of blocksize, and the header
 * is outside that.
 *
 * blocksize: will contain the block size when padding may be required or 1
 *
 * It may return a negative error code on error.
 */
static int record_overhead_rt(gnutls_session_t session, unsigned int *blocksize)
{
record_parameters_st *params;
int total = 0, ret, iv_size;

  if (session->internals.initial_negotiation_completed == 0)
    return GNUTLS_E_INVALID_REQUEST;

  ret = _gnutls_epoch_get (session, EPOCH_WRITE_CURRENT, &params);
  if (ret < 0)
    return gnutls_assert_val(ret);

  /* requires padding */
  iv_size = _gnutls_cipher_get_iv_size(params->cipher_algorithm);

  if (_gnutls_cipher_is_block (params->cipher_algorithm) == CIPHER_BLOCK)
    {
      *blocksize = iv_size;

      total += iv_size; /* iv_size == block_size in DTLS */

      /* We always pad with at least one byte; never 0. */
      total++;
    }
  else
    {
      *blocksize = 1;
    }
  
  if (params->mac_algorithm == GNUTLS_MAC_AEAD)
    total += _gnutls_cipher_get_tag_size(params->cipher_algorithm);
  else
    {
      ret = _gnutls_hmac_get_algo_len(params->mac_algorithm);
      if (ret < 0)
        return gnutls_assert_val(ret);
      total+=ret;
    }

  if (params->compression_algorithm != GNUTLS_COMP_NULL)
    total += EXTRA_COMP_SIZE;

  return total;
}
Exemplo n.º 3
0
/* Deciphers the ciphertext packet, and puts the result to compress_data, of compress_size.
 * Returns the actual compressed packet size.
 */
int
_gnutls_ciphertext2compressed (gnutls_session_t session,
                               opaque * compress_data,
                               int compress_size,
                               gnutls_datum_t ciphertext, uint8_t type,
                               record_parameters_st * params)
{
  uint8_t MAC[MAX_HASH_SIZE];
  uint16_t c_length;
  uint8_t pad;
  int length;
  uint16_t blocksize;
  int ret, i, pad_failed = 0;
  opaque preamble[PREAMBLE_SIZE];
  int preamble_size;
  int ver = gnutls_protocol_get_version (session);
  int hash_size = _gnutls_hash_get_algo_len (params->mac_algorithm);

  blocksize = gnutls_cipher_get_block_size (params->cipher_algorithm);


  /* actual decryption (inplace)
   */
  switch (_gnutls_cipher_is_block (params->cipher_algorithm))
    {
    case CIPHER_STREAM:
      if ((ret =
           _gnutls_cipher_decrypt (&params->read.cipher_state,
                                   ciphertext.data, ciphertext.size)) < 0)
        {
          gnutls_assert ();
          return ret;
        }

      length = ciphertext.size - hash_size;

      break;
    case CIPHER_BLOCK:
      if ((ciphertext.size < blocksize) || (ciphertext.size % blocksize != 0))
        {
          gnutls_assert ();
          return GNUTLS_E_DECRYPTION_FAILED;
        }

      if ((ret =
           _gnutls_cipher_decrypt (&params->read.cipher_state,
                                   ciphertext.data, ciphertext.size)) < 0)
        {
          gnutls_assert ();
          return ret;
        }

      /* ignore the IV in TLS 1.1.
       */
      if (_gnutls_version_has_explicit_iv
          (session->security_parameters.version))
        {
          ciphertext.size -= blocksize;
          ciphertext.data += blocksize;

          if (ciphertext.size == 0)
            {
              gnutls_assert ();
              return GNUTLS_E_DECRYPTION_FAILED;
            }
        }

      pad = ciphertext.data[ciphertext.size - 1] + 1;   /* pad */

      if ((int) pad > (int) ciphertext.size - hash_size)
        {
          gnutls_assert ();
          _gnutls_record_log
            ("REC[%p]: Short record length %d > %d - %d (under attack?)\n",
             session, pad, ciphertext.size, hash_size);
          /* We do not fail here. We check below for the
           * the pad_failed. If zero means success.
           */
          pad_failed = GNUTLS_E_DECRYPTION_FAILED;
        }

      length = ciphertext.size - hash_size - pad;

      /* Check the pading bytes (TLS 1.x)
       */
      if (_gnutls_version_has_variable_padding (ver) && pad_failed == 0)
        for (i = 2; i < pad; i++)
          {
            if (ciphertext.data[ciphertext.size - i] !=
                ciphertext.data[ciphertext.size - 1])
              pad_failed = GNUTLS_E_DECRYPTION_FAILED;
          }
      break;
    default:
      gnutls_assert ();
      return GNUTLS_E_INTERNAL_ERROR;
    }

  if (length < 0)
    length = 0;
  c_length = _gnutls_conv_uint16 ((uint16_t) length);

  /* Pass the type, version, length and compressed through
   * MAC.
   */
  if (params->mac_algorithm != GNUTLS_MAC_NULL)
    {
      digest_hd_st td;

      ret = mac_init (&td, params->mac_algorithm,
                      params->read.mac_secret.data,
                      params->read.mac_secret.size, ver);

      if (ret < 0)
        {
          gnutls_assert ();
          return GNUTLS_E_INTERNAL_ERROR;
        }

      preamble_size =
        make_preamble (UINT64DATA
                       (params->read.sequence_number), type,
                       c_length, ver, preamble);
      mac_hash (&td, preamble, preamble_size, ver);
      if (length > 0)
        mac_hash (&td, ciphertext.data, length, ver);

      mac_deinit (&td, MAC, ver);
    }

  /* This one was introduced to avoid a timing attack against the TLS
   * 1.0 protocol.
   */
  if (pad_failed != 0)
    {
      gnutls_assert ();
      return pad_failed;
    }

  /* HMAC was not the same. 
   */
  if (memcmp (MAC, &ciphertext.data[length], hash_size) != 0)
    {
      gnutls_assert ();
      return GNUTLS_E_DECRYPTION_FAILED;
    }

  /* copy the decrypted stuff to compress_data.
   */
  if (compress_size < length)
    {
      gnutls_assert ();
      return GNUTLS_E_DECOMPRESSION_FAILED;
    }
  memcpy (compress_data, ciphertext.data, length);

  return length;
}
Exemplo n.º 4
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.
 */
int
_gnutls_compressed2ciphertext (gnutls_session_t session,
                               opaque * cipher_data, int cipher_size,
                               gnutls_datum_t compressed,
                               content_type_t _type, int random_pad,
                               record_parameters_st * params)
{
  uint8_t MAC[MAX_HASH_SIZE];
  uint16_t c_length;
  uint8_t pad;
  int length, ret;
  uint8_t type = _type;
  opaque preamble[PREAMBLE_SIZE];
  int preamble_size;
  int hash_size = _gnutls_hash_get_algo_len (params->mac_algorithm);
  int blocksize = gnutls_cipher_get_block_size (params->cipher_algorithm);
  cipher_type_t block_algo =
    _gnutls_cipher_is_block (params->cipher_algorithm);
  opaque *data_ptr;
  int ver = gnutls_protocol_get_version (session);


  /* Initialize MAC */

  c_length = _gnutls_conv_uint16 (compressed.size);

  if (params->mac_algorithm != GNUTLS_MAC_NULL)
    {                           /* actually when the algorithm in not the NULL one */
      digest_hd_st td;

      ret = mac_init (&td, params->mac_algorithm,
                      params->write.mac_secret.data,
                      params->write.mac_secret.size, ver);

      if (ret < 0)
        {
          gnutls_assert ();
          return ret;
        }
      preamble_size =
        make_preamble (UINT64DATA
                       (params->write.sequence_number),
                       type, c_length, ver, preamble);
      mac_hash (&td, preamble, preamble_size, ver);
      mac_hash (&td, compressed.data, compressed.size, ver);
      mac_deinit (&td, MAC, ver);
    }


  /* Calculate the encrypted length (padding etc.)
   */
  length =
    calc_enc_length (session, compressed.size, hash_size, &pad,
                     random_pad, block_algo, blocksize);
  if (length < 0)
    {
      gnutls_assert ();
      return length;
    }

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

  data_ptr = cipher_data;
  if (block_algo == CIPHER_BLOCK &&
      _gnutls_version_has_explicit_iv (session->security_parameters.version))
    {
      /* copy the random IV.
       */
      ret = _gnutls_rnd (GNUTLS_RND_NONCE, data_ptr, blocksize);
      if (ret < 0)
        {
          gnutls_assert ();
          return ret;
        }

      data_ptr += blocksize;
    }

  memcpy (data_ptr, compressed.data, compressed.size);
  data_ptr += compressed.size;

  if (hash_size > 0)
    {
      memcpy (data_ptr, MAC, hash_size);
      data_ptr += hash_size;
    }
  if (block_algo == CIPHER_BLOCK && pad > 0)
    {
      memset (data_ptr, pad - 1, pad);
    }


  /* Actual encryption (inplace).
   */
  ret =
    _gnutls_cipher_encrypt (&params->write.cipher_state, cipher_data, length);
  if (ret < 0)
    {
      gnutls_assert ();
      return ret;
    }

  return length;
}
Exemplo n.º 5
0
/* Deciphers the ciphertext packet, and puts the result to compress_data, of compress_size.
 * Returns the actual compressed packet size.
 */
int
_gnutls_ciphertext2compressed (gnutls_session_t session,
			       opaque * compress_data,
			       int compress_size,
			       gnutls_datum_t ciphertext, uint8_t type)
{
  uint8_t MAC[MAX_HASH_SIZE];
  uint16_t c_length;
  uint8_t pad;
  int length;
  digest_hd_st td;
  uint16_t blocksize;
  int ret, i, pad_failed = 0;
  uint8_t major, minor;
  gnutls_protocol_t ver;
  int hash_size =
    _gnutls_hash_get_algo_len (session->security_parameters.
			       read_mac_algorithm);

  ver = gnutls_protocol_get_version (session);
  minor = _gnutls_version_get_minor (ver);
  major = _gnutls_version_get_major (ver);

  blocksize =
    _gnutls_cipher_get_block_size (session->security_parameters.
				   read_bulk_cipher_algorithm);

  /* initialize MAC 
   */
  ret = mac_init (&td, session->security_parameters.read_mac_algorithm,
		  session->connection_state.read_mac_secret.data,
		  session->connection_state.read_mac_secret.size, ver);

  if (ret < 0
      && session->security_parameters.read_mac_algorithm != GNUTLS_MAC_NULL)
    {
      gnutls_assert ();
      return GNUTLS_E_INTERNAL_ERROR;
    }

  /* actual decryption (inplace)
   */
  switch (_gnutls_cipher_is_block
	  (session->security_parameters.read_bulk_cipher_algorithm))
    {
    case CIPHER_STREAM:
      if ((ret =
	   _gnutls_cipher_decrypt (&session->connection_state.
				   read_cipher_state, ciphertext.data,
				   ciphertext.size)) < 0)
	{
	  gnutls_assert ();
	  return ret;
	}

      length = ciphertext.size - hash_size;

      break;
    case CIPHER_BLOCK:
      if ((ciphertext.size < blocksize) || (ciphertext.size % blocksize != 0))
	{
	  gnutls_assert ();
	  return GNUTLS_E_DECRYPTION_FAILED;
	}

      if ((ret =
	   _gnutls_cipher_decrypt (&session->connection_state.
				   read_cipher_state, ciphertext.data,
				   ciphertext.size)) < 0)
	{
	  gnutls_assert ();
	  return ret;
	}

      /* ignore the IV in TLS 1.1.
       */
      if (session->security_parameters.version >= GNUTLS_TLS1_1)
	{
	  ciphertext.size -= blocksize;
	  ciphertext.data += blocksize;

	  if (ciphertext.size == 0)
	    {
	      gnutls_assert ();
	      return GNUTLS_E_DECRYPTION_FAILED;
	    }
	}

      pad = ciphertext.data[ciphertext.size - 1] + 1;	/* pad */

      if ((int) pad > (int) ciphertext.size - hash_size)
	{
	  gnutls_assert ();
	  _gnutls_record_log
	    ("REC[%x]: Short record length %d > %d - %d (under attack?)\n",
	     session, pad, ciphertext.size, hash_size);
	  /* We do not fail here. We check below for the
	   * the pad_failed. If zero means success.
	   */
	  pad_failed = GNUTLS_E_DECRYPTION_FAILED;
	}

      length = ciphertext.size - hash_size - pad;

      /* Check the pading bytes (TLS 1.x)
       */
      if (ver >= GNUTLS_TLS1 && pad_failed == 0)
	for (i = 2; i < pad; i++)
	  {
	    if (ciphertext.data[ciphertext.size - i] !=
		ciphertext.data[ciphertext.size - 1])
	      pad_failed = GNUTLS_E_DECRYPTION_FAILED;
	  }
      break;
    default:
      gnutls_assert ();
      return GNUTLS_E_INTERNAL_ERROR;
    }

  if (length < 0)
    length = 0;
  c_length = _gnutls_conv_uint16 ((uint16_t) length);

  /* Pass the type, version, length and compressed through
   * MAC.
   */
  if (session->security_parameters.read_mac_algorithm != GNUTLS_MAC_NULL)
    {
      _gnutls_hmac (&td,
		    UINT64DATA (session->connection_state.
				read_sequence_number), 8);

      _gnutls_hmac (&td, &type, 1);
      if (ver >= GNUTLS_TLS1)
	{			/* TLS 1.x */
	  _gnutls_hmac (&td, &major, 1);
	  _gnutls_hmac (&td, &minor, 1);
	}
      _gnutls_hmac (&td, &c_length, 2);

      if (length > 0)
	_gnutls_hmac (&td, ciphertext.data, length);

      mac_deinit (&td, MAC, ver);
    }

  /* This one was introduced to avoid a timing attack against the TLS
   * 1.0 protocol.
   */
  if (pad_failed != 0)
    return pad_failed;

  /* HMAC was not the same. 
   */
  if (memcmp (MAC, &ciphertext.data[length], hash_size) != 0)
    {
      gnutls_assert ();
      return GNUTLS_E_DECRYPTION_FAILED;
    }

  /* copy the decrypted stuff to compress_data.
   */
  if (compress_size < length)
    {
      gnutls_assert ();
      return GNUTLS_E_DECOMPRESSION_FAILED;
    }
  memcpy (compress_data, ciphertext.data, length);

  return length;
}
Exemplo n.º 6
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.
 */
int
_gnutls_compressed2ciphertext (gnutls_session_t session,
			       opaque * cipher_data, int cipher_size,
			       gnutls_datum_t compressed,
			       content_type_t _type, int random_pad)
{
  uint8_t MAC[MAX_HASH_SIZE];
  uint16_t c_length;
  uint8_t pad;
  int length, ret;
  digest_hd_st td;
  uint8_t type = _type;
  uint8_t major, minor;
  int hash_size =
    _gnutls_hash_get_algo_len (session->security_parameters.
			       write_mac_algorithm);
  gnutls_protocol_t ver;
  int blocksize =
    _gnutls_cipher_get_block_size (session->security_parameters.
				   write_bulk_cipher_algorithm);
  cipher_type_t block_algo =
    _gnutls_cipher_is_block (session->security_parameters.
			     write_bulk_cipher_algorithm);
  opaque *data_ptr;


  ver = gnutls_protocol_get_version (session);
  minor = _gnutls_version_get_minor (ver);
  major = _gnutls_version_get_major (ver);


  /* Initialize MAC */
  ret = mac_init (&td, session->security_parameters.write_mac_algorithm,
		  session->connection_state.write_mac_secret.data,
		  session->connection_state.write_mac_secret.size, ver);

  if (ret < 0
      && session->security_parameters.write_mac_algorithm != GNUTLS_MAC_NULL)
    {
      gnutls_assert ();
      return ret;
    }

  c_length = _gnutls_conv_uint16 (compressed.size);

  if (session->security_parameters.write_mac_algorithm != GNUTLS_MAC_NULL)
    {				/* actually when the algorithm in not the NULL one */
      _gnutls_hmac (&td,
		    UINT64DATA (session->connection_state.
				write_sequence_number), 8);

      _gnutls_hmac (&td, &type, 1);
      if (ver >= GNUTLS_TLS1)
	{			/* TLS 1.0 or higher */
	  _gnutls_hmac (&td, &major, 1);
	  _gnutls_hmac (&td, &minor, 1);
	}
      _gnutls_hmac (&td, &c_length, 2);
      _gnutls_hmac (&td, compressed.data, compressed.size);
      mac_deinit (&td, MAC, ver);
    }


  /* Calculate the encrypted length (padding etc.)
   */
  length =
    calc_enc_length (session, compressed.size, hash_size, &pad,
		     random_pad, block_algo, blocksize);
  if (length < 0)
    {
      gnutls_assert ();
      return length;
    }

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

  data_ptr = cipher_data;
  if (block_algo == CIPHER_BLOCK &&
      session->security_parameters.version >= GNUTLS_TLS1_1)
    {
      /* copy the random IV.
       */
      ret = _gnutls_rnd (GNUTLS_RND_NONCE, data_ptr, blocksize);
      if (ret < 0)
	{
	  gnutls_assert ();
	  return ret;
	}

      data_ptr += blocksize;
    }

  memcpy (data_ptr, compressed.data, compressed.size);
  data_ptr += compressed.size;

  if (hash_size > 0)
    {
      memcpy (data_ptr, MAC, hash_size);
      data_ptr += hash_size;
    }
  if (block_algo == CIPHER_BLOCK && pad > 0)
    {
      memset (data_ptr, pad - 1, pad);
    }


  /* Actual encryption (inplace).
   */
  ret =
    _gnutls_cipher_encrypt (&session->connection_state.write_cipher_state,
			    cipher_data, length);
  if (ret < 0)
    {
      gnutls_assert ();
      return ret;
    }

  return length;
}
Exemplo n.º 7
0
/* Deciphers the ciphertext packet, and puts the result to compress_data, of compress_size.
 * Returns the actual compressed packet size.
 */
static int
ciphertext_to_compressed (gnutls_session_t session,
                          gnutls_datum_t *ciphertext, 
                          opaque * compress_data,
                          int compress_size,
                          uint8_t type, record_parameters_st * params, 
                          uint64* sequence)
{
  uint8_t tag[MAX_HASH_SIZE];
  uint8_t pad;
  int length, length_to_decrypt;
  uint16_t blocksize;
  int ret, i, pad_failed = 0;
  opaque preamble[MAX_PREAMBLE_SIZE];
  int preamble_size;
  int ver = gnutls_protocol_get_version (session);
  int tag_size = _gnutls_auth_cipher_tag_len (&params->read.cipher_state);
  int explicit_iv = _gnutls_version_has_explicit_iv (session->security_parameters.version);

  blocksize = gnutls_cipher_get_block_size (params->cipher_algorithm);

  /* actual decryption (inplace)
   */
  switch (_gnutls_cipher_is_block (params->cipher_algorithm))
    {
    case CIPHER_STREAM:
      /* The way AEAD ciphers are defined in RFC5246, it allows
       * only stream ciphers.
       */
      if (explicit_iv && _gnutls_auth_cipher_is_aead(&params->read.cipher_state))
        {
          uint8_t nonce[blocksize];
          /* Values in AEAD are pretty fixed in TLS 1.2 for 128-bit block
           */
          if (params->read.IV.data == NULL || params->read.IV.size != 4)
            return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
          
          if (ciphertext->size < tag_size+AEAD_EXPLICIT_DATA_SIZE)
            return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);

          memcpy(nonce, params->read.IV.data, AEAD_IMPLICIT_DATA_SIZE);
          memcpy(&nonce[AEAD_IMPLICIT_DATA_SIZE], ciphertext->data, AEAD_EXPLICIT_DATA_SIZE);
          
          _gnutls_auth_cipher_setiv(&params->read.cipher_state, nonce, AEAD_EXPLICIT_DATA_SIZE+AEAD_IMPLICIT_DATA_SIZE);

          ciphertext->data += AEAD_EXPLICIT_DATA_SIZE;
          ciphertext->size -= AEAD_EXPLICIT_DATA_SIZE;
          
          length_to_decrypt = ciphertext->size - tag_size;
        }
      else
        {
          if (ciphertext->size < tag_size)
            return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
  
          length_to_decrypt = ciphertext->size;
        }

      length = ciphertext->size - tag_size;

      /* Pass the type, version, length and compressed through
       * MAC.
       */
      preamble_size =
        make_preamble (UINT64DATA(*sequence), type,
                       length, ver, preamble);

      _gnutls_auth_cipher_add_auth (&params->read.cipher_state, preamble, preamble_size);

      if ((ret =
           _gnutls_auth_cipher_decrypt (&params->read.cipher_state,
             ciphertext->data, length_to_decrypt)) < 0)
        return gnutls_assert_val(ret);

      break;
    case CIPHER_BLOCK:
      if (ciphertext->size < MAX(blocksize, tag_size) || (ciphertext->size % blocksize != 0))
        return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);

      /* ignore the IV in TLS 1.1+
       */
      if (explicit_iv)
        {
          _gnutls_auth_cipher_setiv(&params->read.cipher_state,
            ciphertext->data, blocksize);

          ciphertext->size -= blocksize;
          ciphertext->data += blocksize;

          if (ciphertext->size == 0)
            {
              gnutls_assert ();
              return GNUTLS_E_DECRYPTION_FAILED;
            }
        }

      /* we don't use the auth_cipher interface here, since
       * TLS with block ciphers is impossible to be used under such
       * an API. (the length of plaintext is required to calculate
       * auth_data, but it is not available before decryption).
       */
      if ((ret =
           _gnutls_cipher_decrypt (&params->read.cipher_state.cipher,
             ciphertext->data, ciphertext->size)) < 0)
        return gnutls_assert_val(ret);

      pad = ciphertext->data[ciphertext->size - 1] + 1;   /* pad */

      if ((int) pad > (int) ciphertext->size - tag_size)
        {
          gnutls_assert ();
          _gnutls_record_log
            ("REC[%p]: Short record length %d > %d - %d (under attack?)\n",
             session, pad, ciphertext->size, tag_size);
          /* We do not fail here. We check below for the
           * the pad_failed. If zero means success.
           */
          pad_failed = GNUTLS_E_DECRYPTION_FAILED;
          pad %= blocksize;
        }

      length = ciphertext->size - tag_size - pad;

      /* Check the pading bytes (TLS 1.x)
       */
      if (ver != GNUTLS_SSL3)
        for (i = 2; i < pad; i++)
          {
            if (ciphertext->data[ciphertext->size - i] !=
                ciphertext->data[ciphertext->size - 1])
              pad_failed = GNUTLS_E_DECRYPTION_FAILED;
          }

      if (length < 0)
        length = 0;

      /* Pass the type, version, length and compressed through
       * MAC.
       */
      preamble_size =
        make_preamble (UINT64DATA(*sequence), type,
                       length, ver, preamble);
      _gnutls_auth_cipher_add_auth (&params->read.cipher_state, preamble, preamble_size);
      _gnutls_auth_cipher_add_auth (&params->read.cipher_state, ciphertext->data, length);

      break;
    default:
      return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
    }

  ret = _gnutls_auth_cipher_tag(&params->read.cipher_state, tag, tag_size);
  if (ret < 0)
    return gnutls_assert_val(ret);

  /* This one was introduced to avoid a timing attack against the TLS
   * 1.0 protocol.
   */
  /* HMAC was not the same. 
   */
  if (memcmp (tag, &ciphertext->data[length], tag_size) != 0 || pad_failed != 0)
    return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);

  /* copy the decrypted stuff to compress_data.
   */
  if (compress_size < length)
    return gnutls_assert_val(GNUTLS_E_DECOMPRESSION_FAILED);

  if (compress_data != ciphertext->data)
    memcpy (compress_data, ciphertext->data, length);

  return length;
}
Exemplo n.º 8
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,
                               opaque * cipher_data, int cipher_size,
                               gnutls_datum_t *compressed,
                               content_type_t type, 
                               record_parameters_st * params)
{
  uint8_t * tag_ptr = NULL;
  uint8_t pad;
  int length, length_to_encrypt, ret;
  opaque 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_algorithm);
  unsigned block_algo =
    _gnutls_cipher_is_block (params->cipher_algorithm);
  opaque *data_ptr;
  int ver = gnutls_protocol_get_version (session);
  int explicit_iv = _gnutls_version_has_explicit_iv (session->security_parameters.version);
  int auth_cipher = _gnutls_auth_cipher_is_aead(&params->write.cipher_state);
  int random_pad;
  
  /* We don't use long padding if requested or if we are in DTLS.
   */
  if (session->internals.priorities.no_padding == 0 && (!IS_DTLS(session)))
    random_pad = 1;
  else
    random_pad = 0;
  
  _gnutls_hard_log("ENC[%p]: cipher: %s, MAC: %s, Epoch: %u\n",
    session, gnutls_cipher_get_name(params->cipher_algorithm), gnutls_mac_get_name(params->mac_algorithm),
    (unsigned int)params->epoch);

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

  /* Calculate the encrypted length (padding etc.)
   */
  length_to_encrypt = length =
    calc_enc_length (session, compressed->size, tag_size, &pad,
                     random_pad, block_algo, auth_cipher, blocksize);
  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)
    {

      if (block_algo == CIPHER_BLOCK)
        {
          /* copy the random IV.
           */
          ret = _gnutls_rnd (GNUTLS_RND_NONCE, data_ptr, blocksize);
          if (ret < 0)
            return gnutls_assert_val(ret);

          _gnutls_auth_cipher_setiv(&params->write.cipher_state, data_ptr, blocksize);

          data_ptr += blocksize;
          cipher_data += blocksize;
          length_to_encrypt -= blocksize;
        }
      else if (auth_cipher)
        {
          uint8_t nonce[blocksize];

          /* 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;
          /* In AEAD ciphers we don't encrypt the tag 
           */
          length_to_encrypt -= AEAD_EXPLICIT_DATA_SIZE + tag_size;
        }
    }
  else
    {
      /* AEAD ciphers have an explicit IV. Shouldn't be used otherwise.
       */
      if (auth_cipher) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
    }

  memcpy (data_ptr, compressed->data, compressed->size);
  data_ptr += compressed->size;

  if (tag_size > 0)
    {
      tag_ptr = data_ptr;
      data_ptr += tag_size;
    }
  if (block_algo == CIPHER_BLOCK && pad > 0)
    {
      memset (data_ptr, pad - 1, pad);
    }

  /* add the authenticate data */
  _gnutls_auth_cipher_add_auth(&params->write.cipher_state, preamble, preamble_size);

  /* Actual encryption (inplace).
   */
  ret =
    _gnutls_auth_cipher_encrypt_tag (&params->write.cipher_state,
      cipher_data, length_to_encrypt, tag_ptr, tag_size, compressed->size);
  if (ret < 0)
    return gnutls_assert_val(ret);

  return length;
}
Exemplo n.º 9
0
/* Deciphers the ciphertext packet, and puts the result to compress_data, of compress_size.
 * Returns the actual compressed packet size.
 */
static int
ciphertext_to_compressed(gnutls_session_t session,
			 gnutls_datum_t * ciphertext,
			 gnutls_datum_t * compressed,
			 uint8_t type, record_parameters_st * params,
			 uint64 * sequence)
{
	uint8_t tag[MAX_HASH_SIZE];
	const uint8_t *tag_ptr;
	unsigned int pad = 0, i;
	int length, length_to_decrypt;
	uint16_t blocksize;
	int ret;
	unsigned int tmp_pad_failed = 0;
	unsigned int pad_failed = 0;
	uint8_t preamble[MAX_PREAMBLE_SIZE];
	unsigned int preamble_size;
	const version_entry_st *ver = get_version(session);
	unsigned int tag_size =
	    _gnutls_auth_cipher_tag_len(&params->read.cipher_state);
	unsigned int explicit_iv = _gnutls_version_has_explicit_iv(ver);
	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);
	blocksize = _gnutls_cipher_get_block_size(params->cipher);

	/* actual decryption (inplace)
	 */
	switch (_gnutls_cipher_is_block(params->cipher)) {
	case CIPHER_STREAM:
		/* The way AEAD ciphers are defined in RFC5246, it allows
		 * only stream ciphers.
		 */
		if (explicit_iv
		    && _gnutls_auth_cipher_is_aead(&params->read.
						   cipher_state)) {
			uint8_t nonce[blocksize];
			/* Values in AEAD are pretty fixed in TLS 1.2 for 128-bit block
			 */
			if (unlikely
			    (params->read.IV.data == NULL
			     || params->read.IV.size != 4))
				return
				    gnutls_assert_val
				    (GNUTLS_E_INTERNAL_ERROR);

			if (unlikely
			    (ciphertext->size <
			     tag_size + AEAD_EXPLICIT_DATA_SIZE))
				return
				    gnutls_assert_val
				    (GNUTLS_E_UNEXPECTED_PACKET_LENGTH);

			memcpy(nonce, params->read.IV.data,
			       AEAD_IMPLICIT_DATA_SIZE);
			memcpy(&nonce[AEAD_IMPLICIT_DATA_SIZE],
			       ciphertext->data, AEAD_EXPLICIT_DATA_SIZE);

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

			ciphertext->data += AEAD_EXPLICIT_DATA_SIZE;
			ciphertext->size -= AEAD_EXPLICIT_DATA_SIZE;

			length = length_to_decrypt =
			    ciphertext->size - tag_size;
			tag_ptr = ciphertext->data + length_to_decrypt;
		} else if (iv_size > 0) {	/* a stream cipher with explicit IV */
			_gnutls_auth_cipher_setiv(&params->read.
						  cipher_state,
						  UINT64DATA(*sequence),
						  8);
			length_to_decrypt = ciphertext->size;
			length = ciphertext->size - tag_size;
			tag_ptr = compressed->data + length;
		} else {
			if (unlikely(ciphertext->size < tag_size))
				return
				    gnutls_assert_val
				    (GNUTLS_E_UNEXPECTED_PACKET_LENGTH);

			length_to_decrypt = ciphertext->size;
			length = ciphertext->size - tag_size;
			tag_ptr = compressed->data + length;
		}


		/* Pass the type, version, length and compressed through
		 * MAC.
		 */
		preamble_size =
		    make_preamble(UINT64DATA(*sequence), type,
				  length, ver, preamble);

		_gnutls_auth_cipher_set_mac_nonce(&params->read.
						  cipher_state,
						  UINT64DATA(*sequence),
						  8);
		ret =
		    _gnutls_auth_cipher_add_auth(&params->read.
						 cipher_state, preamble,
						 preamble_size);
		if (unlikely(ret < 0))
			return gnutls_assert_val(ret);

		if (unlikely
		    ((unsigned) length_to_decrypt > compressed->size)) {
			_gnutls_audit_log(session,
					  "Received %u bytes, while expecting less than %u\n",
					  (unsigned int) length_to_decrypt,
					  (unsigned int) compressed->size);
			return
			    gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
		}

		ret =
		    _gnutls_auth_cipher_decrypt2(&params->read.
						 cipher_state,
						 ciphertext->data,
						 length_to_decrypt,
						 compressed->data,
						 compressed->size);

		if (unlikely(ret < 0))
			return gnutls_assert_val(ret);

		break;
	case CIPHER_BLOCK:
		if (unlikely
		    (ciphertext->size < blocksize
		     || (ciphertext->size % blocksize != 0)))
			return
			    gnutls_assert_val
			    (GNUTLS_E_UNEXPECTED_PACKET_LENGTH);

		/* ignore the IV in TLS 1.1+
		 */
		if (explicit_iv) {
			_gnutls_auth_cipher_setiv(&params->read.
						  cipher_state,
						  ciphertext->data,
						  blocksize);

			ciphertext->size -= blocksize;
			ciphertext->data += blocksize;
		}

		if (unlikely(ciphertext->size < tag_size + 1))
			return
			    gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);

		/* we don't use the auth_cipher interface here, since
		 * TLS with block ciphers is impossible to be used under such
		 * an API. (the length of plaintext is required to calculate
		 * auth_data, but it is not available before decryption).
		 */
		if (unlikely(ciphertext->size > compressed->size))
			return
			    gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);

		ret =
		    _gnutls_cipher_decrypt2(&params->read.cipher_state.
					    cipher, ciphertext->data,
					    ciphertext->size,
					    compressed->data,
					    compressed->size);
		if (unlikely(ret < 0))
			return gnutls_assert_val(ret);

		pad = compressed->data[ciphertext->size - 1];	/* pad */

		/* Check the pading bytes (TLS 1.x). 
		 * Note that we access all 256 bytes of ciphertext for padding check
		 * because there is a timing channel in that memory access (in certain CPUs).
		 */
		if (ver->id != GNUTLS_SSL3)
			for (i = 2; i <= MIN(256, ciphertext->size); i++) {
				tmp_pad_failed |=
				    (compressed->
				     data[ciphertext->size - i] != pad);
				pad_failed |=
				    ((i <= (1 + pad)) & (tmp_pad_failed));
			}

		if (unlikely
		    (pad_failed != 0
		     || (1 + pad > ((int) ciphertext->size - tag_size)))) {
			/* We do not fail here. We check below for the
			 * the pad_failed. If zero means success.
			 */
			pad_failed = 1;
			pad = 0;
		}

		length = ciphertext->size - tag_size - pad - 1;
		tag_ptr = &compressed->data[length];

		/* Pass the type, version, length and compressed through
		 * MAC.
		 */
		preamble_size =
		    make_preamble(UINT64DATA(*sequence), type,
				  length, ver, preamble);

		_gnutls_auth_cipher_set_mac_nonce(&params->read.
						  cipher_state,
						  UINT64DATA(*sequence),
						  8);
		ret =
		    _gnutls_auth_cipher_add_auth(&params->read.
						 cipher_state, preamble,
						 preamble_size);
		if (unlikely(ret < 0))
			return gnutls_assert_val(ret);

		ret =
		    _gnutls_auth_cipher_add_auth(&params->read.
						 cipher_state,
						 compressed->data, length);
		if (unlikely(ret < 0))
			return gnutls_assert_val(ret);

		break;
	default:
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
	}

	ret =
	    _gnutls_auth_cipher_tag(&params->read.cipher_state, tag,
				    tag_size);
	if (unlikely(ret < 0))
		return gnutls_assert_val(ret);

	/* Here there could be a timing leakage in CBC ciphersuites that
	 * could be exploited if the cost of a successful memcmp is high. 
	 * A constant time memcmp would help there, but it is not easy to maintain
	 * against compiler optimizations. Currently we rely on the fact that
	 * a memcmp comparison is negligible over the crypto operations.
	 */
	if (unlikely
	    (memcmp(tag, tag_ptr, tag_size) != 0 || pad_failed != 0)) {
		/* HMAC was not the same. */
		dummy_wait(params, compressed, pad_failed, pad,
			   length + preamble_size);

		return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
	}

	return length;
}
Exemplo n.º 10
0
static int
compressed_to_ciphertext_new(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)
{
	uint16_t pad = min_pad;
	int length, length_to_encrypt, 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, final_cipher_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);

	/* 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);

	/* cipher_data points to the start of data to be encrypted */
	data_ptr = cipher_data;

	length_to_encrypt = length = 0;

	if (explicit_iv) {
		if (block_algo == CIPHER_BLOCK) {
			/* copy the random IV.
			 */
			DECR_LEN(cipher_size, blocksize);

			memcpy(data_ptr, nonce, blocksize);
			_gnutls_auth_cipher_setiv(&params->write.
						  cipher_state, data_ptr,
						  blocksize);

			data_ptr += blocksize;
			cipher_data += blocksize;
			length += 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 */
			DECR_LEN(cipher_size, AEAD_EXPLICIT_DATA_SIZE);
			memcpy(data_ptr, &nonce[AEAD_IMPLICIT_DATA_SIZE],
			       AEAD_EXPLICIT_DATA_SIZE);

			data_ptr += AEAD_EXPLICIT_DATA_SIZE;
			cipher_data += AEAD_EXPLICIT_DATA_SIZE;
			length += 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);
	}

	DECR_LEN(cipher_size, 2);

	if (block_algo == CIPHER_BLOCK) {	/* make pad a multiple of blocksize */
		unsigned t =
		    (2 + pad + compressed->size + tag_size) % blocksize;
		if (t > 0) {
			pad += blocksize - t;
		}
	}

	_gnutls_write_uint16(pad, data_ptr);
	data_ptr += 2;
	length_to_encrypt += 2;
	length += 2;
	final_cipher_size = cipher_size;

	if (pad > 0) {
		unsigned t;

		t = cipher_size - compressed->size;
		if (pad > t) {
			if (block_algo == CIPHER_BLOCK) {
				if (pad <= blocksize)
					return
					    gnutls_assert_val
					    (GNUTLS_E_INVALID_REQUEST);

				pad -= blocksize * ((pad - t) / blocksize);
			} else
				pad = t;
		}

		DECR_LEN(cipher_size, pad);

		memset(data_ptr, 0, pad);
		data_ptr += pad;
		length_to_encrypt += pad;
		length += pad;
	}

	DECR_LEN(cipher_size, compressed->size);

	memcpy(data_ptr, compressed->data, compressed->size);
	data_ptr += compressed->size;
	length_to_encrypt += compressed->size;
	length += compressed->size;

	if (tag_size > 0) {
		DECR_LEN(cipher_size, tag_size);

		data_ptr += tag_size;

		/* In AEAD ciphers we don't encrypt the tag 
		 */
		length += tag_size;
	}

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

	_gnutls_auth_cipher_set_mac_nonce(&params->write.cipher_state,
					  UINT64DATA(params->write.
						     sequence_number), 8);
	/* 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);

	/* Actual encryption (inplace).
	 */
	ret =
	    _gnutls_auth_cipher_encrypt2_tag(&params->write.cipher_state,
					     cipher_data,
					     length_to_encrypt,
					     cipher_data,
					     final_cipher_size, 0);
	if (ret < 0)
		return gnutls_assert_val(ret);

	return length;
}
Exemplo n.º 11
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;
}