openssl使用哈希算法生成随机密钥

时间:2024-12-05 17:44:23

文章目录

  • 一、openssl中随机数函数
      • **OpenSSL 随机数函数概览**
        • 1. **核心随机数函数**
      • **常用函数详解**
        • 1. `RAND_bytes`
        • 2. `RAND_priv_bytes`
        • 3. `RAND_seed` 和 `RAND_add`
        • 4. `RAND_status`
      • **随机数生成器的熵池**
      • **常见用例**
      • **注意事项**
  • 二、使用哈希算法生成随机的密钥


一、openssl中随机数函数

OpenSSL 提供了一套功能强大的随机数生成函数,用于生成高质量的伪随机数。随机数在密码学中至关重要,广泛用于密钥生成、盐值生成、初始化向量 (IV) 等安全操作。


OpenSSL 随机数函数概览

1. 核心随机数函数
函数名称 描述
RAND_bytes 生成高质量的伪随机字节。
RAND_priv_bytes 生成高质量伪随机字节,推荐用于对安全性要求更高的密钥生成。
RAND_pseudo_bytes 生成伪随机字节(不保证是加密级别安全,已被弃用)。
RAND_seed 手动为伪随机数生成器添加种子值。
RAND_add 添加额外的熵(种子数据)到伪随机数生成器的池中。
RAND_status 检查随机数生成器是否被正确初始化。
RAND_poll 自动收集熵以初始化随机数生成器(由内部调用)。

常用函数详解

1. RAND_bytes
  • 作用:生成高质量的加密级别伪随机字节。

  • 函数原型

    int RAND_bytes(unsigned char *buf, int num);
    
    • buf:指向用于存储随机字节的缓冲区。
    • num:要生成的随机字节数。
    • 返回值
      • 成功返回 1
      • 如果随机数生成器未正确初始化,返回 0
  • 示例

    unsigned char random_bytes[16];
    if (RAND_bytes(random_bytes, sizeof(random_bytes)) == 1) {
        printf("生成的随机数:");
        for (int i = 0; i < sizeof(random_bytes); i++) {
            printf("%02x", random_bytes[i]);
        }
        printf("\n");
    } else {
        fprintf(stderr, "随机数生成失败!\n");
    }
    

2. RAND_priv_bytes
  • 作用:与 RAND_bytes 类似,但专为高安全性应用设计(如密钥生成)。可能在实现中增加额外的保护。
  • 函数原型
    int RAND_priv_bytes(unsigned char *buf, int num);
    
  • 使用方法与 RAND_bytes 一致。

3. RAND_seedRAND_add
  • 作用:为随机数生成器添加种子值或熵,增强其随机性。
    OpenSSL 的随机数生成器依赖熵池,通常会自动初始化,但可以通过这些函数手动添加种子数据。

  • 函数原型

    void RAND_seed(const void *buf, int num);
    void RAND_add(const void *buf, int num, double entropy);
    
    • buf:种子数据。
    • num:种子数据的字节数。
    • entropy:种子中估计的熵(单位是比特,范围 0 到 8*num)。
  • 示例

    unsigned char seed_data[] = {0x12, 0x34, 0x56, 0x78};
    RAND_seed(seed_data, sizeof(seed_data));
    

4. RAND_status
  • 作用:检查随机数生成器是否被正确初始化。

  • 函数原型

    int RAND_status(void);
    
    • 返回值
      • 如果熵池已初始化且可用随机性足够,返回 1
      • 否则返回 0
  • 示例

    if (RAND_status() == 1) {
        printf("随机数生成器已初始化!\n");
    } else {
        printf("随机数生成器未初始化!\n");
    }
    

随机数生成器的熵池

OpenSSL 的随机数生成器使用熵池作为随机性的来源,依赖于系统提供的随机性(如 /dev/random/dev/urandom)。在大多数情况下,OpenSSL 会自动处理熵池的初始化,但开发者可以通过 RAND_seedRAND_add 提供额外的种子数据。


常见用例

  1. 生成随机密钥

    unsigned char key[32]; // 256 位密钥
    if (RAND_bytes(key, sizeof(key)) == 1) {
        printf("密钥生成成功!\n");
    }
    
  2. 生成随机初始化向量 (IV)

    unsigned char iv[16]; // 128 位 IV
    if (RAND_bytes(iv, sizeof(iv)) == 1) {
        printf("IV 生成成功!\n");
    }
    
  3. 增强随机数生成器熵

    unsigned char extra_entropy[] = {0xde, 0xad, 0xbe, 0xef};
    RAND_add(extra_entropy, sizeof(extra_entropy), 4.0); // 添加 4 比特熵
    

注意事项

  1. 使用 RAND_bytesRAND_priv_bytes

    • 推荐使用这两个函数生成随机数,因为它们提供加密级别的安全性。
    • 不建议使用 RAND_pseudo_bytes,因为它已被弃用。
  2. 熵的重要性

    • 高质量的熵是随机数生成的核心。如果熵不足,生成的随机数可能会被预测,降低安全性。
  3. 平台依赖

    • OpenSSL 的随机数生成器在不同平台上依赖系统的熵源,例如 /dev/urandom 或 Windows 的 CryptGenRandom。

OpenSSL 的随机数生成函数设计灵活,满足了从简单随机需求到高安全性应用的各种场景。如果需要更高安全性的随机数生成,推荐使用 RAND_priv_bytes

二、使用哈希算法生成随机的密钥

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/rand.h>
#include <openssl/evp.h>

#define SEED_LENGTH 32  // 随机种子长度(32 字节 = 256 位)
#define KEY_LENGTH 32   // 密钥长度(32 字节 = 256 位)

// 使用随机种子和哈希算法生成密钥
void generate_hashed_key(unsigned char *key, size_t key_length) {
    unsigned char seed[SEED_LENGTH]; // 随机种子

    // 生成随机种子
    if (!RAND_bytes(seed, sizeof(seed))) {
        fprintf(stderr, "随机种子生成失败!\n");
        exit(EXIT_FAILURE);
    }

    // 打印随机种子(调试用)
    printf("随机种子: ");
    for (size_t i = 0; i < sizeof(seed); i++) {
        printf("%02x", seed[i]);
    }
    printf("\n");

    // 使用 SHA-256 哈希函数对种子进行散列
    EVP_MD_CTX *mdctx = EVP_MD_CTX_new(); // 创建哈希上下文
    if (!mdctx) {
        fprintf(stderr, "创建哈希上下文失败!\n");
        exit(EXIT_FAILURE);
    }

    // 初始化哈希计算(使用 SHA-256)
    if (EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL) != 1) {
        fprintf(stderr, "哈希初始化失败!\n");
        EVP_MD_CTX_free(mdctx);
        exit(EXIT_FAILURE);
    }

    // 提供数据进行哈希计算
    if (EVP_DigestUpdate(mdctx, seed, sizeof(seed)) != 1) {
        fprintf(stderr, "哈希更新失败!\n");
        EVP_MD_CTX_free(mdctx);
        exit(EXIT_FAILURE);
    }

    // 获取哈希结果
    unsigned char hash[EVP_MAX_MD_SIZE];
    unsigned int hash_len;
    if (EVP_DigestFinal_ex(mdctx, hash, &hash_len) != 1) {
        fprintf(stderr, "哈希计算失败!\n");
        EVP_MD_CTX_free(mdctx);
        exit(EXIT_FAILURE);
    }

    // 释放哈希上下文
    EVP_MD_CTX_free(mdctx);

    // 取哈希结果的前 key_length 字节作为密钥
    if (key_length > hash_len) {
        fprintf(stderr, "密钥长度超出哈希值长度!\n");
        exit(EXIT_FAILURE);
    }
    memcpy(key, hash, key_length);

    // 打印生成的密钥(调试用)
    printf("生成的密钥: ");
    for (size_t i = 0; i < key_length; i++) {
        printf("%02x", key[i]);
    }
    printf("\n");
}

int main() {
    unsigned char key[KEY_LENGTH]; // 存储生成的密钥

    // 调用密钥生成函数
    generate_hashed_key(key, KEY_LENGTH);

    return 0;
}

运行两次的结果:

这里可以看到每次运行后生成的密钥都是不一样的,这样就保证了密钥的不一致性。
在这里插入图片描述