你还在用rand()生成随机数?

news2025/1/3 4:01:28
1. rand() 的缺陷

伪随机数生成器使用数学算法来产生具有良好统计特性的数字序列,但这些数字并非真正随机。

C 标准库中的 rand() 函数并不保证所生成的随机序列的质量。某些 rand() 实现生成的数字周期较短,且这些数字是可以预测的。对于有强伪随机数要求的应用程序,必须使用已知能满足其需求的生成器。

#include <stdio.h>
#include <stdlib.h>
  
enum { len = 12 };
  
void func(void) {
  /*
   * id will hold the ID, starting with the characters
   *  "ID" followed by a random integer.
   */
  char id[len]; 
  int r;
  int num;
  /* ... */
  r = rand();  /* Generate a random integer */
  num = snprintf(id, len, "ID%-d", r);  /* Generate the ID */
  /* ... */
}

rand()自身的局限性

  • 有限范围rand() 函数返回的整数值在 0RAND_MAX 之间,而 RAND_MAX 至少为 32767(即 2^15 - 1)。对于某些应用来说,这个范围可能太小。
  • 低质量随机性rand() 的实现通常基于线性同余生成器(LCG),它提供的随机序列的质量较差,特别是低位上的周期性较强,容易被预测。
  • 缺乏可移植性:不同平台上 rand() 的具体实现和特性可能有所不同,这会影响程序行为的一致性。
  • 种子问题:如果使用相同的种子(通过 srand() 设置),rand() 将总是产生相同的序列。这虽然可以用于调试,但在需要真正随机性的场合是一个隐患。
#include <stdio.h>
#include <stdlib.h> // 包含 rand() 和 srand()
#include <time.h>   // 包含 time()

void print_random_sequence(int seed, int count) {
    printf("Generating random sequence with seed %d:\n", seed);
    srand(seed); // 使用给定的种子初始化随机数生成器
    for (int i = 0; i < count; ++i) {
        printf("%d ", rand() % 100); // 打印 0 到 99 之间的随机数
    }
    printf("\n");
}

int main() {
    int seed = 12345; // 设定一个固定的种子
    int count = 10;   // 每次打印的随机数个数

    // 第一次生成随机序列
    print_random_sequence(seed, count);

    // 第二次生成同样的随机序列
    print_random_sequence(seed, count);

    return 0;
}

运行结果:

Generating random sequence with seed 250:
22 69 7 43 87 96 63 22 73 1 
Generating random sequence with seed 250:
22 69 7 43 87 96 63 22 73 1 

安全问题:

  • 加密安全性不足rand() 不适合用于生成加密密钥或其它对安全性要求高的随机数据。因为它的输出是可以被预测的,攻击者可以通过观察部分输出推断出后续值。
  • 不可控的种子来源:默认情况下,rand() 使用的时间作为种子,但这很容易受到时间攻击,特别是在多线程环境中,多个调用可能会发生在同一秒内,导致相同的种子。
2. 合适的替代方案

为了获得更好的随机性,建议使用以下替代方法之一:

  • C11 标准库:如果你的编译环境支持 C11 或更新的标准,可以使用 <stdlib.h> 中引入的新函数如 rand_r()random(),或者更推荐的是使用 <stdalign.h><random> 库中的设施。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

enum
{
    len = 12
};

void func(void)
{
    /*
     * id will hold the ID, starting with the characters
     *  "ID" followed by a random integer.
     */
    char id[len];
    int r;
    int num;
    /* ... */
    struct timespec ts;
    if (timespec_get(&ts, TIME_UTC) == 0)
    {
        /* Handle error */
    }
    srandom(ts.tv_nsec ^ ts.tv_sec); /* Seed the PRNG */
    /* ... */
    r = random();                        /* Generate a random integer */
    num = snprintf(id, len, "ID%-d", r); /* Generate the ID */
                                         /* ... */
}
  • C++11 及以上版本:在 C++ 中,应该使用 <random> 头文件提供的高级随机数生成工具,例如 std::mt19937(Mersenne Twister)或其他引擎与分布相结合。

  • 操作系统提供的接口:一些操作系统提供了专门的随机数生成API,比如 Linux 上的 /dev/urandom 或 Windows 上的 BCryptGenRandom 等,这些API通常更适合安全需求较高的应用。

#include <iostream>
#include <random>
#include <array>
#include <fstream>

// 如果是在 Windows 上,需要包含以下头文件
#ifdef _WIN32
#include <windows.h>
#include <bcrypt.h>
#pragma comment(lib, "Bcrypt.lib")
#endif

void generate_random_bytes(std::vector<uint8_t>& buffer) {
#if defined(_WIN32)
    // Windows 平台使用 BCryptGenRandom
    NTSTATUS status = BCryptGenRandom(NULL, buffer.data(), static_cast<ULONG>(buffer.size()), BCRYPT_USE_SYSTEM_PREFERRED_RNG);
    if (status != STATUS_SUCCESS) {
        throw std::runtime_error("BCryptGenRandom failed");
    }
#else
    // Linux 和其他 Unix 系统使用 /dev/urandom
    std::ifstream urandom("/dev/urandom", std::ios::binary);
    if (!urandom.is_open()) {
        throw std::runtime_error("Failed to open /dev/urandom");
    }
    urandom.read(reinterpret_cast<char*>(buffer.data()), buffer.size());
    if (!urandom) {
        throw std::runtime_error("Failed to read from /dev/urandom");
    }
#endif
}

int main() {
    try {
        // 定义一个缓冲区来存储随机字节
        std::vector<uint8_t> randomBytes(16); // 例如,16 字节

        // 生成随机字节
        generate_random_bytes(randomBytes);

        // 打印生成的随机字节
        std::cout << "Generated random bytes: ";
        for (uint8_t byte : randomBytes) {
            std::cout << std::hex << static_cast<int>(byte) << ' ';
        }
        std::cout << std::dec << '\n';
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << '\n';
        return 1;
    }

    return 0;
}
3.加密场景随机数生成

加密库在生成随机数时通常依赖于操作系统提供的高质量熵源,或者使用专门设计的密码学安全伪随机数生成器(CSPRNG)。这些方法确保了生成的随机数具有足够的不可预测性和随机性,以满足加密应用的需求。以下是几种常见的做法:

3.1.操作系统提供的熵源

许多现代操作系统都提供了专门用于获取高熵随机数据的接口,这些接口通常被认为是安全的,因为它们从多个难以预测的硬件和软件事件中收集熵。例如:

  • Linux 和 Unix 系统/dev/random/dev/urandom

    • /dev/random 提供阻塞式的访问,只有当有足够的熵时才会返回数据,这保证了最高级别的安全性。
    • /dev/urandom 提供非阻塞式的访问,即使没有足够的熵也会继续返回数据,但它的输出仍然被认为是足够安全的,特别是在系统启动后经过一段时间。
  • WindowsBCryptGenRandom 函数

    • 这个 API 是 Windows CryptoAPI 的一部分,提供了一种简单而安全的方式从操作系统获取随机字节。它内部使用了一个基于 ChaCha20 或 AES-CTR 的 CSPRNG。
3.2.密码学安全伪随机数生成器 (CSPRNG)

CSPRNG 是专门为加密应用设计的伪随机数生成器,它们的特点是即使攻击者知道部分输出或状态,也很难推断出未来的输出。一些常见的 CSPRNG 包括:

  • ChaCha20:一种快速且安全的流密码,也可以用作 CSPRNG。
  • AES-CTR:高级加密标准(AES)算法在计数器模式下的实现,可以作为 CSPRNG 使用。
  • HMAC_DRBG:基于哈希消息认证码(HMAC)的确定性随机位生成器(DRBG),常用于 FIPS 140-2 标准中。
  • Hash_DRBG:基于安全哈希函数(如 SHA-256)的 DRBG。
  • CTR_DRBG:基于对称密钥算法(如 AES)的 DRBG,在计数器模式下运行。
3.3.硬件随机数生成器 (HRNG)

比如可信平台模块(Trusted Platform Module, TPM)

TPM 是一种专门设计用于增强计算机安全性的硬件组件,它提供了一系列的安全功能,其中包括密码学操作、密钥生成和存储等。TPM 内置了硬件随机数生成器(HRNG),这使得它可以生成高质量的随机数,这些随机数对于加密应用来说至关重要。

img

在这里插入图片描述

现在大部分PC或设备都配备有TPM2.0芯片,可以通过TSS库调用TPM生成随机数。

#include <tss2/tss2_sys.h>
#include <iostream>
#include <vector>

void generate_random_bytes_from_tpm(TSS2_SYS_CONTEXT *sysContext, size_t numBytes) {
    std::vector<uint8_t> randomBytes(numBytes);
    TPM2B_DIGEST *outData = reinterpret_cast<TPM2B_DIGEST*>(randomBytes.data());
    outData->size = static_cast<UINT16>(numBytes);

    TSS2_RC rc = Tss2_Sys_GetRandom(sysContext, NULL, numBytes, outData, NULL);
    if (rc != TSS2_RC_SUCCESS) {
        throw std::runtime_error("Failed to get random bytes from TPM");
    }

    std::cout << "Random bytes from TPM: ";
    for (uint8_t byte : randomBytes) {
        std::cout << std::hex << static_cast<int>(byte) << ' ';
    }
    std::cout << std::dec << '\n';
}

int main() {
    // 初始化 TPM 系统上下文和其他必要的设置...
    TSS2_SYS_CONTEXT *sysContext;
    // ... 这里省略了初始化代码 ...

    try {
        generate_random_bytes_from_tpm(sysContext, 16); // 例如,生成 16 字节的随机数
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << '\n';
        return 1;
    }

    // 清理资源...
    // ... 这里省略了清理代码 ...

    return 0;
}
3.4加密库的选择

不同的加密库可能会选择不同的方式来生成随机数,具体取决于其设计目标和应用场景。例如:

  • OpenSSL:默认情况下使用操作系统的熵源(如 /dev/urandomBCryptGenRandom),同时也支持自定义 CSPRNG。

img

  • Libsodium:强烈推荐使用操作系统提供的 CSPRNG,并通过封装好的 API 提供给开发者使用。
  • BoringSSL:Google 开发的 OpenSSL 分支,同样依赖于操作系统提供的 CSPRNG。
  • Botan:一个全面的加密库,提供了多种 CSPRNG 实现,包括 HMAC_DRBG 和 Hash_DRBG。

enRandom`),同时也支持自定义 CSPRNG。

[外链图片转存中…(img-qiYX5YpX-1735569568267)]

  • Libsodium:强烈推荐使用操作系统提供的 CSPRNG,并通过封装好的 API 提供给开发者使用。
  • BoringSSL:Google 开发的 OpenSSL 分支,同样依赖于操作系统提供的 CSPRNG。
  • Botan:一个全面的加密库,提供了多种 CSPRNG 实现,包括 HMAC_DRBG 和 Hash_DRBG。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2268394.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于FPGA的2ASK+帧同步系统verilog开发,包含testbench,高斯信道,误码统计,可设置SNR

目录 1.算法仿真效果 2.算法涉及理论知识概要 2.1 2ASK调制解调 2.2 帧同步 3.Verilog核心程序 4.完整算法代码文件获得 1.算法仿真效果 vivado2019.2仿真结果如下&#xff08;完整代码运行后无水印&#xff09;&#xff1a; 设置SNR8db 设置SNR20db 整体波形效果&…

RT-Thread中堆和栈怎么跟单片机内存相联系

现在RT-ThreadMCU的应用方式越来越普遍&#xff0c;RT-Thread需要配置MCU中的RAM到的系统中&#xff0c;进入系统内存管理&#xff0c;才能提供给基于实时系统的应用程序使用&#xff0c;比如给应用程序提供malloc、free等函数调用功能。在嵌入式软件开发中&#xff0c;我们经常…

2、Bert论文笔记

Bert论文 1、解决的问题2、预训练微调2.1预训练微调概念2.2深度双向2.3基于特征和微调&#xff08;预训练下游策略&#xff09; 3、模型架构4、输入/输出1.输入&#xff1a;2.输出&#xff1a;3.Learned Embeddings(学习嵌入)1. **Token Embedding**2. **Position Embedding**3…

TiDB 的MPP架构概述

MPP架构介绍&#xff1a; 如图&#xff0c;TiDB Server 作为协调者&#xff0c;首先 TiDB Server 会把每个TiFlash 拥有的region 会在TiFlash上做交换&#xff0c;让表连接在一个TiFlash上。另外 TiFlash会作为计算节点&#xff0c;每个TiFlash都负责数据交换&#xff0c;表连接…

3、redis的高可用

主从复制 主从复制&#xff1a;这是redis高可用的基础。哨兵模式和集群都是建立在此基础之上。 主从模式和数据库的主从模式是一样的&#xff0c;主负责写入&#xff0c;然后把写入的数据同步到从&#xff0c;从节点只能读不能写。read only。 不能做高可用的切换&#xff…

【架构-38】如何选择通信协议和数据格式

一、通信协议选择 不同的协议适用于不同的应用场景&#xff0c;关键在于数据传输的需求&#xff0c;如&#xff1a;实时性、带宽、可靠性等。下面是几种常见通信协议的适用场景&#xff1a; WebSocket 适用场景&#xff1a;实时、双向数据传输、低延迟、持久连接 特点&#x…

SpringCloudAlibaba 技术栈—Sentinel

1、什么是sentinel? Sentinel是一个用于微服务架构的流量管理和控制系统&#xff0c;它通过限制和控制进入系统的流量&#xff0c;来保护系统免受过载和故障的影响&#xff0c;确保服务的稳定性。简而言之&#xff0c;它就是一个帮助微服务在高负载情况下也能稳定运行的工具。…

初学STM32 ---高级定时器互补输出带死区控制

互补输出&#xff0c;还带死区控制&#xff0c;什么意思&#xff1f; 带死区控制的互补输出应用之H桥 捕获/比较通道的输出部分&#xff08;通道1至3&#xff09; 死区时间计算 举个栗子&#xff08;F1为例&#xff09;&#xff1a;DTG[7:0]250&#xff0c;250即二进制&#x…

RoboMIND:多体现基准 机器人操纵的智能规范数据

我们介绍了 RoboMIND&#xff0c;这是机器人操纵的多体现智能规范数据的基准&#xff0c;包括 4 个实施例、279 个不同任务和 61 个不同对象类别的 55k 真实世界演示轨迹。 工业机器人企业 埃斯顿自动化 | 埃夫特机器人 | 节卡机器人 | 珞石机器人 | 法奥机器人 | 非夕科技 | C…

Hadoop HA安装配置(容器环境),大数据职业技能竞赛模块A平台搭建,jdk+zookeeper+hadoop HA

HA概述 &#xff08;1&#xff09; 所谓HA&#xff08;High Availablity&#xff09;,即高可用&#xff08;7*24小时不中断服务&#xff09;。 &#xff08;2&#xff09; 实现高可用最关键的策略是消除单点故障&#xff0c;HA严格来说应该分为各个组件的HA机制&#xff0c;H…

国产文本编辑器EverEdit - 如何让输出窗口的日志具有双击跳转到文件指定行的功能

1 开发参考&#xff1a;编写脚本时如何向输出窗口打印可跳转到文件位置的日志 1.1 应用场景 编写脚本时&#xff0c;有时对文本进行分析&#xff0c;需要将提示信息打印到输出窗口&#xff0c;同时希望将文本的行、列信息也打印在日志中&#xff0c; 最好是双击日志信息可以跳…

《云原生安全攻防》-- K8s安全配置:CIS安全基准与kube-bench工具

在本节课程中&#xff0c;我们来了解一下K8s集群的安全配置&#xff0c;通过对CIS安全基准和kube-bench工具的介绍&#xff0c;可以快速发现K8s集群中不符合最佳实践的配置项&#xff0c;及时进行修复&#xff0c;从而来提高集群的安全性。 在这个课程中&#xff0c;我们将学习…

3、redis的集群模式

主从模式 哨兵模式 集群 主从模式&#xff1a;这是redis高可用的基础&#xff0c;哨兵模式和集群都是建立在此基础之上。 主从模式和数据库的主从模式是一样的&#xff0c;主负责写入&#xff0c;然后把写入的数据同步到从&#xff0c; 从节点只能读不能写&#xff0c;rea…

计算机图形学知识点汇总

一、计算机图形学定义与内容 1.图形 图形分为“图”和“形”两部分。 其中&#xff0c;“形”指形体或形状&#xff0c;存在于客观世界和虚拟世界&#xff0c;它的本质是“表示”&#xff1b;而图则是包含几何信息与属性信息的点、线等基本图元构成的画面&#xff0c;用于表达…

自动化测试模型(一)

8.8.1 自动化测试模型概述 在自动化测试运用于测试工作的过程中&#xff0c;测试人员根据不同自动化测试工具、测试框架等所进行的测试活动进行了抽象&#xff0c;总结出线性测试、模块化驱动测试、数据驱动测试和关键字驱动测试这4种自动化测试模型。 线性测试 首先&#…

医疗数仓数据仓库设计

医疗数仓数据仓库设计 数据仓库构建流程数据调研明确数据域构建业务总线矩阵明确统计指标交易主题医生主题用户主题评价主题 维度模型设计汇总模型设计 数据仓库构建流程 数据仓库分层规划 优秀可靠的数仓体系&#xff0c;需要良好的数据分层结构。合理的分层&#xff0c;能够…

Go-知识 注释

Go-知识 注释 行注释块注释包注释结构体&接口注释函数&方法注释废弃注释文档 在 go 语言中注释有两种&#xff0c;行注释和块注释 行注释 使用双斜线 // 开始&#xff0c;一般后面紧跟一个空格。行注释是Go语言中最常见的注释形式&#xff0c;在标准包中&#xff0c;…

1230作业

思维导图 作业 将广播发送和接收端实现一遍&#xff0c;完成一个发送端发送信息&#xff0c;对应多个接收端接收 自实验 //广播发送端 #include <myhead.h> #define G_PORT 8765 #define G_IP "192.168.124.255" int main(int argc, const char *argv[]) {//…

U盘格式化工具合集:6个免费的U盘格式化工具

在日常使用中&#xff0c;U盘可能会因为文件系统不兼容、数据损坏或使用需求发生改变而需要进行格式化。一个合适的格式化工具不仅可以清理存储空间&#xff0c;还能解决部分存储问题。本文为大家精选了6款免费的U盘格式化工具&#xff0c;并详细介绍它们的功能、使用方法、优缺…

Windows系统使用Koodo Reader轻松搭建在线私人图书馆远程看书

文章目录 前言1. Koodo Reader 功能特点1.1 开源免费1.2 支持众多格式1.3 多平台兼容1.4 多端数据备份同步1.5 多功能阅读体验1.6 界面简洁直观 2. Koodo Reader安装流程2.1 安装Git2.2 安装Node.js2.3 下载koodo reader 3. 安装Cpolar内网穿透3.1 配置公网地址3.2 配置固定公网…