Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >写给开发人员的实用密码学 - 随机数

写给开发人员的实用密码学 - 随机数

作者头像
云水木石
发布于 2021-01-12 03:11:59
发布于 2021-01-12 03:11:59
2K0
举报

上一篇文章中介绍了消息验证码,这篇文章咱们来聊聊随机数。随机数看起来是一个很简单的概念,不论哪种编程语言都提供了简单的生成随机数的方法,有必要单独写一篇文章么?

随机数看起来简单,但在密码学中的用途非常大。比如用于加解密的密钥本质上就是一个随机数,密码学算法内部也会用到随机数。从开发者直观的角度看,随机数就是一串杂乱无序的字母、数字、符号组合,但如何生成随机数很重要,也就是说如何正确使用随机数生成算法非常重要。

反映二战期间历史的谍战片中,经常有破译密电的情节。一种常用的手段就是截获密报,从众多密报中找出规律,从而破解密码。这种破解方式在现代计算机面前太容易了。首先,因为信息技术的广泛使用,密文的收集非常容易,其次,计算机运算速度快,遍历、迭代都非常容易做到。所以现代密码学的首要要求是不可预测,这也是随机数为什么如此重要。比如加密密钥,应该是其他任何人都不能生成,或者以相同的密钥生成方式生成。

下面讨论计算机科学中的随机数及其在密码学中的作用,以及伪随机数生成器(Preudo Random Number Generator,PRNG)、密码学伪随机生成器(Cryptography secure Preudo Random Number Generator,CSPRNG)以及开发人员应如何生成和使用随机数的一些准则。

伪随机数生成器(PRNG)

PRNG是从某个初始熵(种子)开始,并通过某种计算来计算下一个随机数的函数,而这些计算在不知道种子的情况下是无法预测的。这种计算称为伪随机函数。

伪随机函数内部会维护一个状态(internal state)。首先,通过初始种子初始化状态。当生成下一个随机数时,它是从内部状态(使用某种计算或公式)计算出来的,然后更改伪随机函数的内部状态(使用某种计算或公式)。当生成下一个随机数时,将再次根据函数的内部状态进行计算,并再次更改此状态,依此类推。以最简单的形式可以执行以下过程:

伪随机数生成

如果每次熵(或种子)是一样的,生成的随机数也是相同的,所以熵(或种子)对于随机数生成器非常重要。

好的随机数生成器应该是快速的,并且应该具有统计随机性(请参阅Diehard测试),即在一段时间内所有数字的生成机会均应相同。而CSPRNG有更高的要求,还要求不可预测性和不可重现性。所谓不可重现性(unrepeat)就是不管经过多长时间,不会产生完全相同的随机数。当然,在软件层面不可能生成完全不一样的随机数,在一定周期内,密码学随机数算法最终会生成两个完全相同的随机数,只是周期长短的问题,在密码学中应该尽量使用周期相对长的随机数。

初始熵(种子)

为了安全起见,PRNG应该从真正随机的初始种子开始,这绝对是不可预测的。如果种子是可预测的,它将生成可预测的随机数序列,并且整个随机生成过程将是不安全的。这就是为什么在开始时拥有不可预测的随机性(安全种子)非常重要的原因。

如何以安全的方式初始化伪随机生成器?答案很简单:收集随机性(熵)。

在计算机科学中,“熵”是指不可预测的随机性,通常以位为单位进行度量。例如,如果您移动计算机的鼠标,它将生成一些难以预测的事件,例如鼠标光标的开始位置和结束位置。如果我们假设鼠标在 [0 ... 255] 像素范围内更改了位置,则从此鼠标移动收集的熵应约为8位(因为2 ^ 8 = 255)。另一个示例:如果要求用户考虑一个[0 ... 1000]范围内的数字,则该数字将会是大约 9-10 位的熵(因为 2 ^ 10 = 1024)。为了收集256位的熵(例如安全地生成256位的整数),您将需要考虑一系列此类事件的序列(例如用户的鼠标移动和键盘输入)。

收集熵

我们可以从计算机中许多难以预测的事件中收集熵:键盘点击、鼠标移动、网络活动、相机、麦克风输入等,以及它们发生的时间。初始随机性的收集通常是由操作系统(OS)在内部执行的,操作系统提供了标准 API 来访问它(例如,从 Linux 中的 /dev/random 文件读取)。

应用软件也可以通过要求用户移动鼠标、在键盘上键入内容、在麦克风上说某些内容或在相机前面移动一会儿来明确地收集熵。一个很好的例子是bitaddress.org钱包应用程序,该应用程序将鼠标移动与键盘事件结合在一起以收集熵:

收集熵

另外一个例子就是 openssl 命令行工具,如果生成密钥,会让您敲击键盘,且要敲一定数量的按键,然后才会生成密钥。

CSPRNG(密码学安全随机数生成器)

根据定义,CSPRNG是一种伪随机数发生器(PRNG),要使PRNG成为CSPRNG,有两个主要要求:

  • 满足下一个比特测试:如果某人从 PRNG 开始就知道所有k个比特,那么他将无法使用合理的计算资源来预测 k + 1个比特。
  • 抗恶意播种:即便某一攻击能获得一段时间上对CSPRNG的输入的完全或部分控制,要预测或再现来自CSPRNG的任何随机输出仍然是不可行的。

操作系统中的熵通常数量有限,并且等待更多的熵是缓慢且不切实际的。大多数密码应用程序使用CSPRNG,CSPRNG会将来自操作系统的可用熵“扩展”到更多位,这是加密目的所必需的,并且符合上述CSPRNG要求。

大多数CSPRNG结合使用来自操作系统和高质量PRNG生成器的熵,它们经常“重置”,这意味着当新的熵来自操作系统时(例如,来自用户输入、系统中断、磁盘 I/O 或硬件随机产生),基础 PRNG 根据即将到来的新熵位来更改其内部状态。随着时间的推移,这种不断的播种使CSPRNG变得非常难以预测和分析。

通常,现代 OS CSPRNG API 将来自环境的不断收集的熵与其内置伪随机算法的内部状态结合起来,并进行连续重新播种,以确保生成的随机性具有最大的不可预测性,同时具有高速和无阻塞行为。

硬件随机发生器

硬件随机发生器,称为真随机数发生器(True Random Number Generator,TRNG),通常捕获物理过程或现象,例如光的可见光谱、环境的热噪声、大气噪声等。物理环境的随机性是通过专门的传感器收集,然后由设备进行放大和处理,最后通过USB、PCI Express或其他标准接口传输到计算机。

现代微处理器(CPU)提供了内置的硬件随机发生器,可通过特殊的CPU指令 RdRand 访问该发生器,该指令将随机整数返回到CPU寄存器之一。

如今,大多数加密应用程序都不需要硬件随机数生成器,因为操作系统中的熵对于常规加密目的而言足够安全。对于具有较高安全性要求的系统(例如银行和金融应用程序、证书颁发机构和大额付款处理等),需要使用TRNG。

开发人员如何正确使用CSPRNG?

通常,开发人员通过加密库访问其操作系统的密码学随机数生成器(CSPRNG)。

  • 在 Linux 和 macOS 中,可以认为 /dev/random 和 /dev/urandom 随机性源对于大多数加密目的而言都是足够安全的,并且大多数加密库都在内部访问它们。
  • Windows 中,可以使用来自下一代(CNG)的Crypto API或更高级的密码库中的 BCryptGenRandom 函数安全地生成用于加密目的的随机数。
  • 在 C# 中,使用 .NET Framework 或 .NET Core 中的 System.Security.Cryptography.RandomNumberGenerator.Create()。
  • Python 中,请使用 os.urandom() 或 secrets 库。
  • Java中,请使用 java.security.SecureRandom 系统类。
  • 在 JavaScript 中,将 window.crypto.getRandomValues(Uint8Array) 用于客户端(在Web浏览器中)或 crypto.randomBytes() 用于服务器端(在Node.js中)。

切勿将 Math.random() 或类似的不安全RNG函数用于加密目的!

小结

看到上面的介绍,是否有些晕。其实在开发中我们并不需要理解随机数是如何生成的,但我们需要时刻牢记在心的是,随机数生成非常重要,一定要使用安全的API生成安全的随机数。在大多数情况下,我们只需要掌握系统提供了哪些安全的随机数生成API,知道如何使用即可。

密码学应用中很多场景会涉及随机数,不同的用途有不同的称呼,比如密钥、初始化向量(IV)、nonce、盐(salt)等,目前可以不用关心这些概念,后续用到会进行讲解。

在下一篇文章中,我们将介绍密码学中的对称加密算法,敬请关注!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-01-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云水木石 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
022_Web3.0私钥生成最佳实践与熵源安全:从硬件RNG到量子时代的密码学保障
在Web3.0生态系统中,私钥是用户资产安全的根本保障。一个私钥对应一个唯一的数字身份,拥有私钥就意味着拥有对应地址上的所有数字资产控制权。因此,私钥生成过程的安全性直接关系到整个Web3安全体系的基石。
安全风信子
2025/11/16
260
Python随机数函数全解析:5个核心工具的实战指南
随机数在编程中无处不在,从游戏开发到机器学习,从密码学到统计模拟。Python标准库中的random模块提供了强大的随机数生成工具,但很多开发者只停留在random.random()的基础认知。本文将深入解析5个最实用的随机数函数,通过实际案例展示它们的威力,并揭示底层原理与最佳实践。
富贵软件
2025/09/09
4510
在以太坊生成随机数的几种方式(含代码)
随机数都是由随机数生成器(Random Number Generator)生成的。随机数分为”真随机数“和”伪随机数“两种。
Tiny熊
2020/06/05
3K0
在以太坊生成随机数的几种方式(含代码)
安卓应用安全指南 5.6.3 密码学 高级话题
在上面的示例代码中,我们展示了三种加密方法的实现示例,每种加密方法用于加密解密以及数据伪造的检测。 你可以使用“图 5.6-1”,“图 5.6-2”,根据你的应用粗略选择使用哪种加密方法。 另一方面,加密方法的更加精细的选择,需要更详细地比较各种方法的特征。 在下面我们考虑一些这样的比较。
ApacheCN_飞龙
2022/12/01
1K0
为什么不使用 Math.random() ?!
当程序在需要不可预测性的上下文中生成可预测的值时,攻击者可能会猜测将要生成的下一个值,并使用该猜测来冒充另一个用户或访问敏感信息。
888888888
2022/01/24
1.8K0
math/rand和crypto/rand对比
在 Go 语言中,math/rand 和 crypto/rand 都是用于生成随机数的包,但它们的用途和特性有显著的不同。
孟斯特
2024/08/16
4220
math/rand和crypto/rand对比
使用 SecureRandom 产生随机数采坑记录
我们的项目工程里经常在每个函数需要用到 Random 的地方定义一下 Random 变量(如下)
kunge
2019/12/23
4.8K0
使用 SecureRandom 产生随机数采坑记录
严重的随机数生成器漏洞披露,数十亿IoT设备受影响
研究人员披露了数十亿物联网(IoT)设备中使用的随机数生成器严重漏洞,这意味着大量用户面临潜在攻击风险。
FB客服
2021/08/24
8970
Java 生成随机数的 5 种方式,你知道几种?
产生的随机数是 0 - 1 之间的一个 double,即 0 <= random <= 1。
Java技术栈
2020/12/08
20.4K0
Java 生成随机数的 5 种方式,你知道几种?
写给开发人员的实用密码学 - MAC
这里的MAC,并不是计算机中的MAC地址,而是消息验证码(Message Authentication Code,MAC)。在写给开发人员的实用密码学 - Hash算法中讲到的Hash算法能够进行完整性校验,但却不能避免消息被篡改,而MAC正是为了避免消息被篡改而设计。
云水木石
2020/12/29
1.2K0
写给开发人员的实用密码学 - MAC
抽奖摇号系统随机性算法介绍
本文分析GO语言包中的"crypto/rand"和"math/rand",芯链HPB系统的区块链随机数,并给出了权衡效率和随机性,并给出了一款区块链摇号抽奖系统如何实现随机数的算法和流程。
辉哥
2020/10/26
2.5K0
抽奖摇号系统随机性算法介绍
java 随机数生成器Random、ThreadLocalRandom、SecureRandom
Random 是最常用的类,ThreadLocalRandom 性能快,SecureRandom 注重安全。 下面简单分析3个类的使用。
潇洒
2023/10/20
1.7K0
FPGA项目开发:基于FPGA的伪随机数发生器(附代码)
今天是画师和各位大侠见面了,执笔绘画FPGA江湖,本人写了篇关于FPGA的伪随机数发生器学习笔记,这里分享给大家,仅供参考。
FPGA技术江湖
2021/04/16
1.3K0
FPGA项目开发:基于FPGA的伪随机数发生器(附代码)
读《图解密码技术》(三):密钥、随机数和应用技术
最后一篇了,如果还没看过前两篇的,最好先翻回去看看,因为这最后一篇的内容是建立在前两篇的基础之上的。本篇的内容包括密钥、随机数、PGP、SSL/TLS,最后再讲讲密码技术的现状和局限性,以及简单介绍一下量子密码和量子计算机。
Keegan小钢
2018/08/10
2.3K0
人类对随机数的探索:如何才能生成一个均匀的随机数列
大数据文摘作品,转载要求见文末 作者 | Carl Tashian 编译 | 陈远鹏,Melody 罗马12毫米骰子,PAS(一个英国政府管理下的保护文物志愿者组织)/大英博物馆董事(CC BY-SA 2.0) 统计学家弗朗西斯 · 加尔顿于1890 年《自然》杂志上写道:“作为一个选择随机的工具,我发现没有什么优于骰子。把它们扔进装骰子的盒子中摇动,它们彼此相互冲撞,并与盒壁碰弹,不停的滚动,即使在一次摇骰子中,骰子的最初朝向也无法为其最终的朝向提供任何有用的线索。” 我们如何才能生成一个均匀的随机数序列
大数据文摘
2018/05/25
2.1K0
区块链核心技术-密码学
大家好,首先感谢腾讯云提供云社区这样一个让技术人员沟通交流的平台,其次很高兴入驻到云+社区认识到大家,我是腾讯云TVP一员,专注于云计算、区块链、Web架构方向,myPagination作者,Github也开源了很多区块链的项目:https://github.com/linapex,有需要的朋友可以下载学习,本文是区块链技术实战系列的第二篇(不定期更新):
linapex
2019/03/22
12.1K0
区块链核心技术-密码学
生成安全的随机数
Math.random()产生的随机数是在0 到1之间的一个double类型的随机数,即 0 <= random <= 1
BUG弄潮儿
2020/06/12
2.9K0
生成安全的随机数
写给开发人员的实用密码学 - Hash算法
说到Hash(哈希),开发人员应该不陌生,比如Hash表是一种非常常用的数据结构,通过Hash表能够根据键值快速找到数据。哈希函数将文本(或其他数据)映射为整数,从而能够提高检索效率。
云水木石
2020/12/29
2.5K0
写给开发人员的实用密码学 - Hash算法
【网络安全】网络防护之旅 - 对称密码加密算法的实现
网络安全是一门关注计算机系统和网络安全的专业学科。其首要任务是维护信息系统的核心价值,包括机密性、完整性和可用性,以对抗未经授权的访问、破坏、篡改或泄露的威胁。
SarPro
2024/02/20
4630
【网络安全】网络防护之旅 - 对称密码加密算法的实现
【Java】深入理解Java随机数
java.lang.Math 类里有一个私有静态内部类,内有一个静态的 java.util.Random 类对象,调用其 nextDouble() 方法,生成 [0.0, 1.0) 范围内的伪随机浮点数。
全栈程序员站长
2022/09/17
1.4K0
推荐阅读
相关推荐
022_Web3.0私钥生成最佳实践与熵源安全:从硬件RNG到量子时代的密码学保障
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
首页
学习
活动
专区
圈层
工具
MCP广场
首页
学习
活动
专区
圈层
工具
MCP广场