C. 建立安全通信议定书的先决条件

在潜入执行前,确保您的开发环境包括一个 C 编译器(GCC 或 Clang), 套接字编程的基本知识, 以及安装的 OpenSSL 库. OpenSSL 提供了强大的加密算法执行, 使其成为 C. On Linux 中的安全通信的标准选择, 通过您的软件包管理器安装 OpenSSL (例如 [[FLT: 0]]) 。 在 Windows 上, 使用预编译的二进制或从源构建 。 也假设了 TCP/IP 套接字和客户端服务器模型的熟悉度 。

理解密码建筑区块

安全通信协议基于三个支柱:保密、完整性和认证。保密是通过加密实现的,确保只有预定的收件人才能读取消息。诚信确保了数据在中转过程中不被更改。认证验证了通信方的身份。在自定义协议中,通常您会将对称加密、散列和消息认证代码(HMAC)以及像Diffie-Hellman这样的关键交换机制结合起来。

与 AES 对称加密

高级加密标准(AES)是使用最广泛的对称密码。它运行在128位块上,并支持128、192或256位的密钥大小。对于安全通信,更喜欢在Galois/Counter Mode(GCM)中提供保密性和完整性的AES。 OpenSSL的EVP接口使得它能够直接与AES GCM加密和解密数据。除非结合小心的垫装和认证,否则避免使用欧洲央行或CBC等较旧的模式。

与 Diffie- Hellman 的密钥交换

为了在无担保的信道上安全地商定一个共同的秘密,使用Diffie-Hellman(DH)密钥交换。双方生成私人密钥并交换公共参数,然后计算一个共同的秘密。Diffie-Hellman[ 如果未经认证,很容易受到人-in-the-middle攻击,因此,您可以随后用数字签名或预-共享密钥来扩展这一范围。对于生产,考虑使用电子密钥(DHE)来提供完美的前向保密。

信件完整性和 HMAC 认证

为了确认信件是否未被篡改, 请在每封加密密码文本中附加基于 Hash % 的信件认证代码( HMAC)。 HMAC 使用共享的秘密密钥和密码散列函数( 如 SHA % 256) 。 接收器在接收的数据上重算 HMAC 并将其与传输值进行比较。 这一步骤防止了重播和篡改攻击。 或者, AES % GCM 包含一个具有相同目的的认证标记, 简化协议 。

在您的 C 工程中设置 OpenSSL

OpenSSL 需要小心初始化。 在程序开始时包含必要的头并拨打 [[FLT: 1] 和 [[FLT: 2]] 。 对于错误处理, 请使用 [[FLT: 3] 和 [[FLT: 4]] 。 链接时, 在编译器旗下添加 [[FLT: 5] 。 最小设置看起来是这样 :

#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/err.h>
// Initialize OpenSSL
void init_openssl() {
 SSL_load_error_strings();
 OpenSSL_add_all_algorithms();
}

构建 TCP 套接层

您协议的基本传输方式是 TCP, 它提供了可靠和有序的发送。 创建一个服务器, 用于收听接通的连接, 以及启动握手的客户端。 使用标准 POSIX 套接字, 其内容包括 [ [FLT: 7] , [[FLT: 8]]], [[FLT: 9]]] , 服务器侧, 以及 [[FLT: 11]] , [[FLT: 12]] 。 使用后请记住处理错误并关闭文件描述符 。

服务器示例

int server_fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(8080);
bind(server_fd, (struct sockaddr*)&address, sizeof(address));
listen(server_fd, 3);
int client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &addr_len);

客户端示例Skeleton

int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);
inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr);
connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr));

执行 Diffie - Hellman 密钥交换

在建立 TCP 连接后, 客户端和服务器执行 DH 密钥交换。 每边使用 OpenSSL [[FLT: 1 15] ] API 生成 DH 密钥对。 公钥会通过套接字发送, 双方使用 [[FLT: 16] ] 获取共享密钥。 为了简单起见, 请使用固定的质组( 如 [[FLT: 17] ) , 参数来自 [[FLT: 18] 。 在真正的协议中, 您会谈判组合或使用预定义的参数 。

// Generate DH parameters
EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DH, NULL);
EVP_PKEY_paramgen_init(pctx);
EVP_PKEY_CTX_set_dh_paramgen_prime_len(pctx, 2048);
EVP_PKEY *params = NULL;
EVP_PKEY_paramgen(pctx, &params);

// Generate key pair
EVP_PKEY_CTX *kctx = EVP_PKEY_CTX_new(params, NULL);
EVP_PKEY_keygen_init(kctx);
EVP_PKEY *my_key = NULL;
EVP_PKEY_keygen(kctx, &my_key);

// Export public key to send
unsigned char *pub_key_der = NULL;
int pub_len = i2d_PUBKEY(my_key, &pub_key_der);
send(sock, pub_key_der, pub_len, 0);

在接收端,同行使用]导入公钥,然后获得共享密钥。衍生密钥可以散开(例如,与SHA ⁇ 256),为AES和HMAC生产统一的密钥。

用 AES GCM 加密和解密信件

AES GCM 是一个首选模式,因为它在一次操作中同时提供加密和认证标记。使用 OpenSSL 的 ] 和 。您需要12+byte unce(IV) 和来自 DH 共享密钥的256+bit 密钥。密码是用块生成的,在最后更新后,您会检索16+byte 标记。 发送非ce, 密码和标签。 接收器执行 [[FLT: 23] , 设置标记和解密。 如果标记验证失败, 信息会被拒绝 。

// Encryption
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, key, nonce);
unsigned char ciphertext[1024];
int outlen;
EVP_EncryptUpdate(ctx, ciphertext, &outlen, plaintext, len);
int tmplen;
EVP_EncryptFinal_ex(ctx, ciphertext + outlen, &tmplen);
unsigned char tag[16];
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag);

添加 HMAC (或使用 GCM 标签) 完整性

如果您选择不使用 AES GCM, 您可以使用 AES CBC 加密, 然后在密码文本上计算 HMAC 。 请使用 OpenSSL 中的 [[ [FLT: 25] 。 在密码文本后添加 HMAC 。 接收器会重新计算和比较 。 这种方法需要两个密钥: 一个用于加密, 一个用于 HMAC 。 使用 HKDF 这样的密钥衍生函数从共享密钥中获取。 然而, AES GCM 取消了对单独的 HMAC 的需求, 降低了复杂度和潜在的错误 。

将它放在一起:完整的工作流程

  1. 建立客户端和服务器之间的TCP连接.
  2. 双方生成麻黄Diffie Hellman键对.
  3. 交换公用钥匙 计算共享的秘密
  4. 衍生256 ⁇ bit AES键和256 ⁇ bit HMAC键(或对GCM使用相同的键).
  5. 客户端发送一个非ce( 12 字节随机) , 然后是 AES GCM 加密消息加标签 。 服务器解密并验证 。
  6. 服务器使用新的非ce发送回复(从未重复使用同一密钥的非ce).
  7. 双方可以继续交流信息;长时间的会话,定期使用相同的DH握手或鼠标机制重排.

安保最佳做法

  • 使用强随机数生成器. 从 OpenSSL 调用 生成密钥, 非密钥, 和 DH 私钥。 永远不要为加密目的使用 或 ] 。
  • 校验所有收到的数据. 检查长度,公钥参数(例如,保证p是质,g是生成器),处理前HMAC标记.
  • 避免硬码密钥或默认. 总是每会话谈判新鲜密钥,以提供完美的前向密钥.
  • 轻轻地处理错误. 如果解密失败或HMAC验证失败, 请关闭连接并登录事件。 不要透露失败的原因 。
  • 保持依赖性更新. 定期更新 OpenSSL 以补补补已知的弱点. OpenSSL文档 提供了折旧和最佳做法的指导.
  • 考虑使用TLS而不是自定义协议。 对于生产系统,依赖像TLS 1.3这样的经过良好测试的协议。从头开始构建自定义协议容易出错,除非您具有深层加密专业知识,否则不推荐。

测试《议定书》

通过运行同一机器( localhost) 上的客户端和服务器来测试您的执行, 并验证消息是否正确解密。 引入错误, 如篡改的密码文本或无效的非目录, 以确保协议拒绝它们。 使用 Wireshark 等工具检查原始网络流量, 并证实纯文本不可见 。 对于单位测试, 请分别模拟套接字层和测试密码原始 。 OpenSSL 的 [[FLT: 29]] 调试可以帮助验证中间值与预期输出的匹配 。

结论

在 C 中构建安全通信协议是一项出色的学习活动,但需要仔细研究细节。 通过利用 OpenSSL 已证明的 Diffie-Hellman、AES-GCM 和 HMAC 的操作,您可以创建一个提供保密、完整性和认证的系统。 始终遵循加密最佳做法:使用强随机性、用 KDF 获取会话键、永远不重复使用非对子,以及彻底验证所有数据。对于学习项目以外的任何内容,请考虑采用标准协议,如 TLS 1.3, 已经严格审查和部署。 安全通信是一个持续改进的过程;随时了解新出现的威胁并相应地更新您的实施。