文章目录
- 一、openssl中随机数函数
-
-
- [**OpenSSL 随机数函数概览**](#OpenSSL 随机数函数概览)
-
- [1. **核心随机数函数**](#1. 核心随机数函数)
- **常用函数详解**
-
- [1. `RAND_bytes`](#1.
RAND_bytes
) - [2. `RAND_priv_bytes`](#2.
RAND_priv_bytes
) - [3. `RAND_seed` 和 `RAND_add`](#3.
RAND_seed
和RAND_add
) - [4. `RAND_status`](#4.
RAND_status
)
- [1. `RAND_bytes`](#1.
- **随机数生成器的熵池**
- **常见用例**
- **注意事项**
-
- 二、使用哈希算法生成随机的密钥
一、openssl中随机数函数
OpenSSL 提供了一套功能强大的随机数生成函数,用于生成高质量的伪随机数。随机数在密码学中至关重要,广泛用于密钥生成、盐值生成、初始化向量 (IV) 等安全操作。
OpenSSL 随机数函数概览
1. 核心随机数函数
函数名称 | 描述 |
---|---|
RAND_bytes |
生成高质量的伪随机字节。 |
RAND_priv_bytes |
生成高质量伪随机字节,推荐用于对安全性要求更高的密钥生成。 |
RAND_pseudo_bytes |
生成伪随机字节(不保证是加密级别安全,已被弃用)。 |
RAND_seed |
手动为伪随机数生成器添加种子值。 |
RAND_add |
添加额外的熵(种子数据)到伪随机数生成器的池中。 |
RAND_status |
检查随机数生成器是否被正确初始化。 |
RAND_poll |
自动收集熵以初始化随机数生成器(由内部调用)。 |
常用函数详解
1. RAND_bytes
-
作用:生成高质量的加密级别伪随机字节。
-
函数原型:
cint RAND_bytes(unsigned char *buf, int num);
buf
:指向用于存储随机字节的缓冲区。num
:要生成的随机字节数。- 返回值 :
- 成功返回
1
。 - 如果随机数生成器未正确初始化,返回
0
。
- 成功返回
-
示例:
cunsigned 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
类似,但专为高安全性应用设计(如密钥生成)。可能在实现中增加额外的保护。 -
函数原型 :
cint RAND_priv_bytes(unsigned char *buf, int num);
-
使用方法与
RAND_bytes
一致。
3. RAND_seed
和 RAND_add
-
作用 :为随机数生成器添加种子值或熵,增强其随机性。
OpenSSL 的随机数生成器依赖熵池,通常会自动初始化,但可以通过这些函数手动添加种子数据。
-
函数原型:
cvoid RAND_seed(const void *buf, int num); void RAND_add(const void *buf, int num, double entropy);
buf
:种子数据。num
:种子数据的字节数。entropy
:种子中估计的熵(单位是比特,范围 0 到 8*num)。
-
示例:
cunsigned char seed_data[] = {0x12, 0x34, 0x56, 0x78}; RAND_seed(seed_data, sizeof(seed_data));
4. RAND_status
-
作用:检查随机数生成器是否被正确初始化。
-
函数原型:
cint RAND_status(void);
- 返回值 :
- 如果熵池已初始化且可用随机性足够,返回
1
。 - 否则返回
0
。
- 如果熵池已初始化且可用随机性足够,返回
- 返回值 :
-
示例:
cif (RAND_status() == 1) { printf("随机数生成器已初始化!\n"); } else { printf("随机数生成器未初始化!\n"); }
随机数生成器的熵池
OpenSSL 的随机数生成器使用熵池作为随机性的来源,依赖于系统提供的随机性(如 /dev/random
或 /dev/urandom
)。在大多数情况下,OpenSSL 会自动处理熵池的初始化,但开发者可以通过 RAND_seed
或 RAND_add
提供额外的种子数据。
常见用例
-
生成随机密钥:
cunsigned char key[32]; // 256 位密钥 if (RAND_bytes(key, sizeof(key)) == 1) { printf("密钥生成成功!\n"); }
-
生成随机初始化向量 (IV):
cunsigned char iv[16]; // 128 位 IV if (RAND_bytes(iv, sizeof(iv)) == 1) { printf("IV 生成成功!\n"); }
-
增强随机数生成器熵:
cunsigned char extra_entropy[] = {0xde, 0xad, 0xbe, 0xef}; RAND_add(extra_entropy, sizeof(extra_entropy), 4.0); // 添加 4 比特熵
注意事项
-
使用
RAND_bytes
或RAND_priv_bytes
- 推荐使用这两个函数生成随机数,因为它们提供加密级别的安全性。
- 不建议使用
RAND_pseudo_bytes
,因为它已被弃用。
-
熵的重要性
- 高质量的熵是随机数生成的核心。如果熵不足,生成的随机数可能会被预测,降低安全性。
-
平台依赖
- OpenSSL 的随机数生成器在不同平台上依赖系统的熵源,例如
/dev/urandom
或 Windows 的 CryptGenRandom。
- OpenSSL 的随机数生成器在不同平台上依赖系统的熵源,例如
OpenSSL 的随机数生成函数设计灵活,满足了从简单随机需求到高安全性应用的各种场景。如果需要更高安全性的随机数生成,推荐使用 RAND_priv_bytes
。
二、使用哈希算法生成随机的密钥
c
#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;
}
运行两次的结果:
这里可以看到每次运行后生成的密钥都是不一样的,这样就保证了密钥的不一致性。