You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于OpenSSL的专有协议TLS流密钥材料解密测试问询

解决方案:保存OpenSSL TLS加密流与密钥材料用于离线验证

我刚好做过类似的OpenSSL TLS内存BIO项目,给你梳理一套可行的方案,帮你保存加密流和密钥材料来做离线测试验证:

一、保存加密流到文件

因为你用的是内存BIO,加密后的字节流不会走网络链路,所以只需要在数据进出内存BIO的节点,把原始加密数据同步写入二进制文件即可。比如在调用SSL_write生成加密数据后,或者SSL_read读取到加密数据前,把对应缓冲区的内容追加写入文件,不会影响原有业务逻辑:

// 假设已通过SSL_write得到加密数据,存于buf中,长度为len
FILE *enc_stream_fp = fopen("encrypted_stream.bin", "ab");
if (enc_stream_fp) {
    // 按字节写入加密流
    fwrite(buf, 1, len, enc_stream_fp);
    fflush(enc_stream_fp);
    // 建议会话结束后再关闭文件,避免频繁IO影响性能
}

这个二进制文件就是完整的加密字节流,后续解密时直接读取即可。

二、提取并保存密钥材料

密钥材料是离线解密的核心,OpenSSL提供了多种接口来获取TLS会话相关密钥:

  1. 主密钥提取:握手完成后,通过会话对象获取主密钥,它是衍生所有会话密钥的基础
  2. 直接提取会话密钥/IV:通过SSL_export_keying_material可以直接获取用于加解密的对称密钥、初始向量等材料

代码示例如下:

// 握手完成后获取当前TLS会话
SSL_SESSION *session = SSL_get_session(ssl);
if (session) {
    // 提取主密钥
    unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH];
    int master_key_len = SSL_SESSION_get_master_key(session, master_key, sizeof(master_key));
    
    FILE *key_fp = fopen("tls_master_key.bin", "wb");
    if (key_fp) {
        // 先写入密钥长度,方便后续读取解析
        fwrite(&master_key_len, sizeof(int), 1, key_fp);
        fwrite(master_key, 1, master_key_len, key_fp);
        fclose(key_fp);
    }

    // 提取更详细的密钥材料(如对称加密密钥、IV)
    unsigned char keying_material[128]; // 根据TLS版本调整大小
    // 自定义标签区分不同类型的密钥材料,比如"client_write_key"
    int km_len = SSL_export_keying_material(ssl, keying_material, sizeof(keying_material),
                                            "client_write_key", strlen("client_write_key"),
                                            NULL, 0, 0);
    if (km_len > 0) {
        FILE *km_fp = fopen("tls_session_keys.bin", "wb");
        if (km_fp) {
            fwrite(&km_len, sizeof(int), 1, km_fp);
            fwrite(keying_material, 1, km_len, km_fp);
            fclose(km_fp);
        }
    }
}

三、离线解密验证流程

有了加密流和密钥材料后,就可以编写离线解密工具验证加密有效性:

  1. 初始化和原项目一致的SSL上下文(相同TLS版本、加密套件)
  2. 用保存的密钥恢复TLS会话状态
  3. 读取加密流文件,分块传入SSL对象执行解密
  4. 将解密后的明文与原始业务数据对比,验证一致性

核心代码框架:

// 初始化SSL上下文(和原项目保持一致)
SSL_CTX *ctx = SSL_CTX_new(TLS_client_method()); // 服务器端用TLS_server_method()
SSL *ssl = SSL_new(ctx);

// 恢复会话并设置密钥
SSL_SESSION *session = SSL_SESSION_new();
// 读取保存的主密钥并设置到会话中
SSL_SESSION_set_master_key(session, master_key, master_key_len);
SSL_set_session(ssl, session);

// 绑定内存BIO用于解密
BIO *in_bio = BIO_new_mem_buf(encrypted_data, encrypted_len); // encrypted_data从文件读取
BIO *out_bio = BIO_new(BIO_s_mem());
SSL_set_bio(ssl, in_bio, out_bio);

// 执行解密并输出结果
char decrypted_buf[4096];
int decrypted_len;
FILE *plain_fp = fopen("decrypted_plaintext.bin", "wb");
while ((decrypted_len = SSL_read(ssl, decrypted_buf, sizeof(decrypted_buf))) > 0) {
    fwrite(decrypted_buf, 1, decrypted_len, plain_fp);
}

// 清理资源
fclose(plain_fp);
SSL_free(ssl);
SSL_CTX_free(ctx);

关键注意事项

  • 密钥材料属于敏感数据,保存时要做好权限控制,避免泄露
  • 确保离线解密工具使用的OpenSSL版本与原项目一致,不同版本的密钥衍生逻辑可能存在差异
  • 加密流的保存要保证字节顺序和完整性,不能出现丢包、乱序,否则解密会失败
  • 如果是分段发送的加密数据,保存时要按原始顺序拼接成完整字节流

内容的提问来源于stack exchange,提问作者Vert

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 04:04:34