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);
}
------------------------------------------------------------------------------------------------
_______________________________________________
gtkmm-list mailing list
[email protected]
http://mail.gnome.org/mailman/listinfo/gtkmm-list

Reply via email to