20.6 OpenSSL 套接字分发RSA公钥

编程入门 行业动态 更新时间:2024-10-25 21:21:55

20.6 OpenSSL 套接字分发RSA<a href=https://www.elefans.com/category/jswz/34/1770983.html style=公钥"/>

20.6 OpenSSL 套接字分发RSA公钥

通过上一节的学习读者应该能够更好的理解RSA加密算法在套接字传输中的使用技巧,但上述代码其实并不算完美的,因为我们的公钥和私钥都必须存储在本地文本中且公钥与私钥是固定的无法做到更好的保护效果,而一旦公钥与私钥泄密则整个传输流程都将会变得不安全,最好的保护效果是RSA密钥在每次通信时都进行变换,依次来实现随机密钥对的功能。

20.6.1 RSA算法封装

要实现这个效果我们就需要封装一套可以在内存中生成密钥对的函数,当需要传输数据时动态的生成密钥对,并将公钥部分通过套接字传输给对应的客户端,当客户端收到公钥后则可以使用该公钥进行通信,此时公钥与私钥全程不会存储为文件,这能极大的提升RSA算法的安全性。

要实现内存传输则首先需要封装实现RSA内存生成密钥对函数GenerateMemoryRSAKeys,以及rsa_encrypt加密函数,rsa_decrypt解密函数,读者可自行理解并使用如下代码片段。

#include <iostream>
#include <Windows.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/crypto.h>extern "C"
{
#include <openssl/applink.c>
}#pragma comment(lib,"ws2_32.lib")
#pragma comment(lib,"libssl_static.lib")
#pragma comment(lib,"libcrypto.lib")// 生成RSA需要的公钥和私钥
BOOL GenerateMemoryRSAKeys(char** private_key, char** public_key, int key_length)
{// 生成Key函数RSA* keypair = RSA_generate_key(key_length, 3, NULL, NULL);BIO* pri = BIO_new(BIO_s_mem());BIO* pub = BIO_new(BIO_s_mem());// 生成写出私钥if (!PEM_write_bio_RSAPrivateKey(pri, keypair, NULL, NULL, 0, NULL, NULL)){return FALSE;}// 生成写出公钥if (!PEM_write_bio_RSAPublicKey(pub, keypair)){return FALSE;}size_t pri_len = BIO_pending(pri);size_t pub_len = BIO_pending(pub);// 分配内存存储公钥与私钥char* prikey = (char*)malloc(pri_len + 1);char* pubkey = (char*)malloc(pub_len + 1);if (prikey == NULL && pubkey == NULL){return FALSE;}// 将公钥与私钥读入到堆中BIO_read(pri, prikey, pri_len);BIO_read(pub, pubkey, pub_len);*private_key = prikey;*public_key = pubkey;RSA_free(keypair);BIO_free_all(pri);BIO_free_all(pub);return TRUE;
}// RSA 加密函数
// type=public 使用公钥加密 type=private 使用私钥加密
BOOL rsa_encrypt(char* pub_key, char* msg, char** encrypt, int* encrypt_len, char *type)
{RSA* rsa = NULL;BIO* keybio = BIO_new_mem_buf((void*)pub_key, -1);char* err = (char*)malloc(130);if (keybio == NULL){return FALSE;}// 如果是public则使用公钥加密/如果是private则使用私钥if (strcmp(type, "public") == 0){// PEM_read_bio_RSA_PUBKEY(keybio, NULL, NULL, NULL)if (!(rsa = PEM_read_bio_RSAPublicKey(keybio, NULL, NULL, NULL))){return FALSE;}}else if (strcmp(type, "private") == 0){// 读取私钥文件if (!(rsa = PEM_read_bio_RSAPrivateKey(keybio, NULL, NULL, NULL))){return FALSE;}}*encrypt_len = RSA_size(rsa);*encrypt = (char*)malloc(4096);if (strcmp(type, "public") == 0){// 使用公钥加密if ((RSA_public_encrypt(strlen(msg) + 1, (unsigned char*)msg, (unsigned char*)*encrypt, rsa, RSA_PKCS1_PADDING)) == -1){return FALSE;}}else if (strcmp(type, "private") == 0){// 使用私钥加密if ((RSA_private_encrypt(strlen(msg) + 1, (unsigned char*)msg, (unsigned char*)*encrypt, rsa, RSA_PKCS1_PADDING)) == -1){return FALSE;}}RSA_free(rsa);free(err);BIO_free_all(keybio);return TRUE;
}// RSA 解密函数
// type=public 使用公钥解密 type=private 使用私钥解密
BOOL rsa_decrypt(char* pri_key, char* msg, char** decrypt, int encrypt_len, char *type)
{RSA* rsa = NULL;BIO* keybio = BIO_new_mem_buf(pri_key, -1);if (keybio == NULL){return FALSE;}// 如果是public则使用公钥解密/如果是private则使用私钥if (strcmp(type, "public") == 0){// 读入公钥文件if (!(rsa = PEM_read_bio_RSAPublicKey(keybio, NULL, NULL, NULL))){return FALSE;}}else if (strcmp(type, "private") == 0){// PEM_read_bio_RSA_PRIVATE(keybio, NULL, NULL, NULL)if (!(rsa = PEM_read_bio_RSAPrivateKey(keybio, NULL, NULL, NULL))){return FALSE;}}char* err = (char*)malloc(130);*decrypt = (char*)malloc(encrypt_len);if (strcmp(type, "public") == 0){// 使用公钥解密if (RSA_public_decrypt(encrypt_len, (unsigned char*)msg, (unsigned char*)*decrypt, rsa, RSA_PKCS1_PADDING) == -1){return FALSE;}}else if (strcmp(type, "private") == 0){// 私用私钥解密if (RSA_private_decrypt(encrypt_len, (unsigned char*)msg, (unsigned char*)*decrypt, rsa, RSA_PKCS1_PADDING) == -1){return FALSE;}}RSA_free(rsa);free(err);BIO_free_all(keybio);return TRUE;
}int main(int argc, char *argv)
{// 生成内存RSA密钥对char *private_key, *public_key;if (GenerateMemoryRSAKeys(&private_key, &public_key, 2048)){std::cout << "生成私钥: " << private_key << std::endl;std::cout << "生成公钥: " << public_key << std::endl;}char *encrypt, *decrypt;int encrypt_length;BOOL flag;// 公钥加密flag = rsa_encrypt(public_key, (char*)"hello lyshark", &encrypt, &encrypt_length, (char *)"public");if (flag == TRUE){std::cout << "[公钥加密] 公钥加密字节: " << strlen(encrypt) << std::endl;}// 私钥解密flag = rsa_decrypt(private_key, encrypt, &decrypt, encrypt_length, (char *)"private");if (flag == TRUE){std::cout << "[私钥解密] 私钥解密字节: " << decrypt << std::endl;}// 私钥加密flag = rsa_encrypt(private_key, (char*)"hello lyshark", &encrypt, &encrypt_length, (char*)"private");if (flag == TRUE){std::cout << "[私钥加密] 私钥加密字节: " << strlen(encrypt) << std::endl;}// 公钥解密flag = rsa_decrypt(public_key, encrypt, &decrypt, encrypt_length, (char*)"public");if (flag == TRUE){std::cout << "[公钥解密] 公钥解密字节: " << decrypt << std::endl;}system("pause");return 0;
}

读者可自行编译上述代码并运行,此时该代码将通过GenerateMemoryRSAKeys函数生成内存密钥对,并调用rsa_encryptrsa_decrypt两个函数实现对特定字符串的加解密功能,输出效果图如下;

20.6.2 公钥动态配对

有了上述内存生成RSA密钥对的方法,那么实现密钥对远程分发将变得很容易实现,首先我们来看客户端的实现方式,当客户端成功连接到了服务端则首先接收服务端传来的公钥,当收到服务器传来的公钥后通过使用rsa_encrypt函数并用公钥对待发送字符串进行加密,加密后调用send将加密数据发送给服务端,解密动作与加密保持一致,同样使用公钥进行解密,这段客户端代码如下所示;

int main(int argc, char* argv[])
{char buf[256] = "The National Aeronautics and Space Administration";WSADATA WSAData;// 初始化套接字库if (WSAStartup(MAKEWORD(2, 0), &WSAData)){return 0;}// 创建套接字SOCKET client_socket;client_socket = socket(AF_INET, SOCK_STREAM, 0);struct sockaddr_in ClientAddr;ClientAddr.sin_family = AF_INET;ClientAddr.sin_port = htons(9999);ClientAddr.sin_addr.s_addr = inet_addr("127.0.0.1");// 链接远程服务器if (connect(client_socket, (LPSOCKADDR)&ClientAddr, sizeof(ClientAddr)) != SOCKET_ERROR){// 接收公钥char public_key[1024] = { 0 };int recv_key_flag = recv(client_socket, public_key, 1024, 0);if (recv_key_flag > 0){std::cout << "接收公钥字节: " << public_key << std::endl;}// 公钥加密并发送数据char* encrypt = nullptr;int encrypt_length = 0;rsa_encrypt(public_key, buf, &encrypt, &encrypt_length, (char*)"public");std::cout << "[服务端发送] 公钥加密字节: " << strlen(encrypt) << std::endl;send(client_socket, encrypt, encrypt_length, 0);// 公钥接收并解密数据char* decrypt = nullptr;memset(buf, 0, 256);recv(client_socket, buf, 256, 0);rsa_decrypt(public_key, buf, &decrypt, 256, (char *)"public");std::cout << "[服务端返回] 原始数据包: " << decrypt << std::endl;closesocket(client_socket);WSACleanup();}system("pause");return 0;
}

与客户端相比,服务端在执行时只是多出来了执行GenerateMemoryRSAKeys函数的功能,通过执行该函数我们可以得到一个动态的内存加密密钥对,有了密钥对则我们就可以使用私钥对数据进行加密与解密操作,如下是服务端核心实现代码;

int main(int argc, char* argv[])
{WSADATA WSAData;// 初始化套接字库if (WSAStartup(MAKEWORD(2, 0), &WSAData)){return 0;}// 创建套接字SOCKET server_socket;server_socket = socket(AF_INET, SOCK_STREAM, 0);struct sockaddr_in ServerAddr;ServerAddr.sin_family = AF_INET;ServerAddr.sin_port = htons(9999);ServerAddr.sin_addr.s_addr = inet_addr("127.0.0.1");// 绑定并侦听套接字bind(server_socket, (LPSOCKADDR)&ServerAddr, sizeof(ServerAddr));listen(server_socket, 10);// 生成RSA密钥对char* private_key, *public_key;BOOL gen_flag = GenerateMemoryRSAKeys(&private_key, &public_key, 2048);if (gen_flag == TRUE){// std::cout << "生成私钥: " << private_key << std::endl;// std::cout << "生成公钥: " << public_key << std::endl;std::cout << "[+] 已生成RSA密钥对" << std::endl;}// 接收请求SOCKET message_socket;if ((message_socket = accept(server_socket, (LPSOCKADDR)0, (int*)0)) != INVALID_SOCKET){// 发送公钥给客户端int put_key_flag = send(message_socket, public_key, strlen(public_key), 0);if (put_key_flag > 0){std::cout << "本地私钥字节: " << private_key << std::endl;std::cout << "发送公钥字节: " << public_key << std::endl;}// 私钥解密: 接收并解密char recv_message[256] = { 0 };recv(message_socket, recv_message, 256, 0);char* decrypt = nullptr;rsa_decrypt(private_key, recv_message, &decrypt, 256, (char*)"private");std::cout << "[客户端返回] 原始数据包: " << decrypt << std::endl;// 私钥加密: 加密并发送char send_message[256] = "hello lyshark";char* encrypt = nullptr;int encrypt_length = 0;rsa_encrypt(private_key, send_message, &encrypt, &encrypt_length, (char*)"private");send(message_socket, encrypt, encrypt_length, 0);}closesocket(server_socket);WSACleanup();system("pause");return 0;
}

读者可自行编译并运行上述代码,首先运行服务端接着运行客户端,读者则可看到如下图所示的输出信息;

更多推荐

20.6 OpenSSL 套接字分发RSA公钥

本文发布于:2023-11-16 18:33:44,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1632186.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:公钥   OpenSSL   RSA

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!