我编写了两个使用对称加密实现服务器 - 客户端通信的程序。他们似乎完成了自己的工作:客户端要求输入消息,使用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;
}
以下是客户端的代码:
/*
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;
}
现在,我想用公共加密来交换密钥,所以我想为每个端加载两个文件:私有文件和另一个文件的公共文件。我已经创造了它们。
因此,将以下代码(在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);
但是,将这段代码添加到客户端与程序混淆,以便服务器的答案不正确:
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);
很抱歉很长的帖子,但我不知道问题出在哪里。我已经尝试过随机冲洗,我想这可能是问题,但它没有用。有什么想法吗?
答案 0 :(得分:0)
...第一个版本按预期运行,因此
AES_Encrypt
和send
必须合作良好。
具有未定义行为的程序按预期运行并不意味着所有井。
Andrew Henle是对的,说
我怀疑
AES_Encrypt()
会产生一个以NUL结尾的字符串 它的加密消息,所以这一行是错误的:if( send(sock , enc_message , strlen(enc_message) , 0) < 0)
AES块大小为16字节; enc_message
将填充16个字节,其中任何一个都不是'\0'
,因此strlen(enc_message)
可能会产生一个太短的send
长度以及渲染由于数组被越过末尾访问,因此行为未定义。