Re: Avoiding string break...



Hi, again,

I post the code of a sample client & server application. Don't worry
about protocol, in a normal escenario the key will not be sent in
clear, non-encrypted manner. Just notice that, in some cases, the
message sent by the server doesn't arrive completely to the client,
which finally breaks throwing an std::bad_alloc exception instance.

Could be managed ? some help ?

Glus

-----

Compile:

$ g++ lt_client.cc rijndael.cc -o lt_client `pkg-config --cflags
--libs glibmm-2.4` `pkg-config --cflags --libs
giomm-2.4` -lssl

$ g++ lt_server.cc rijndael.cc -o lt_server `pkg-config --cflags
--libs glibmm-2.4` `pkg-config --cflags --libs giomm-2.4` -lssl

----- lt_client.cc
------------------------------------------------------------------------------
#include <glibmm.h>
#include <giomm.h>
#include <string>
#include <iostream>
#include <cstring>

#include "./rijndael.h"

const std::string Host = "localhost";
const guint16 Port = 23410;

Glib::RefPtr<Gio::Socket> socket;
Glib::RefPtr<Gio::SocketAddress> address;
Glib::RefPtr<Gio::SocketAddressEnumerator> enumerator;
Glib::RefPtr<Gio::SocketConnectable> connectable;

void connect_to_server ()
{
	try
	{
		socket = Gio::Socket::create (
			(Gio::SocketFamily)G_SOCKET_FAMILY_IPV6,
			Gio::SOCKET_TYPE_STREAM,
			Gio::SOCKET_PROTOCOL_DEFAULT
			);
	}
	catch (const Gio::Error & error)
	{
		std::cerr
			<< Glib::ustring::compose ("%1", error.what())
			<< std::endl;
		exit (1);
	}

	socket->set_blocking (true);

	try
	{
		connectable = Gio::NetworkAddress::create (Host, Port);
	}
	catch (Gio::Error & error)
	{
		std::cerr
			<< Glib::ustring::compose ("%1", error.what())
			<< std::endl;
		exit (1);
	}

	enumerator = connectable->enumerate();

	try
	{
		address = enumerator->next();
		if (!address)
		{
			std::cerr
				<< "No more addresses to try"
				<< std::endl;
			exit (1);
		}
	}
	catch (const Gio::Error & error)
	{
		std::cerr
			<< Glib::ustring::compose ("%1", error.what())
			<< std::endl;
		exit (1);
	}

	try
	{
		socket->connect (address);
	}
	catch (Gio::Error & error)
	{
		std::cerr
			<< Glib::ustring::compose ("Connection failed: %1"
				", trying next", error.what())
			<< std::endl;
		exit (1);
	}
}

std::string generate_key(int n_pos=32)
{
	Glib::Rand rand_gen;

	std::string mykey="";

	for (gint an=0; an < n_pos; an++)
	{
		gint bn = rand_gen.get_int_range(0,9);
		gchar * cn = g_strdup_printf ("%d", bn);
		mykey+=cn;
	}

	return mykey;
}

bool send_my_message (std::string & s_mymess)
{
	const gchar * s_message = g_strdup_printf("%s\0", s_mymess.data());
	gssize to_send = s_mymess.size();

	gssize size = 0;

	while (to_send > 0)
	{
		try
		{
			size = socket->send (s_message, to_send);
		}
		catch (Gio::Error & error)
		{
			if (error.code() == Gio::Error::WOULD_BLOCK)
			{
				continue;
			}
			else
			{
				std::cerr
					<< Glib::ustring::compose ("Error sending to socket: %1",
						error.what())
					<< Glib::ustring::compose ("(%1)", size)
					<< std::endl;
				return false;
			}
		}

		if (size == 0)
		{
			std::cerr
				<< "Unexpected short write"
					<< std::endl;
				return false;
		}

		to_send -= size;
	}

	return true;

}

std::string recv_my_message()
{
	gchar * r_message = g_new0(gchar,999999);
    gint messlen=0;

    try
    {
		messlen = socket->receive (r_message, 999999);
	}
	catch (const Gio::Error & error)
	{
		std::cerr
			<< Glib::ustring::compose ("Error receiving from socket: %1",
				error.what())
			<< std::endl;
		socket->close();
		return "";
	}

	if (messlen==0)
    {
        socket->close();
        return "";
    }
    else
    {
        r_message[messlen]='\0';
        std::string r_string (r_message);

        return r_string;
	}
}

int main (int argc, char * argv[])
{
	Glib::init();
	Gio::init();

	while (true)
	{
		connect_to_server();

		std::string key = generate_key();

		std::string s_message = "<_hello_:"+key;

		send_my_message (s_message);

		std::string r_message = recv_my_message ();

		std::string message="";

		if (r_message.size() > 3)
		{
			std::string enc_sub = r_message.substr(4);
			AesDecrypt (NormKey(key, 32, ' '), enc_sub, message);
		}
		else
			message = r_message;

		std::cout
			<< message
			<< std::endl;

		sleep (1);

	}
	return 0;
}
-------------------------------------------------------------------------------------------------

----- lt_server.cc
------------------------------------------------------------------------------
#include <glibmm.h>
#include <giomm.h>
#include <string>
#include <iostream>
#include <cstring>

#include "./rijndael.h"

const guint16 Port = 23410;

Glib::RefPtr<Gio::Socket> socket, client_socket;
Glib::RefPtr<Gio::SocketAddress> src_address, address;

bool service_up ()
{
	try
	{
		socket = Gio::Socket::create (
			(Gio::SocketFamily) G_SOCKET_FAMILY_IPV6,
			Gio::SOCKET_TYPE_STREAM,
			Gio::SOCKET_PROTOCOL_DEFAULT
			);
	}
	catch (Gio::Error & error)
	{
		std::cerr
			<< error.what()
			<< std::endl;
		return false;
	}

	socket->set_blocking (true);
	socket->set_listen_backlog (500);

	src_address = Gio::InetSocketAddress::create (
		Gio::InetAddress::create_any
			((Gio::SocketFamily) G_SOCKET_FAMILY_IPV6),
		Port);

	try
	{
		socket->bind (src_address, true);
	}
	catch (const Gio::Error & error)
	{
		std::cerr
			<< Glib::ustring::compose ("Can't bind socket: %1", error.what())
			<< std::endl;
		return false;
	}

	try
	{
		socket->listen();
	}
	catch (const Gio::Error & error)
	{
		std::cerr
			<< Glib::ustring::compose ("Can't listen on socket: %1",
				error.what())
			<< std::endl;
		return false;
	}

    return true;
}

std::string recv_my_message()
{
	gchar * r_message = g_new0(gchar,50);
    gint messlen=0;

    try
    {
		messlen = client_socket->receive (r_message, 50);
	}
	catch (const Gio::Error & error)
	{
		std::cerr
			<< Glib::ustring::compose ("Error receiving from socket: %1",
				error.what())
			<< std::endl;
		client_socket->close();
		return "";
	}

	if (messlen==0)
    {
        client_socket->close();
        return "";
    }
    else
    {
        r_message[messlen]='\0';
        std::string r_string (r_message);

        return r_string;
	}
}

std::string get_my_reply()
{
	Glib::TimeVal h_time;
	h_time.assign_current_time();
	return h_time.as_iso8601();
}

bool send_my_message (std::string & s_mymess)
{
	const gchar * s_message = g_strdup_printf("%s\0", s_mymess.data());
	gssize to_send = s_mymess.size();

	gssize size = 0;

	while (to_send > 0)
	{
		try
		{
			size = client_socket->send (s_message, to_send);
		}
		catch (Gio::Error & error)
		{
			if (error.code() == Gio::Error::WOULD_BLOCK)
			{
				continue;
			}
			else
			{
				std::cerr
					<< Glib::ustring::compose ("Error sending to socket: %1",
						error.what())
					<< Glib::ustring::compose ("(%1)", size)
					<< std::endl;
				return false;
			}
		}

		if (size == 0)
		{
			std::cerr
				<< "Unexpected short write"
					<< std::endl;
				return false;
		}

		to_send -= size;
	}

	return true;

}

int main (int argc, char * argv[])
{
	Glib::init();
	Gio::init();

	service_up ();

	std::cout
		<< "Ready..."
		<< std::endl;

	while (true)
	{

		try
		{
			client_socket = socket->accept();
		}
		catch (const Gio::Error & error)
		{
			std::cerr
				<< Glib::ustring::compose ("Error accepting socket: %1",
					error.what())
				<< std::endl;
			exit(1);
		}

		std::string r_message = recv_my_message();

			std::cout << r_message << std::endl;

		std::string s_message = "";

		if (r_message.size() > 9)
		{
			std::string reply = get_my_reply();
			std::string key = r_message.substr(9);
			std::string reply_e="";
			AesEncrypt(NormKey(key, 32, ' '), reply, reply_e);

			s_message = ">00:"+reply_e;
		}
		else
			s_message = ">01";

		send_my_message (s_message);
	}

	return 0;
}
-------------------------------------------------------------------------------------------------

----- rijndael.h
--------------------------------------------------------------------------------
#include <iostream>
#include <fstream>
#include <cstdio>
#include <string>
#include <cmath>
#include <cstdlib>
#include <openssl/aes.h>
#include <openssl/evp.h>
#include <openssl/rand.h>

using namespace std;

int AesEncrypt(const std::string &sAesKey, const std::string
&ToEncrypt, std::string &Encrypted);

int AesDecrypt(const std::string &sAesKey, const std::string
&ToDecrypt, std::string &Decrypted);

std::string NormKey(std::string Key, const int NoBits, char FillSeq);
-------------------------------------------------------------------------------------------------

----- rijndael.cc
-------------------------------------------------------------------------------
#include "./rijndael.h"

int AesEncrypt(const std::string &sAesKey,
					const std::string &ToEncrypt,
					std::string &Encrypted) {
	const int AesBlockSize=16;
	unsigned char cInitVector[AesBlockSize];
	EVP_CIPHER_CTX oEncCtx;
	const EVP_CIPHER *oChiper=0;
	int retval=0;
	unsigned char *cOutBuffer=0;

	// Set aes key:
	if (sAesKey.length()==16) {
		oChiper = EVP_aes_128_cbc();
	} else if (sAesKey.length()==32) {
		oChiper = EVP_aes_256_cbc();
	} else {
		return -1; // Wrong key size.
	}

	// Create init vector and add him infront of encrypted output data:
	RAND_pseudo_bytes(cInitVector, AesBlockSize);
	Encrypted.assign((char *)cInitVector, ((char *)cInitVector)+AesBlockSize);

	// Create encryption context.
	EVP_CIPHER_CTX_init(&oEncCtx);
	EVP_EncryptInit_ex(&oEncCtx, oChiper, 0, (unsigned char
*)sAesKey.c_str(), cInitVector);

	// Encrypt most of the data:
	int OutBufferByteLen = ToEncrypt.length()+2*AesBlockSize;
	cOutBuffer = new unsigned char[OutBufferByteLen];
	retval = EVP_EncryptUpdate(
		&oEncCtx,
		cOutBuffer,
		&OutBufferByteLen,
		(unsigned char *)ToEncrypt.c_str(),
		ToEncrypt.length());

	// Doese encryption fail?
	if (retval<0) {
		delete[] cOutBuffer;
		return retval; // Encryption error.
	}

	// Add encrypted data to output:
	Encrypted.append((char *)cOutBuffer, ((char *)cOutBuffer)+OutBufferByteLen);
	delete[] cOutBuffer;

	//Add last block+padding:
	OutBufferByteLen = 2*AesBlockSize;
	cOutBuffer = new unsigned char[OutBufferByteLen]; // To be sure add two blocks.
	retval = EVP_EncryptFinal_ex(
		&oEncCtx,
		cOutBuffer,
		&OutBufferByteLen);

	// Doese encryption fail?
	if (retval<0) {
		delete[] cOutBuffer;
		return retval; // Encryption error.
	}

	// Add encrypted data to output:
	Encrypted.append((char *)cOutBuffer, ((char *)cOutBuffer)+OutBufferByteLen);
	delete[] cOutBuffer;

	EVP_CIPHER_CTX_cleanup(&oEncCtx);
	return 0; // Success
}

int AesDecrypt(const std::string &sAesKey,
					const std::string &ToDecrypt,
					std::string &Decrypted) {
	const int AesBlockSize=16;
	unsigned char cInitVector[AesBlockSize];
	EVP_CIPHER_CTX oEncCtx;
	const EVP_CIPHER *oChiper=0;
	int retval=0;
	unsigned char *cOutBuffer=0;

	// Set aes key:
	if (sAesKey.length()==16) {
		oChiper = EVP_aes_128_cbc();
	} else if (sAesKey.length()==32) {
		oChiper = EVP_aes_256_cbc();
	} else {
		return -1; // Wrong key size.
	}

	// Get init vector:
	const char *constInitVectorPtr = ToDecrypt.c_str();
	for (int i=0; i<AesBlockSize; i++) {
		cInitVector[i] = *constInitVectorPtr;
		constInitVectorPtr++;
	}

	// Create decryption context.
	EVP_CIPHER_CTX_init(&oEncCtx);
	EVP_DecryptInit_ex(&oEncCtx, oChiper, 0, (unsigned char
*)sAesKey.c_str(), cInitVector);

	// Decrypt most of the data:
	int OutBufferByteLen = ToDecrypt.length() - AesBlockSize; // Subtract
the InitVec.
	cOutBuffer = new unsigned char[OutBufferByteLen];
	retval = EVP_DecryptUpdate(
		&oEncCtx,
		cOutBuffer,
		&OutBufferByteLen,
		((unsigned char *)ToDecrypt.c_str()) + AesBlockSize, // Remove the InitVector.
		OutBufferByteLen);

	// Doese encryption fail?
	if (retval<0) {
		delete[] cOutBuffer;
		return retval; // Encryption error.
	}

	// Add encrypted data to output:
	Decrypted.append((char *)cOutBuffer, ((char *)cOutBuffer)+OutBufferByteLen);
	delete[] cOutBuffer;

	//Add last block+padding:
	OutBufferByteLen = 2*AesBlockSize;
	cOutBuffer = new unsigned char[OutBufferByteLen]; // To be sure add two blocks.
	retval = EVP_DecryptFinal_ex(
		&oEncCtx,
		cOutBuffer,
		&OutBufferByteLen);

	// Doese encryption fail?
	if (retval<0) {
		delete[] cOutBuffer;
		return retval; // Encryption error.
	}

	// Add encrypted data to output:
	Decrypted.append((char *)cOutBuffer, ((char *)cOutBuffer)+OutBufferByteLen);
	delete[] cOutBuffer;

	EVP_CIPHER_CTX_cleanup(&oEncCtx);
	return 0; // Success
}

std::string NormKey(std::string Key, const int NoBits, char FillSeq)
{
	Key.insert (Key.end(),NoBits,FillSeq);
	return Key.substr (0,NoBits);
}
------------------------------------------------------------------------------------------------


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]