4

I have written two programs that implement server-client communication with symmetric encryption. They seem to do their job: the client asks for a message,encrypts it with an AES_key, sends it to the server, which decrypts it and sends it back. Here is the code for the server:

/*
C socket server example using sockets and symmetric encryption
compile with gcc server.c -o server -lssl -lcrypto
*/

#include<stdio.h>
#include<string.h>    //strlen
#include<sys/socket.h>
#include<arpa/inet.h> //inet_addr
#include<unistd.h>    //write
#include <openssl/aes.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>

int main(int argc , char *argv[])
{

static const unsigned char key[] = {"hello"};
int socket_desc , client_sock , c , read_size;
struct sockaddr_in server , client;
unsigned char client_message[40];
unsigned char dec_message[16];

//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
    printf("Could not create socket");
}
puts("Socket created");

//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8888 );

//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
    //print the error message
    perror("bind failed. Error");
    return 1;
}
puts("bind done");

//Listen
listen(socket_desc , 3);

//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);

//accept connection from an incoming client
client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c);
if (client_sock < 0)
{
    perror("accept failed");
    return 1;
}
puts("Connection accepted");

//create decryption key
AES_KEY aes_key;
AES_set_decrypt_key((const unsigned char*) key, 128, &aes_key);

//Receive a message from client


while( (read_size = recv(client_sock , client_message , 2000 , 0)) > 0 )
{

    //decry message
    AES_decrypt((const unsigned char*)client_message,dec_message,(const AES_KEY *)&aes_key);
    //Send the message back to client
write(client_sock , dec_message , strlen(dec_message));
}

if(read_size == 0)
{
    puts("Client disconnected");
    fflush(stdout);
}
else if(read_size == -1)
{
    perror("recv failed");
}

return 0;
}

Here is the code for the client:

/*
C ECHO client example using sockets and symmetric encryption
*/
#include<stdio.h> //printf
#include<string.h>    //strlen
#include<sys/socket.h>    //socket
#include<arpa/inet.h> //inet_addr
#include<unistd.h>    //write
#include "openssl/aes.h"
#include <openssl/rsa.h>
#include <openssl/evp.h>

int main(int argc , char *argv[])
{
static const unsigned char key[] = {"hello"};
int sock;
struct sockaddr_in server;




//Create socket
sock = socket(AF_INET , SOCK_STREAM , 0);
if (sock == -1)
{
    printf("Could not create socket");
}
puts("Socket created");

server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons( 8888 );

//Connect to remote server
if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0)
{
    perror("connect failed. Error");
    return 1;
}

puts("Connected\n");
//create key
AES_KEY aes_key;
AES_set_encrypt_key((const unsigned char*)key, 128, &aes_key);

//keep communicating with server
while(1)
{
    unsigned char enc_message[40]={0};
    unsigned char message[16]={0};
    unsigned char server_reply[40]={0};
     fflush(stdin);
fflush(stdout);
    printf("Enter message : ");
    scanf("%s" , message);
    //encrypt message
    AES_encrypt((const unsigned char*)message,enc_message,(const AES_KEY *)&aes_key);
    //Send some data
    if( send(sock , enc_message , strlen(enc_message) , 0) < 0)
    {
        puts("Send failed");
        return 1;
    }

    //Receive a reply from the server
    if( recv(sock , server_reply , 2000 , 0) < 0)
    {
        puts("recv failed");
        break;
    }

    printf("Server reply : %s \n",server_reply);

}

close(sock);
return 0;
}

Now, I'd like to exchange the key with public encyption, so I want to load two files for each end: its private and the public of the other one. I've already created them.

So, adding the following code(at the beginning of main) to server works:

RSA* pRSAPRI = RSA_new();
RSA* pRSAPRI2 = RSA_new();
OpenSSL_add_all_algorithms();
OpenSSL_add_all_ciphers();
ERR_load_crypto_strings();
RSA*    pRSAserver;
RSA*    pRSAclientimport;
FILE*   f1;
FILE*   f2;

//load public key of client
f1 = fopen("client_public.pem", "r");
if (f1==NULL)
{
  printf("could not open file \n");
}
pRSAclientimport = PEM_read_RSAPublicKey(f1, &pRSAPRI, NULL, NULL);
fclose(f1);
 //load private key of server
f2 = fopen("server_private.pem", "r");
if (f2==NULL)
{
  printf("could not open file \n");
}
pRSAserver = PEM_read_RSAPrivateKey(f2, &pRSAPRI2, NULL, "1234");
fclose(f2);

However, adding this piece of code to client messes with the program, so that the answer from the server is not correct:

 RSA* pRSAPRI2 = RSA_new();
RSA* pRSAPRI = RSA_new();
OpenSSL_add_all_algorithms();
OpenSSL_add_all_ciphers();
ERR_load_crypto_strings();
RSA*    pRSAclient;
RSA*    pRSAserverimport;

FILE*   f3;
FILE*   f4;
//load public key of server
f3 = fopen("server_public.pem", "r");
if (f3==NULL)
{
  printf("could not open file \n");
}
pRSAserverimport = PEM_read_RSAPublicKey(f3, &pRSAPRI, NULL, NULL);

fclose(f3);
 //load private key of client
f4 = fopen("client_private.pem", "r");
if (f4==NULL)
{
  printf("could not open file \n");
}
pRSAclient = PEM_read_RSAPrivateKey(f4, &pRSAPRI2, NULL, "1234");

fclose(f4);

Sorry for the long post, but I have no idea where the problem is. I've tried flushing randomly, which I guess may be the problem, but it didn't work. Any ideas?

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
blindeyes
  • 409
  • 3
  • 13
  • What do you mean by "messes with the program"? That's not the kind of information that will help anyone solve your problem. What kind of errors do you see? – Andrew Henle Dec 30 '15 at 01:03
  • 1
    Also, I doubt `AES_Encrypt()` produces a NUL-terminated string as its encrypted message, so this line would be wrong: `if( send(sock , enc_message , strlen(enc_message) , 0) < 0)` – Andrew Henle Dec 30 '15 at 01:23
  • The program runs without errors, the problem is that the answer from the server is not the decrypted message, but random characters. Sorry, for not being clear on that. Also, the first version runs as expected, so `AES_Encrypt` and `send` must be cooperating well. – blindeyes Dec 30 '15 at 01:37

1 Answers1

0

… the first version runs as expected, so AES_Encrypt and send must be cooperating well.

That a program with undefined behavior runs as expected does not imply that all is well.

Andrew Henle is right, saying

I doubt AES_Encrypt() produces a NUL-terminated string as its encrypted message, so this line would be wrong: if( send(sock , enc_message , strlen(enc_message) , 0) < 0)

The AES block size is 16 Bytes; enc_message will have been filled with 16 Bytes, any as well as none of which may be '\0', so strlen(enc_message) could yield a too short length to send as well as render the behavior undefined due to the array being accessed beyond the end.

Armali
  • 18,255
  • 14
  • 57
  • 171