Beispiel #1
0
static
void dcrypt_gnutls_ctx_sym_set_key_iv_random(struct dcrypt_context_symmetric *ctx)
{
	if(ctx->key.data != NULL) p_free(ctx->pool, ctx->key.data);
	if(ctx->iv.data != NULL) p_free(ctx->pool, ctx->iv.data);
	ctx->key.data = p_malloc(ctx->pool, gnutls_cipher_get_key_size(ctx->cipher));
	random_fill(ctx->key.data, gnutls_cipher_get_key_size(ctx->cipher));
	ctx->key.size = gnutls_cipher_get_key_size(ctx->cipher);
	ctx->iv.data = p_malloc(ctx->pool, gnutls_cipher_get_iv_size(ctx->cipher));
	random_fill(ctx->iv.data, gnutls_cipher_get_iv_size(ctx->cipher));
	ctx->iv.size = gnutls_cipher_get_iv_size(ctx->cipher);
}
Beispiel #2
0
static
void dcrypt_gnutls_ctx_sym_set_iv(struct dcrypt_context_symmetric *ctx, const unsigned char *iv, size_t iv_len)
{
	if(ctx->iv.data != NULL) p_free(ctx->pool, ctx->iv.data);
	ctx->iv.size = I_MIN(iv_len,(size_t)gnutls_cipher_get_iv_size(ctx->cipher));
	ctx->iv.data = p_malloc(ctx->pool, ctx->iv.size);
	memcpy(ctx->iv.data, iv, ctx->iv.size);
}
static void cipher_bench(int algo, int size, int aead)
{
	int ret;
	gnutls_cipher_hd_t ctx;
	void *_key, *_iv;
	gnutls_datum_t key, iv;
	int ivsize = gnutls_cipher_get_iv_size(algo);
	int keysize = gnutls_cipher_get_key_size(algo);
	int step = size * 1024;
	struct benchmark_st st;

	_key = malloc(keysize);
	if (_key == NULL)
		return;
	memset(_key, 0xf0, keysize);

	_iv = malloc(ivsize);
	if (_iv == NULL)
		return;
	memset(_iv, 0xf0, ivsize);

	iv.data = _iv;
	if (aead)
		iv.size = 12;
	else
		iv.size = ivsize;

	key.data = _key;
	key.size = keysize;

	printf("%16s ", gnutls_cipher_get_name(algo));
	fflush(stdout);

	start_benchmark(&st);

	ret = gnutls_cipher_init(&ctx, algo, &key, &iv);
	if (ret < 0) {
		fprintf(stderr, "error: %s\n", gnutls_strerror(ret));
		goto leave;
	}

	if (aead)
		gnutls_cipher_add_auth(ctx, data, 1024);

	do {
		gnutls_cipher_encrypt2(ctx, data, step, data, step + 64);
		st.size += step;
	}
	while (benchmark_must_finish == 0);

	gnutls_cipher_deinit(ctx);

	stop_benchmark(&st, NULL, 1);

      leave:
	free(_key);
	free(_iv);
}
Beispiel #4
0
static void cipher_mac_bench(int algo, int mac_algo, int size)
{
	int ret;
	gnutls_cipher_hd_t ctx;
	gnutls_hmac_hd_t mac_ctx;
	void *_key, *_iv;
	gnutls_datum_t key, iv;
	int ivsize = gnutls_cipher_get_iv_size(algo);
	int keysize = gnutls_cipher_get_key_size(algo);
	int step = size * 1024;
	struct benchmark_st st;
	void *output, *input;
	unsigned char c, *i;

	_key = malloc(keysize);
	if (_key == NULL)
		return;
	memset(_key, 0xf0, keysize);

	_iv = malloc(ivsize);
	if (_iv == NULL) {
		free(_key);
		return;
	}
	memset(_iv, 0xf0, ivsize);

	iv.data = _iv;
	iv.size = ivsize;

	key.data = _key;
	key.size = keysize;

	assert(gnutls_rnd(GNUTLS_RND_NONCE, &c, 1) >= 0);

	printf("%19s-%s ", gnutls_cipher_get_name(algo),
	       gnutls_mac_get_name(mac_algo));
	fflush(stdout);

	ALLOCM(input, MAX_MEM);
	ALLOC(output);
	i = input;

	start_benchmark(&st);

	ret = gnutls_hmac_init(&mac_ctx, mac_algo, key.data, key.size);
	if (ret < 0) {
		fprintf(stderr, "error: %s\n", gnutls_strerror(ret));
		goto leave;
	}

	ret = gnutls_cipher_init(&ctx, algo, &key, &iv);
	if (ret < 0) {
		fprintf(stderr, "error: %s\n", gnutls_strerror(ret));
		goto leave;
	}

	do {
		gnutls_hmac(mac_ctx, i, step);
		gnutls_cipher_encrypt2(ctx, i, step, output, step + 64);
		st.size += step;
		INC(input, i, step);
	}
	while (benchmark_must_finish == 0);

	gnutls_cipher_deinit(ctx);
	gnutls_hmac_deinit(mac_ctx, NULL);

	stop_benchmark(&st, NULL, 1);

      leave:
	FREE(input);
	FREE(output);
	free(_key);
	free(_iv);
}
Beispiel #5
0
static void cipher_bench(int algo, int size, int aead)
{
	int ret;
	gnutls_cipher_hd_t ctx;
	void *_key, *_iv;
	gnutls_aead_cipher_hd_t actx;
	gnutls_datum_t key, iv;
	int ivsize = gnutls_cipher_get_iv_size(algo);
	int keysize = gnutls_cipher_get_key_size(algo);
	int step = size * 1024;
	void *input, *output;
	struct benchmark_st st;
	unsigned char c, *i;

	_key = malloc(keysize);
	if (_key == NULL)
		return;
	memset(_key, 0xf0, keysize);

	_iv = malloc(ivsize);
	if (_iv == NULL) {
		free(_key);
		return;
	}
	memset(_iv, 0xf0, ivsize);

	iv.data = _iv;
	iv.size = ivsize;

	key.data = _key;
	key.size = keysize;

	printf("%24s ", gnutls_cipher_get_name(algo));
	fflush(stdout);
	assert(gnutls_rnd(GNUTLS_RND_NONCE, &c, 1) >= 0);

	ALLOCM(input, MAX_MEM);
	ALLOCM(output, step+64);
	i = input;

	start_benchmark(&st);

	if (algo == GNUTLS_CIPHER_NULL) {
		do {
			force_memcpy(output, i, step);
			st.size += step;
			INC(input, i, step);
		}
		while (benchmark_must_finish == 0);
	} else if (aead != 0) {
		unsigned tag_size = gnutls_cipher_get_tag_size(algo);
		size_t out_size;

		ret = gnutls_aead_cipher_init(&actx, algo, &key);
		if (ret < 0) {
			fprintf(stderr, "error: %s\n", gnutls_strerror(ret));
			goto leave;
		}

		do {
			out_size = step+64;
			assert(gnutls_aead_cipher_encrypt(actx, iv.data, iv.size, NULL, 0, tag_size,
				i, step, output, &out_size) >= 0);
			st.size += step;
			INC(input, i, step);
		}
		while (benchmark_must_finish == 0);

		gnutls_aead_cipher_deinit(actx);
	} else {
		ret = gnutls_cipher_init(&ctx, algo, &key, &iv);
		if (ret < 0) {
			fprintf(stderr, "error: %s\n", gnutls_strerror(ret));
			goto leave;
		}

		do {
			gnutls_cipher_encrypt2(ctx, i, step, output, step + 64);
			st.size += step;
			INC(input, i, step);
		}
		while (benchmark_must_finish == 0);

		gnutls_cipher_deinit(ctx);
	}
	stop_benchmark(&st, NULL, 1);

	FREE(input);
	FREE(output);
      leave:
	free(_key);
	free(_iv);
}
Beispiel #6
0
/*
 * Helper function converts a data blob to a gnutls_datum_t.
 * Note that this does not copy the data.
 *      So the returned value should be treated as read only.
 *      And that changes to the length of the underlying DATA_BLOB
 *      will not be reflected in the returned object.
 *
 */
static const gnutls_datum_t convert_from_data_blob(DATA_BLOB blob) {

	const gnutls_datum_t datum = {
		.size = blob.length,
		.data = blob.data,
	};
	return datum;
}

/*
 * @brief Get the gnutls algorithm needed to decrypt the EncryptedSecret
 *
 * @param ldb ldb context, to allow logging.
 * @param es  the encrypted secret
 *
 * @return The gnutls algoritm number, or 0 if there is no match.
 *
 */
static int gnutls_get_algorithm(struct ldb_context *ldb,
				struct EncryptedSecret *es) {

	switch (es->header.algorithm) {
	case ENC_SECRET_AES_128_AEAD:
		return GNUTLS_CIPHER_AES_128_GCM;
	default:
		ldb_asprintf_errstring(ldb,
				       "Unsupported encryption algorithm %d\n",
				       es->header.algorithm);
		return 0;
	}
}

/*
 *
 * @param err  Pointer to an error code, set to:
 *             LDB_SUCESS               If the value was successfully encrypted
 *             LDB_ERR_OPERATIONS_ERROR If there was an error.
 *
 * @param ctx  Talloc memory context the will own the memory allocated
 * @param ldb  ldb context, to allow logging.
 * @param val  The ldb value to encrypt, not altered or freed
 * @param data The context data for this module.
 *
 * @return The encrypted ldb_val, or data_blob_null if there was an error.
 */
static struct ldb_val gnutls_encrypt_aead(int *err,
					  TALLOC_CTX *ctx,
					  struct ldb_context *ldb,
					  const struct ldb_val val,
					  const struct es_data *data)
{
	struct EncryptedSecret *es = NULL;
	struct ldb_val enc = data_blob_null;
	DATA_BLOB pt = data_blob_null;
	gnutls_aead_cipher_hd_t cipher_hnd;
	int rc;

	TALLOC_CTX *frame = talloc_stackframe();

	es = makeEncryptedSecret(ldb, frame);
	if (es == NULL) {
		goto error_exit;
	}

	pt = makePlainText(frame, ldb, val);
	if (pt.length == 0) {
		goto error_exit;
	}

	/*
	 * Set the encryption key and initialize the encryption handle.
	 */
	{
		const size_t key_size = gnutls_cipher_get_key_size(
			data->encryption_algorithm);
		gnutls_datum_t cipher_key;
		DATA_BLOB key_blob = get_key(data);

		if (key_blob.length != key_size) {
			ldb_asprintf_errstring(ldb,
					       "Invalid EncryptedSecrets key "
					       "size, expected %zu bytes and "
					       "it is %zu bytes\n",
					       key_size,
					       key_blob.length);
			goto error_exit;
		}
		cipher_key = convert_from_data_blob(key_blob);

		rc = gnutls_aead_cipher_init(&cipher_hnd,
					     data->encryption_algorithm,
					     &cipher_key);
		if (rc !=0) {
			ldb_asprintf_errstring(ldb,
					       "gnutls_aead_cipher_init failed "
					       "%s - %s\n",
					       gnutls_strerror_name(rc),
					       gnutls_strerror(rc));
			goto error_exit;
		}

	}

	/*
	 * Set the initialisation vector
	 */
	{
		unsigned iv_size = gnutls_cipher_get_iv_size(
			data->encryption_algorithm);
		uint8_t *iv;

		iv = talloc_zero_size(frame, iv_size);
		if (iv == NULL) {
			ldb_set_errstring(ldb,
					  "Out of memory allocating IV\n");
			goto error_exit_handle;
		}

		rc = gnutls_rnd(GNUTLS_RND_NONCE, iv, iv_size);
		if (rc !=0) {
			ldb_asprintf_errstring(ldb,
					       "gnutls_rnd failed %s - %s\n",
					       gnutls_strerror_name(rc),
					       gnutls_strerror(rc));
			goto error_exit_handle;
		}
		es->iv.length = iv_size;
		es->iv.data   = iv;
	}

	/*
	 * Encrypt the value.
	 */
	{
		const unsigned block_size = gnutls_cipher_get_block_size(
			data->encryption_algorithm);
		const unsigned tag_size = gnutls_cipher_get_tag_size(
			data->encryption_algorithm);
		const size_t ed_size = round_to_block_size(
			block_size,
			sizeof(struct PlaintextSecret) + val.length);
		const size_t en_size = ed_size + tag_size;
		uint8_t *ct = talloc_zero_size(frame, en_size);
		size_t el = en_size;

		if (ct == NULL) {
			ldb_set_errstring(ldb,
					  "Out of memory allocation cipher "
					  "text\n");
			goto error_exit_handle;
		}

		rc = gnutls_aead_cipher_encrypt(
			cipher_hnd,
			es->iv.data,
			es->iv.length,
			&es->header,
			sizeof(struct EncryptedSecretHeader),
			tag_size,
			pt.data,
			pt.length,
			ct,
			&el);
		if (rc !=0) {
			ldb_asprintf_errstring(ldb,
					       "gnutls_aead_cipher_encrypt '"
					       "failed %s - %s\n",
					       gnutls_strerror_name(rc),
					       gnutls_strerror(rc));
			*err = LDB_ERR_OPERATIONS_ERROR;
			return data_blob_null;
		}
		es->encrypted.length = el;
		es->encrypted.data   = ct;
		gnutls_aead_cipher_deinit(cipher_hnd);
	}

	rc = ndr_push_struct_blob(&enc,
				  ctx,
				  es,
				  (ndr_push_flags_fn_t)
					ndr_push_EncryptedSecret);
	if (!NDR_ERR_CODE_IS_SUCCESS(rc)) {
		ldb_set_errstring(ldb,
				  "Unable to ndr push EncryptedSecret\n");
		goto error_exit;
	}
	TALLOC_FREE(frame);
	return enc;

error_exit_handle:
	gnutls_aead_cipher_deinit(cipher_hnd);
error_exit:
	*err = LDB_ERR_OPERATIONS_ERROR;
	TALLOC_FREE(frame);
	return data_blob_null;
}

/*
 * @brief Decrypt data encrypted using an aead algorithm.
 *
 * Decrypt the data in ed and insert it into ev. The data was encrypted
 * with one of the gnutls aead compatable algorithms.
 *
 * @param err  Pointer to an error code, set to:
 *             LDB_SUCESS               If the value was successfully decrypted
 *             LDB_ERR_OPERATIONS_ERROR If there was an error.
 *
 * @param ctx  The talloc context that will own the PlaintextSecret
 * @param ldb  ldb context, to allow logging.
 * @param ev   The value to be updated with the decrypted data.
 * @param ed   The data to decrypt.
 * @param data The context data for this module.
 *
 * @return ev is updated with the unencrypted data.
 */
static void gnutls_decrypt_aead(int *err,
				TALLOC_CTX *ctx,
				struct ldb_context *ldb,
				struct EncryptedSecret *es,
				struct PlaintextSecret *ps,
				const struct es_data *data)
{

	gnutls_aead_cipher_hd_t cipher_hnd;
	DATA_BLOB pt = data_blob_null;
	const unsigned tag_size =
		gnutls_cipher_get_tag_size(es->header.algorithm);
	int rc;

	/*
	 * Get the encryption key and initialise the encryption handle
	 */
	{
		gnutls_datum_t cipher_key;
		DATA_BLOB key_blob;
		const int algorithm = gnutls_get_algorithm(ldb, es);
		const size_t key_size = gnutls_cipher_get_key_size(algorithm);
		key_blob   = get_key(data);

		if (algorithm == 0) {
			goto error_exit;
		}

		if (key_blob.length != key_size) {
			ldb_asprintf_errstring(ldb,
					       "Invalid EncryptedSecrets key "
					       "size, expected %zu bytes and "
					       "it is %zu bytes\n",
					       key_size,
					       key_blob.length);
			goto error_exit;
		}
		cipher_key = convert_from_data_blob(key_blob);

		rc = gnutls_aead_cipher_init(
			&cipher_hnd,
			algorithm,
			&cipher_key);
		if (rc != 0) {
			ldb_asprintf_errstring(ldb,
					       "gnutls_aead_cipher_init failed "
					       "%s - %s\n",
					       gnutls_strerror_name(rc),
					       gnutls_strerror(rc));
			goto error_exit;
		}
	}

	/*
	 * Decrypt and validate the encrypted value
	 */

	pt.length = es->encrypted.length;
	pt.data = talloc_zero_size(ctx, es->encrypted.length);

	if (pt.data == NULL) {
		ldb_set_errstring(ldb,
				  "Out of memory allocating plain text\n");
		goto error_exit_handle;
	}

	rc = gnutls_aead_cipher_decrypt(cipher_hnd,
					es->iv.data,
					es->iv.length,
					&es->header,
					sizeof(struct EncryptedSecretHeader),
					tag_size,
					es->encrypted.data,
					es->encrypted.length,
					pt.data,
					&pt.length);
	if (rc != 0) {
		/*
		 * Typically this will indicate that the data has been
		 * corrupted i.e. the tag comparison has failed.
		 * At the moment gnutls does not provide a separate
		 * error code to indicate this
		 */
		ldb_asprintf_errstring(ldb,
				       "gnutls_aead_cipher_decrypt failed "
				       "%s - %s. Data possibly corrupted or "
				       "altered\n",
				       gnutls_strerror_name(rc),
				       gnutls_strerror(rc));
		goto error_exit_handle;
	}
	gnutls_aead_cipher_deinit(cipher_hnd);

	rc = ndr_pull_struct_blob(&pt,
				  ctx,
				  ps,
				  (ndr_pull_flags_fn_t)
					ndr_pull_PlaintextSecret);
	if(!NDR_ERR_CODE_IS_SUCCESS(rc)) {
		ldb_asprintf_errstring(ldb,
				       "Error(%d) unpacking decrypted data, "
				       "data possibly corrupted or altered\n",
				       rc);
		goto error_exit;
	}
	return;

error_exit_handle:
	gnutls_aead_cipher_deinit(cipher_hnd);
error_exit:
	*err = LDB_ERR_OPERATIONS_ERROR;
	return;
}
/**
 * gnutls_x509_privkey_import_openssl:
 * @key: The structure to store the parsed key
 * @data: The DER or PEM encoded key.
 * @password: the password to decrypt the key (if it is encrypted).
 *
 * This function will convert the given PEM encrypted to 
 * the native gnutls_x509_privkey_t format. The
 * output will be stored in @key.  
 *
 * The @password should be in ASCII. If the password is not provided
 * or wrong then %GNUTLS_E_DECRYPTION_FAILED will be returned.
 *
 * If the Certificate is PEM encoded it should have a header of
 * "PRIVATE KEY" and the "DEK-Info" header. 
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 **/
int
gnutls_x509_privkey_import_openssl(gnutls_x509_privkey_t key,
				   const gnutls_datum_t * data,
				   const char *password)
{
	gnutls_cipher_hd_t handle;
	gnutls_cipher_algorithm_t cipher = GNUTLS_CIPHER_UNKNOWN;
	gnutls_datum_t b64_data;
	gnutls_datum_t salt, enc_key;
	unsigned char *key_data;
	size_t key_data_size;
	const char *pem_header = (void *) data->data;
	const char *pem_header_start = (void *) data->data;
	ssize_t pem_header_size;
	int ret;
	unsigned int i, iv_size, l;

	pem_header_size = data->size;

	pem_header =
	    memmem(pem_header, pem_header_size, "PRIVATE KEY---", 14);
	if (pem_header == NULL) {
		gnutls_assert();
		return GNUTLS_E_PARSING_ERROR;
	}

	pem_header_size -= (ptrdiff_t) (pem_header - pem_header_start);

	pem_header = memmem(pem_header, pem_header_size, "DEK-Info: ", 10);
	if (pem_header == NULL) {
		gnutls_assert();
		return GNUTLS_E_PARSING_ERROR;
	}

	pem_header_size =
	    data->size - (ptrdiff_t) (pem_header - pem_header_start) - 10;
	pem_header += 10;

	for (i = 0; i < sizeof(pem_ciphers) / sizeof(pem_ciphers[0]); i++) {
		l = strlen(pem_ciphers[i].name);
		if (!strncmp(pem_header, pem_ciphers[i].name, l) &&
		    pem_header[l] == ',') {
			pem_header += l + 1;
			cipher = pem_ciphers[i].cipher;
			break;
		}
	}

	if (cipher == GNUTLS_CIPHER_UNKNOWN) {
		_gnutls_debug_log
		    ("Unsupported PEM encryption type: %.10s\n",
		     pem_header);
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	iv_size = gnutls_cipher_get_iv_size(cipher);
	salt.size = iv_size;
	salt.data = gnutls_malloc(salt.size);
	if (!salt.data)
		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

	for (i = 0; i < salt.size * 2; i++) {
		unsigned char x;
		const char *c = &pem_header[i];

		if (*c >= '0' && *c <= '9')
			x = (*c) - '0';
		else if (*c >= 'A' && *c <= 'F')
			x = (*c) - 'A' + 10;
		else {
			gnutls_assert();
			/* Invalid salt in encrypted PEM file */
			ret = GNUTLS_E_INVALID_REQUEST;
			goto out_salt;
		}
		if (i & 1)
			salt.data[i / 2] |= x;
		else
			salt.data[i / 2] = x << 4;
	}

	pem_header += salt.size * 2;
	if (*pem_header != '\r' && *pem_header != '\n') {
		gnutls_assert();
		ret = GNUTLS_E_INVALID_REQUEST;
		goto out_salt;
	}
	while (*pem_header == '\n' || *pem_header == '\r')
		pem_header++;

	ret =
	    _gnutls_base64_decode((const void *) pem_header,
				  pem_header_size, &b64_data);
	if (ret < 0) {
		gnutls_assert();
		goto out_salt;
	}

	if (b64_data.size < 16) {
		/* Just to be sure our parsing is OK */
		gnutls_assert();
		ret = GNUTLS_E_PARSING_ERROR;
		goto out_b64;
	}

	ret = GNUTLS_E_MEMORY_ERROR;
	enc_key.size = gnutls_cipher_get_key_size(cipher);
	enc_key.data = gnutls_malloc(enc_key.size);
	if (!enc_key.data) {
		ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
		goto out_b64;
	}

	key_data_size = b64_data.size;
	key_data = gnutls_malloc(key_data_size);
	if (!key_data) {
		ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
		goto out_enc_key;
	}

	while (1) {
		memcpy(key_data, b64_data.data, key_data_size);

		ret = openssl_hash_password(password, &enc_key, &salt);
		if (ret < 0) {
			gnutls_assert();
			goto out;
		}

		ret = gnutls_cipher_init(&handle, cipher, &enc_key, &salt);
		if (ret < 0) {
			gnutls_assert();
			gnutls_cipher_deinit(handle);
			goto out;
		}

		ret =
		    gnutls_cipher_decrypt(handle, key_data, key_data_size);
		gnutls_cipher_deinit(handle);

		if (ret < 0) {
			gnutls_assert();
			goto out;
		}

		/* We have to strip any padding to accept it.
		   So a bit more ASN.1 parsing for us. */
		if (key_data[0] == 0x30) {
			gnutls_datum_t key_datum;
			unsigned int blocksize =
			    gnutls_cipher_get_block_size(cipher);
			unsigned int keylen = key_data[1];
			unsigned int ofs = 2;

			if (keylen & 0x80) {
				int lenlen = keylen & 0x7f;
				keylen = 0;

				if (lenlen > 3) {
					gnutls_assert();
					goto fail;
				}

				while (lenlen) {
					keylen <<= 8;
					keylen |= key_data[ofs++];
					lenlen--;
				}
			}
			keylen += ofs;

			/* If there appears to be more padding than required, fail */
			if (key_data_size - keylen > blocksize) {
				gnutls_assert();
				goto fail;
			}

			/* If the padding bytes aren't all equal to the amount of padding, fail */
			ofs = keylen;
			while (ofs < key_data_size) {
				if (key_data[ofs] !=
				    key_data_size - keylen) {
					gnutls_assert();
					goto fail;
				}
				ofs++;
			}

			key_datum.data = key_data;
			key_datum.size = keylen;
			ret =
			    gnutls_x509_privkey_import(key, &key_datum,
						       GNUTLS_X509_FMT_DER);
			if (ret == 0)
				goto out;
		}
	      fail:
		ret = GNUTLS_E_DECRYPTION_FAILED;
		goto out;
	}
      out:
	zeroize_key(key_data, key_data_size);
	gnutls_free(key_data);
      out_enc_key:
	_gnutls_free_key_datum(&enc_key);
      out_b64:
	gnutls_free(b64_data.data);
      out_salt:
	gnutls_free(salt.data);
	return ret;
}
Beispiel #8
0
static
int dcrypt_gnutls_ctx_sym_get_iv_length(struct dcrypt_context_symmetric *ctx)
{
	return gnutls_cipher_get_iv_size(ctx->cipher);
}
static int cipher_test(const char *ocipher, gnutls_cipher_algorithm_t gcipher, unsigned tag_size)
{
	int ret;
	gnutls_aead_cipher_hd_t hd;
	gnutls_datum_t dkey, dnonce;
	unsigned char key[32];
	unsigned char nonce[32];
	size_t enc_data_size, dec_data_size;
	int dec_data_size2;
	EVP_CIPHER_CTX *ctx;
	const EVP_CIPHER *evp_cipher;
	unsigned char tag[64];

	assert(gnutls_rnd(GNUTLS_RND_NONCE, orig_plain_data, sizeof(orig_plain_data)) >= 0);
	assert(gnutls_rnd(GNUTLS_RND_NONCE, buffer_auth, sizeof(buffer_auth)) >= 0);
	assert(gnutls_rnd(GNUTLS_RND_NONCE, key, sizeof(key)) >= 0);
	assert(gnutls_rnd(GNUTLS_RND_NONCE, nonce, sizeof(nonce)) >= 0);

	dkey.data = (void*)key;
	dkey.size = gnutls_cipher_get_key_size(gcipher);
	assert(gnutls_aead_cipher_init(&hd, gcipher, &dkey) >= 0);

	dnonce.data = (void*)nonce;
	dnonce.size = gnutls_cipher_get_iv_size(gcipher);

	enc_data_size = sizeof(enc_data);
	assert(gnutls_aead_cipher_encrypt(hd, dnonce.data, dnonce.size, 
		buffer_auth, sizeof(buffer_auth), tag_size, orig_plain_data, sizeof(orig_plain_data),
		enc_data, &enc_data_size) >= 0);

	if (debug)
		success("encrypted %d bytes, to %d\n", (int)sizeof(orig_plain_data), (int)enc_data_size);

	dec_data_size = sizeof(dec_data);
	ret = gnutls_aead_cipher_decrypt(hd, dnonce.data, dnonce.size, 
		buffer_auth, sizeof(buffer_auth), tag_size, enc_data, enc_data_size,
		dec_data, &dec_data_size);
	if (ret < 0) {
		fail("error in gnutls_aead_cipher_decrypt for %s: %s\n", ocipher, gnutls_strerror(ret));
	}

	if (dec_data_size != sizeof(orig_plain_data) || memcmp(dec_data, orig_plain_data, sizeof(orig_plain_data)) != 0) {
		fail("gnutls encrypt-decrypt failed (got: %d, expected: %d)\n", (int)dec_data_size, (int)sizeof(orig_plain_data));
	}

	gnutls_aead_cipher_deinit(hd);

	/* decrypt with openssl */
	evp_cipher = EVP_get_cipherbyname(ocipher);
	if (!evp_cipher)
		fail("EVP_get_cipherbyname failed for %s\n", ocipher);

	ctx = EVP_CIPHER_CTX_new();
	assert(EVP_CipherInit_ex(ctx, evp_cipher, NULL, key, nonce, 0) > 0);

	EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tag_size, enc_data+enc_data_size-tag_size);

	dec_data_size2 = sizeof(dec_data);
	assert(EVP_CipherUpdate(ctx, NULL, &dec_data_size2, buffer_auth, sizeof(buffer_auth)) > 0);
	dec_data_size2 = sizeof(dec_data);
	assert(EVP_CipherUpdate(ctx, dec_data, &dec_data_size2, enc_data, enc_data_size-tag_size) > 0);

	dec_data_size = dec_data_size2;
	dec_data_size2 = tag_size;
	assert(EVP_CipherFinal_ex(ctx, tag, &dec_data_size2) > 0);

	if (dec_data_size != sizeof(orig_plain_data) || memcmp(dec_data, orig_plain_data, sizeof(orig_plain_data)) != 0) {
		fail("openssl decrypt failed for %s\n", ocipher);
	}

	EVP_CIPHER_CTX_free(ctx);

	return 0;
}