文件处理与对称的客户端-服务器通信有关

时间:2022-03-12 05:52:37

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:

我已经编写了两个程序,它们使用对称加密实现服务器-客户机通信。它们似乎完成了它们的工作:客户机请求消息,用AES_key加密它,将它发送到服务器,服务器解密并发回它。以下是服务器的代码:

/*
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.

现在,我想用public encyption来交换密钥,所以我想为每一端加载两个文件:另一端的private和public。我已经创造了他们。

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

因此,将以下代码(在main开始时)添加到服务器工作:

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?

很抱歉这么长时间发邮件,但我不知道问题出在哪里。我试过随机冲水,我想这可能是问题所在,但没有用。什么好主意吗?

1 个解决方案

#1


0  

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

第一个版本按照预期运行,所以AES_Encrypt和send必须配合良好。

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)

我怀疑AES_Encrypt()会生成一个以null结尾的字符串作为加密消息,因此这一行是错误的: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.

AES块大小为16字节;enc_message将被填充为16个字节,其中任何一个字节都可能不是“\0”,因此strlen(enc_message)可能会产生太短的发送长度,并且由于数组被访问超过末尾而导致行为未定义。

#1


0  

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

第一个版本按照预期运行,所以AES_Encrypt和send必须配合良好。

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)

我怀疑AES_Encrypt()会生成一个以null结尾的字符串作为加密消息,因此这一行是错误的: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.

AES块大小为16字节;enc_message将被填充为16个字节,其中任何一个字节都可能不是“\0”,因此strlen(enc_message)可能会产生太短的发送长度,并且由于数组被访问超过末尾而导致行为未定义。