Android固定种子生成相同随机数时Bouncy Castle随机生成器选型咨询
Android平台基于Bouncy Castle实现固定种子可复现随机数
Android原生SecureRandom从4.2版本开始,调用setSeed()时仅会将用户传入的种子追加到系统熵池,不会替换原有系统熵,因此无法输出确定的随机序列,这是平台预设的安全设计,无法通过配置修改。
重要提示:下文实现的确定性随机数生成器不具备密码学安全的不可预测性,仅适用于单元测试、可复现仿真、确定性内容生成等场景,禁止用于密钥生成、签名、加密等安全敏感场景。
生成器选型
直接选择Bouncy Castle的DigestRandomGenerator即可,这是BC库中最轻量、行为最可控的确定性生成器:
- 初始化后不会主动读取任何系统熵,所有输出完全由内部状态和传入的种子决定
- 相同种子、相同调用顺序下,跨Android版本、跨设备的输出完全一致
- 实现逻辑简单,没有隐式的种子补充逻辑,不会出现类似
SecureRandom的不可控行为
如果有NIST SP 800-90A合规要求,可以使用SP800SecureRandomBuilder构建DRBG实例,构建时必须显式传入仅返回固定种子的自定义熵源,关闭默认的系统熵读取逻辑。
依赖配置
不要使用Android系统内置的裁剪版Bouncy Castle,不同厂商、不同系统版本的内置BC实现存在定制修改,会导致同种子输出不一致。请在gradle中引入官方发布的完整依赖:
dependencies { implementation 'org.bouncycastle:bcprov-jdk15on:1.70' }
可直接复用的实现代码
import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.prng.DigestRandomGenerator; import java.nio.charset.StandardCharsets; import java.util.Random; public class DeterministicRng extends Random { private final DigestRandomGenerator generator; public DeterministicRng(byte[] fixedSeed) { // 选用SHA-256作为摘要核心,跨版本一致性稳定 generator = new DigestRandomGenerator(new SHA256Digest()); // 仅使用传入的固定种子初始化,无额外熵注入 generator.addSeedMaterial(fixedSeed); } @Override public void setSeed(long seed) { // 兼容long类型种子输入,行为和JDK标准Random一致 if (generator != null) { generator.addSeedMaterial(seed); } } public void setSeed(byte[] seed) { generator.addSeedMaterial(seed); } @Override public void nextBytes(byte[] dst) { generator.nextBytes(dst); } @Override protected int next(int bitCount) { int byteLen = (bitCount + 7) / 8; byte[] buf = new byte[byteLen]; generator.nextBytes(buf); int res = 0; for (int i = 0; i < byteLen; i++) { res = (res << 8) | (buf[i] & 0xFF); } return res >>> (byteLen * 8 - bitCount); } }
验证方式
传入相同种子调用,所有环境下输出完全固定:
// 固定测试种子 byte[] seed = "my_fixed_seed_2024".getBytes(StandardCharsets.UTF_8); DeterministicRng rng = new DeterministicRng(seed); // 任意设备、任意Android版本上,连续调用的输出完全一致 System.out.println(rng.nextInt()); System.out.println(rng.nextLong()); System.out.println(rng.nextFloat());
避坑说明
- 不要使用
SecureRandom.getInstance("SHA1PRNG", "BC")获取实例,部分BC版本的SHA1PRNG服务提供者实现仍会默认读取系统熵补充种子,无法保证输出确定性 - 不要混用不同版本的Bouncy Castle库,不同版本的摘要算法或生成器逻辑调整可能导致输出差异,生产环境请锁定依赖版本
- 若必须使用确定性随机数做安全相关操作(极度不推荐),请额外对生成序列做合规校验,固定种子的随机数本质上不具备抗预测能力
内容的提问来源于stack exchange,提问作者root99
相关产品推荐
相关产品推荐

