参考链接: 🅰 aardio 文档 - .NET 调用指南 📄 BouncyCastle 文档增强检索
本文档 根据 BouncyCastle 用户手册 由 AI 自动翻译为 aardio 版 本,适用 aardio
v40.7以上版本,以及 aardio 扩展库 BouncyCastlev2.6.1以上版本。
开源组件 Bouncy Castle 是基于 .NET 的加密算法与协议实现库,不仅提供常用基础加密算法,还支持 CMS、OpenPGP、(D)TLS、TSP、X.509 证书生成等功能。此外,它还实现了美国国家标准与技术研究院(NIST)的后量子密码学标准化算法,如ML - DSA、ML - KEM、SLH - DSA、Falcon、经典McEliece、FrodoKEM、NTRU、NTRU Prime、Picnic、Saber 和 BIKE。
Bouncy Castle 仅需要系统自带的 NET .NET 4.6.1( Win10 1709 就已经自带,这基本是目前主流 .NET 程序的最低要求,即使更老的操作系统也都已普及安装了 )。
aardio 提供了 BouncyCastle 扩展库,实际上这个扩展库的源代码只有几句代码,主要是添加了内存加载 BouncyCastle.Cryptography.dll 的代码,以实现生成无依赖的独立 EXE 文件。其他 BouncyCastle 的 .NET 接口在 aardio 里可以直接使用,不需要再额外封装。
工具 » 扩展库 搜索并勾选 BouncyCastle 扩展库,安装 / 更新 按钮。✅ 在 aardio 中直接运行包含
import BouncyCastle语句的代码也会自动安装扩展库。
import BouncyCastle 语句会导入 .NET 的 BouncyCastle 名字空间。
要特别注意 aardio 的 import 语句与 C# 的 using 语句存在区别:
import 只会引入名字空间,但并不会污染现有名字空间。aardio 中访问 .NET 对象要写完整名字空间,示例:
import BouncyCastle;
var sha3 = BouncyCastle.Crypto.Digests.Sha3Digest(256);
aardio 不能像 C# 那样用 Sha3Digest 代替 BouncyCastle.Crypto.Digests.Sha3Digest, 必须指定完整的名字空间。
但是在 aardio 里名字空间或者类都可以通过赋值语句指定更短的名称,例如:
//用局部变量指向名字空间
var Sha3Digest = BouncyCastle.Crypto.Digests.Sha3Digest;
//使用更短的名字直接访问对象
var sha3 = Sha3Digest(256);
注意在 aardio 中构造类的实例不需要使用 new 关键字。
在密码学领域,随机数至关重要。随机数有许多应用场景,例如为对称密码生成密钥、帮助为不对称算法生成大数(通常是素数),以及在加密算法中引入 nonce¹ 以防止(或减少)所谓的重放²攻击。
¹ nonce( Number once ) 是指定范围内的随机整数或伪随机整数。
² 重放攻击( Replay Attacks) 简单来说,就是当攻击者截获加密消息/数据并在稍后重新发送该消息/数据时发生的攻击。
当提到随机数时,至少有以下三种含义:
TRNG(真随机数生成器)- 这些系统生成的数字(或比特串)来自物理随机源,如热/电压耗散噪声、放射性衰变噪声或大气噪声(参见 http://www.random.org)等许多随机物理过程。如果您的硬件支持 TRNG,则可以从 aardio 代码中访问它。
PRNG(伪随机数生成器,也称为 DRBG,确定性随机比特生成器)- 这些是数学算法,通常使用称为种子值的整数初始化函数来生成数字。这些数字本质上不是真正的随机数,因为可以生成的此类值的数量是有限的 - 最终数字序列将重复。(与此形成对比的是像大气噪声 TRNG 这样的东西,它可以近似为连续的值集。因此,在实际应用中,使用 TRNG 我们可以生成无限数量的不同值。)
CSPRNG(加密安全伪随机数生成器)- 这些同样使用数学算法生成随机比特串。PRNG 和 CSPRNG 之间的区别在于后者必须能够抵抗加密攻击。
在 Bouncy Castle .NET 加密程序集中,可以使用上述所有三种方式。.NET 直接支持线性同余算法的修改版本,可用作 PRNG。我们在下面的示例中使用它,因为我们希望在测试期间获得一致的密钥和密文。
aardio 提供了基于 PRNG 的 math.random(), 而生成随机字符串的 string.random() 函数同样基于 math.random() 生成的随机数。需要注意的是所有 aardio 线程启动时都会单独生成一个加密安全的随机数作为 math.random(), string.random() 函数的随机数种子,以避免多线程并发时默认可能生成相同的随机数序列的问题。也可以在运行时手动调用 math.randomize( seedNumber ) 重新设置 math.random() 的随机数种子。aardio 标准库的 crypt.random 则提供了基于系统熵源(System Entropy Source)的加密钱数随机数生成器(CSPRNG)。请参考:aardio 随机数与随机字符串
PRNG:
//设置固定的随机数种子
math.randomize(151) //除了测试目的,最好不要指定固定的随机数种子
//生成固定系列的伪随机数
for(i=1;10;1){
print( math.random(1,0xFFFFFFFF) );
}
CSPRNG:
import crypt.random;
//创建随机数生成器
var rng = crypt.random();
//生成 5 个字节的随机 buffer
var buf = rng.buffer(5);
//生成 1 到 9 范围的随机整数
var n = rng.integer(1,9);
//生成 0 到 1 之间的随机小数
var num = rng.number();
import BouncyCastle;
import console;
// 设置固定随机种子
var fixedRandomSeed = 151;
var fixedRandom = System.Random(fixedRandomSeed);
// 生成 32 字节随机数
var bytes = dotNet.buffer(32);
fixedRandom.NextBytes(bytes);
var number = raw.convert(bytes.Value,{INT num}).num;
console.log("固定种子随机数:", number);
console.pause();
上面的代码将为您提供一组一致的"随机"数字,用于测试。执行上述代码两次将生成相同的字节数组。
请注意,.NET 还在 System.Security.Cryptography.RandomNumberGenerator 类中提供了加密安全的 PRNG。BC API 也提供了 PRNG 和 CSPRNG,如下例所示。
import BouncyCastle;
import console;
// 创建默认安全随机数生成器
var defaultSecureRandom = BouncyCastle.Security.SecureRandom();
// 生成32字节随机数
var bytes = dotNet.buffer(32);
defaultSecureRandom.NextBytes(bytes);
//安全随机数
console.hex(bytes.Value);
console.pause();
默认的 SecureRandom 基于 SHA256 摘要算法。种子值通过 .NET 内部类 System.Security.Cryptography.RandomNumberGenerator 提供。执行上述代码两次显示生成的字节集是不同的。如上例生成的 SecureRandom 在加密上是安全的,在大多数加密情况下已经足够。然而,BC API 还提供了几种 NIST SP.800-90A 推荐的方法来生成加密安全的随机数。
NIST 文档推荐基于以下内容的 DRBG:
下面的示例展示了基于 HMAC 的 SecureRandom 对象的生成。
import BouncyCastle;
import console;
// 创建SHA256摘要
var digest = BouncyCastle.Crypto.Digests.Sha256Digest();
// 创建HMAC随机数生成器构建器
var hMacSecureRandomBuilder = BouncyCastle.Crypto.Prng.SP800SecureRandomBuilder(
BouncyCastle.Security.SecureRandom(),
false
);
// 设置个性化字符串
hMacSecureRandomBuilder.SetPersonalizationString(raw.buffer("aardio-app"));
// 创建HMAC摘要
var hmac = BouncyCastle.Crypto.Macs.HMac(digest);
// 构建随机数生成器
var hmacSecureRandom = hMacSecureRandomBuilder.BuildHMac(
hmac,
null, // 不使用nonce
false
);
// 生成 32 字节随机数
var bytes = dotNet.buffer(32);
hmacSecureRandom.NextBytes(bytes);
console.log("HMAC 安全随机数:", string.hex(bytes.Value));
console.pause();