量子密码的轻量级通信协议笔记

发布于:2025-05-10 ⋅ 阅读:(12) ⋅ 点赞:(0)

代码笔记

本文档提供了项目代码的详细说明,包括代码结构、关键算法实现和重要的代码片段。

代码结构

.
├── Makefile                # 构建系统配置
├── coap_client.c           # CoAP客户端实现
├── coap_server.c           # CoAP服务端实现
├── coap.c                  # CoAP协议基础功能实现
├── coap.h                  # CoAP协议相关定义和函数声明
├── rainbow.c               # Rainbow签名算法实现
├── rainbow.h               # Rainbow签名相关定义和函数声明
├── protocol_optimize.c     # 协议优化算法实现
├── protocol_optimize.h     # 协议优化相关定义和函数声明
├── protocol_test.c         # 协议优化性能测试
├── performance_analyzer.c  # 性能分析工具
├── visualize_performance.py # 性能数据可视化脚本
└── run_tests.sh            # 测试脚本

代码规范

项目采用C语言实现,遵循以下规范:

  1. 命名规范:

    • 函数名: 使用小写字母和下划线,如 rainbow_sign()
    • 变量名: 使用小写字母和下划线,如 message_id
    • 常量和宏: 使用大写字母和下划线,如 KYBER_PUBLICKEYBYTES
    • 结构体: 使用驼峰命名法,如 PerformanceMetrics
  2. 代码缩进:

    • 使用4个空格缩进
    • 大括号放在同一行
  3. 注释规范:

    • 函数前使用多行注释说明功能
    • 复杂逻辑处使用单行注释
    • 所有公共API都有文档注释
  4. 错误处理:

    • 所有函数返回值都进行检查
    • 使用返回值指示错误状态
    • 内存分配都检查是否成功

CoAP协议实现 (coap.c/h)

CoAP消息格式

typedef struct {
    uint8_t version;         // CoAP版本号(固定为1)
    uint8_t type;            // 消息类型(CON, NON, ACK, RST)
    uint8_t token_len;       // 令牌长度(0-8字节)
    uint8_t code;            // 响应码
    uint16_t message_id;     // 消息ID
    uint8_t token[8];        // 令牌
    Option *options;         // 选项链表
    uint8_t *payload;        // 有效负载
    size_t payload_len;      // 有效负载长度
} CoAPMessage;

消息类型

#define COAP_MESSAGE_CON 0   // 需要确认的消息
#define COAP_MESSAGE_NON 1   // 不需要确认的消息
#define COAP_MESSAGE_ACK 2   // 确认消息
#define COAP_MESSAGE_RST 3   // 重置消息

核心函数

消息创建和释放
// 创建新的CoAP消息
CoAPMessage *coap_message_create();

// 释放CoAP消息资源
void coap_message_free(CoAPMessage *message);
消息编码和解码
// 将CoAP消息编码为二进制格式
int coap_message_encode(const CoAPMessage *message, uint8_t *buffer, size_t buffer_len);

// 从二进制数据解码CoAP消息
int coap_message_decode(CoAPMessage *message, const uint8_t *buffer, size_t buffer_len);
分块传输实现

实现了简化版的CoAP分块传输机制,使用Block2选项:

// 添加Block2选项
int coap_add_block2_option(CoAPMessage *message, uint32_t num, uint8_t more, uint16_t size);

// 解析Block2选项
int coap_parse_block2_option(const CoAPMessage *message, uint32_t *num, uint8_t *more, uint16_t *size);

Rainbow签名实现 (rainbow.h/c)

关键数据结构

// Rainbow密钥对结构
typedef struct {
    unsigned char public_key[RAINBOW_PUBLIC_KEY_BYTES];
    unsigned char private_key[RAINBOW_PRIVATE_KEY_BYTES];
} RainbowKeyPair;

主要函数

密钥生成
void rainbow_keygen(RainbowKeyPair *keypair) {
    printf("rainbow_keygen 开始\n");
    // 使用 rand() 生成私钥
    for (int i = 0; i < RAINBOW_PRIVATE_KEY_BYTES; i++) {
        keypair->private_key[i] = rand() % 256;
    }
    // 使用 SHA256 哈希私钥生成公钥,确保单向性
    unsigned char hash[SHA256_DIGEST_LENGTH];
    SHA256(keypair->private_key, RAINBOW_PRIVATE_KEY_BYTES, hash);
    for (int i = 0; i < RAINBOW_PUBLIC_KEY_BYTES; i++) {
        keypair->public_key[i] = hash[i % SHA256_DIGEST_LENGTH];
    }
    printf("rainbow_keygen 完成,私钥前16字节: ");
    for (int i = 0; i < 16; i++) printf("%02x", keypair->private_key[i]);
    printf("\n公钥前16字节: ");
    for (int i = 0; i < 16; i++) printf("%02x", keypair->public_key[i]);
    printf("\n");
}
签名和验证
// 签名实现
void rainbow_sign(unsigned char *signature, const unsigned char *message, 
                 size_t message_len, const unsigned char *private_key) {
    // 计算消息哈希
    unsigned char hash[SHA256_DIGEST_LENGTH];
    SHA256(message, message_len, hash);
    
    // 生成签名 = 哈希 XOR 私钥
    for (int i = 0; i < RAINBOW_SIGNATURE_BYTES; i++) {
        signature[i] = hash[i % SHA256_DIGEST_LENGTH] ^ 
                       private_key[i % RAINBOW_PRIVATE_KEY_BYTES];
    }
}

// 简化的验证实现(实际使用中替换为真正的验证逻辑)
int rainbow_verify(const unsigned char *message, size_t message_len, 
                  const unsigned char *signature, const unsigned char *public_key) {
    // 注意:这是一个简化实现,总是返回验证成功
    return 1;
}

协议优化实现 (protocol_optimize.c/h)

1. 报文压缩 (RLE算法)

// 应用游程长度编码(RLE)压缩
size_t apply_compression(unsigned char *input, size_t input_len, 
                         unsigned char *output, size_t output_max_len) {
    // 如果输入数据较小,直接使用未压缩模式
    if (input_len < 512) {
        output[0] = 0xC1;  // 未压缩标记
        memcpy(output + 1, input, input_len);
        return input_len + 1;
    }
    
    size_t out_pos = 1; // 保留第一个字节作为压缩模式标记
    size_t in_pos = 0;
    
    while (in_pos < input_len) {
        // 查找连续相同的字节序列
        unsigned char current = input[in_pos];
        size_t run_length = 1;
        
        while (in_pos + run_length < input_len && 
               input[in_pos + run_length] == current && 
               run_length < 255) {
            run_length++;
        }
        
        // 如果序列长度超过3,使用RLE编码
        if (run_length >= 3) {
            // 写入RLE标记、重复字节和重复次数
            output[out_pos++] = 0xFF; // RLE标记
            output[out_pos++] = current; // 重复字节
            output[out_pos++] = run_length; // 重复次数
        } else {
            // 对于短序列,直接复制
            for (size_t j = 0; j < run_length; j++) {
                output[out_pos++] = current;
            }
        }
        
        // 移动到下一个未处理的字节
        in_pos += run_length;
    }
    
    // 设置压缩模式标记
    output[0] = 0xC0;
    return out_pos;
}
解压缩实现
// 对应的解压缩算法
size_t decompress_data(unsigned char *input, size_t input_len, 
                      unsigned char *output, size_t output_max_len) {
    // 检查压缩标记
    if (input[0] == 0xC1) {
        // 未压缩数据,直接复制
        size_t copy_len = input_len - 1;
        if (copy_len > output_max_len) {
            copy_len = output_max_len;
        }
        
        memcpy(output, input + 1, copy_len);
        return copy_len;
    } else if (input[0] != 0xC0) {
        // 无效的压缩标记
        return 0;
    }
    
    // 解压缩RLE编码的数据
    size_t in_pos = 1;  // 跳过压缩标记
    size_t out_pos = 0;
    
    while (in_pos < input_len && out_pos < output_max_len) {
        // 检查是否是RLE编码标记
        if (input[in_pos] == 0xFF && in_pos + 2 < input_len) {
            // 读取重复字节和次数
            unsigned char value = input[in_pos + 1];
            unsigned char count = input[in_pos + 2];
            
            // 展开重复序列
            for (unsigned char i = 0; i < count; i++) {
                output[out_pos++] = value;
            }
            
            // 移动到下一个编码
            in_pos += 3;
        } else {
            // 直接复制单个字节
            output[out_pos++] = input[in_pos++];
        }
    }
    
    return out_pos;
}

2. 会话密钥复用

数据结构
// 会话密钥缓存结构
typedef struct {
    unsigned char key[64]; // 足够大以存储各种密钥
    size_t key_len;
    unsigned char associated_data[256]; // 关联数据(如IP地址、端口等)
    size_t ad_len;
    time_t creation_time;
    int valid;
} SessionKeyCache;

#define MAX_SESSION_KEYS 10
static SessionKeyCache session_keys[MAX_SESSION_KEYS];
static int session_key_count = 0;
密钥保存与检索
// 保存会话密钥供后续使用
void save_session_key(const unsigned char *key, size_t key_len, 
                     const unsigned char *associated_data, size_t ad_len) {
    int index = -1;
    
    // 如果已存在相同关联数据的条目,则更新它
    if (associated_data && ad_len > 0) {
        for (int i = 0; i < session_key_count; i++) {
            if (session_keys[i].ad_len == ad_len && 
                memcmp(session_keys[i].associated_data, associated_data, ad_len) == 0) {
                index = i;
                break;
            }
        }
    }
    
    // 如果未找到现有条目,创建一个新的或替换最老的
    if (index == -1) {
        if (session_key_count < MAX_SESSION_KEYS) {
            index = session_key_count++;
        } else {
            // 替换最老的会话密钥
            time_t oldest_time = time(NULL);
            int oldest_idx = 0;
            
            for (int i = 0; i < MAX_SESSION_KEYS; i++) {
                if (session_keys[i].creation_time < oldest_time) {
                    oldest_time = session_keys[i].creation_time;
                    oldest_idx = i;
                }
            }
            
            index = oldest_idx;
        }
    }
    
    // 更新会话密钥条目
    memcpy(session_keys[index].key, key, key_len);
    session_keys[index].key_len = key_len;
    
    if (associated_data && ad_len > 0) {
        memcpy(session_keys[index].associated_data, associated_data, ad_len);
        session_keys[index].ad_len = ad_len;
    }
    
    session_keys[index].creation_time = time(NULL);
    session_keys[index].valid = 1;
}

// 检索之前保存的会话密钥
int retrieve_session_key(unsigned char *key, size_t key_len,
                        const unsigned char *associated_data, size_t ad_len) {
    for (int i = 0; i < session_key_count; i++) {
        if (session_keys[i].valid && 
            session_keys[i].ad_len == ad_len && 
            memcmp(session_keys[i].associated_data, associated_data, ad_len) == 0) {
            
            // 检查密钥是否过期 (24小时)
            time_t now = time(NULL);
            if (now - session_keys[i].creation_time > 24 * 60 * 60) {
                session_keys[i].valid = 0;
                return 0;
            }
            
            // 复制密钥
            size_t copy_len = key_len < session_keys[i].key_len ? 
                              key_len : session_keys[i].key_len;
            memcpy(key, session_keys[i].key, copy_len);
            
            return 1; // 成功找到并复制密钥
        }
    }
    
    return 0; // 未找到匹配的密钥
}

3. 协议头压缩

// 应用协议头压缩
size_t apply_header_reduction(unsigned char *buffer, size_t buffer_len) {
    // 添加协议头压缩标记 0xA5
    unsigned char header_flag = 0xA5;
    
    // 检查是否是CoAP首包并需要压缩
    if (buffer_len >= 8 && ((buffer[0] >> 4) & 0x0F) <= 3) {
        // 提取和保留重要字段
        unsigned char type_ver = buffer[0];
        unsigned char code = buffer[1];
        unsigned short message_id = (buffer[2] << 8) | buffer[3];
        
        // 创建压缩头部
        unsigned char new_header[5];
        new_header[0] = header_flag;
        new_header[1] = type_ver;
        new_header[2] = code;
        new_header[3] = (message_id >> 8) & 0xFF;
        new_header[4] = message_id & 0xFF;
        
        // 计算选项部分起始位置
        size_t options_start = 4;
        size_t payload_marker_pos = 0;
        
        // 找到有效载荷标记0xFF的位置
        for (size_t i = options_start; i < buffer_len; i++) {
            if (buffer[i] == 0xFF) {
                payload_marker_pos = i;
                break;
            }
        }
        
        // 如果找到有效载荷标记
        if (payload_marker_pos > 0) {
            // 计算需要移动的数据大小
            size_t options_size = payload_marker_pos - options_start;
            size_t payload_size = buffer_len - payload_marker_pos - 1;
            
            // 复制压缩头部
            memmove(buffer, new_header, 5);
            
            // 复制选项部分(如果有)
            if (options_size > 0) {
                memmove(buffer + 5, buffer + options_start, options_size);
            }
            
            // 添加有效载荷标记
            buffer[5 + options_size] = 0xFF;
            
            // 复制有效载荷数据(如果有)
            if (payload_size > 0) {
                memmove(buffer + 5 + options_size + 1, 
                        buffer + payload_marker_pos + 1, 
                        payload_size);
            }
            
            // 返回新的缓冲区长度
            return 5 + options_size + 1 + payload_size;
        }
    }
    
    // 如果不能压缩,返回原始长度
    return buffer_len;
}

性能测试 (protocol_test.c)

测试数据生成

// 生成测试数据
TestData generate_test_data(size_t size) {
    TestData data;
    data.data = (unsigned char *)malloc(size);
    data.data_len = size;
    
    if (data.data) {
        // 填充一些模拟数据
        for (size_t i = 0; i < size; i++) {
            // 生成一些模式用于测试压缩效果
            if (i % 100 < 20) {
                data.data[i] = 0x00;  // 一些零字节
            } else if (i % 100 < 40) {
                data.data[i] = 0xFF;  // 一些FF字节
            } else if (i % 100 < 60) {
                data.data[i] = i & 0xFF;  // 递增模式
            } else if (i % 100 < 80) {
                data.data[i] = 'A' + (i % 26);  // 文本模式
            } else {
                data.data[i] = rand() & 0xFF;  // 随机数据
            }
        }
    }
    
    return data;
}

性能计时器

// 启动计时器
void start_timer(struct timespec *timer) {
    if (!timer) return;
    
    clock_gettime(CLOCK_MONOTONIC, timer);
}

// 停止计时器并返回经过的毫秒数
double stop_timer(struct timespec *timer) {
    if (!timer) return 0.0;
    
    struct timespec end;
    clock_gettime(CLOCK_MONOTONIC, &end);
    
    double milliseconds = (end.tv_sec - timer->tv_sec) * 1000.0;
    milliseconds += (end.tv_nsec - timer->tv_nsec) / 1000000.0;
    
    return milliseconds;
}

客户端和服务端实现

客户端通信流程

// 简化的客户端通信逻辑
int main() {
    // 1. 初始化(创建套接字、绑定端口等)
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    
    // 2. 生成密钥对(Kyber和Rainbow)
    crypto_kem_keypair(client_pk, client_sk);
    rainbow_keygen(&rainbow_keypair);
    
    // 3. 发送公钥到服务端
    CoAPMessage *request = coap_message_create();
    // ... 设置请求参数
    coap_send_request(sock, request, server_addr);
    
    // 4. 接收服务端的公钥和密文
    CoAPMessage *response = coap_receive_response(sock);
    
    // 5. 解密共享密钥
    crypto_kem_dec(shared_secret, server_ciphertext, client_sk);
    
    // 6. 验证服务端签名
    rainbow_verify(server_message, message_len, server_signature, server_rainbow_pk);
    
    // 7. 使用共享密钥进行后续通信
    // ...
    
    return 0;
}

服务端通信流程

// 简化的服务端通信逻辑
int main() {
    // 1. 初始化(创建套接字、绑定端口等)
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    bind(sock, (struct sockaddr*)&server_addr, sizeof(server_addr));
    
    // 2. 生成密钥对(Kyber和Rainbow)
    crypto_kem_keypair(server_pk, server_sk);
    rainbow_keygen(&rainbow_keypair);
    
    // 3. 等待客户端连接并接收公钥
    CoAPMessage *request = coap_receive_request(sock);
    
    // 4. 使用客户端公钥加密共享密钥
    crypto_kem_enc(ciphertext, shared_secret, client_pk);
    
    // 5. 对消息进行签名
    rainbow_sign(signature, message, message_len, rainbow_keypair.private_key);
    
    // 6. 发送服务端公钥、密文和签名
    CoAPMessage *response = coap_message_create();
    // ... 设置响应参数
    coap_send_response(sock, response, client_addr);
    
    // 7. 使用共享密钥进行后续通信
    // ...
    
    return 0;
}

优化算法复杂度分析

1. 报文压缩算法 (RLE)

  • 时间复杂度: O(n),其中n是输入数据的长度
  • 空间复杂度: O(n),最坏情况下压缩后数据与原始数据大小相当
  • 最佳场景: 数据中包含大量连续重复字节

2. 会话密钥复用

  • 时间复杂度:
    • 保存: O(k),其中k是最大存储的密钥数量
    • 检索: O(k),需要线性搜索所有密钥
  • 空间复杂度: O(k),存储k个密钥及其元数据
  • 优化点: 可以使用哈希表提高检索效率至O(1)

3. 协议头压缩

  • 时间复杂度: O(n),其中n是消息长度
  • 空间复杂度: O(1),使用固定额外空间
  • 节省空间: 通常在小数据包中节省1-5字节

安全考虑

密钥管理

  • 当前实现中,密钥直接存储在内存中,生产环境应考虑:
    • 安全的密钥存储(如TPM, HSM)
    • 密钥分发机制
    • 密钥轮换策略

简化实现的限制

  • Rainbow签名实现是简化版本,不提供真正的安全保证
  • 会话密钥目前只有简单的时间失效机制
  • 没有防止重放攻击的机制

增强安全性的建议

  1. 替换Rainbow为标准化的后量子签名算法
  2. 添加随机数和时间戳防止重放攻击
  3. 实现完整的TLS/DTLS安全层
  4. 加入密钥衍生函数(KDF)和安全的随机数生成器

调试技巧

输出调试信息

在关键函数中添加如下代码以启用调试输出:

#ifdef DEBUG_LOGGING
#define DEBUG_LOG(fmt, ...) printf("[DEBUG] " fmt "\n", ##__VA_ARGS__)
#else
#define DEBUG_LOG(fmt, ...)
#endif

// 使用示例
DEBUG_LOG("Processing message ID: %d", message_id);

内存调试

使用Valgrind检查内存泄漏:

valgrind --leak-check=full --show-leak-kinds=all ./coap_server

网络调试

使用tcpdump或Wireshark捕获CoAP数据包:

sudo tcpdump -i lo udp port 5683 -vvv -X

网站公告

今日签到

点亮在社区的每一天
去签到