如何从/dev/urandom获取带前置零掩码的32字节随机数据?
问题背景
我正在开发一个寻找比特币地址部分碰撞的程序,已获取urandom的源码但不知从何入手。我需要从/dev/urandom获取总计32字节的随机字节(包含掩码零),因为程序需要256位数据,转换为十六进制时开头需带有零掩码,示例十六进制输出如下:
000000000000000000000000000000000000000000000000000000000000002d4
注意实际十六进制值前的零(我称之为掩码),Python中很多生成比特币地址的库都需要这种格式。
我在使用以下代码时遇到了问题(该代码并非来自random.c),现在认为修改urandom本身可能更有帮助:
static bool init_rand(void *data, size_t size) { FILE *stream = fopen("/dev/urandom", "r"); if (stream == NULL) return false; bool ok = (fread(data, sizeof(uint8_t), size, stream) == size); fclose(stream); return ok; } static bool init_rand(void *data, size_t size) { size_t size0 = size / sizeof(unsigned) + 1; assert(size0 * sizeof(unsigned) >= size); unsigned data0[size0]; for (size_t i = 0; i < size0; i++) { int err = rand_s(data0 + i); if (err != 0) return false; } memcpy(data, data0, size); return true; } static struct seed *make_seed(void) { struct seed *seed = (struct seed *)malloc(sizeof(struct seed)); assert(seed != NULL); seed->counter = 0; if (!init_rand(seed, sizeof(struct seed))) { fprintf(stderr, "error: failed to init random seed\n"); exit(EXIT_FAILURE); } if (seed->counter == 0) // Sanity check... { fprintf(stderr, "error: random seed initialization failed\n"); exit(EXIT_FAILURE); } return seed; }
请问是否可以修改Linux内核驱动中的random.c,使其生成已带有零掩码的字节?
解决方案分析
完全没必要修改Linux内核的random.c,原因及替代方案如下:
内核修改的弊端
- 成本极高:需要重新编译内核、维护自定义内核分支,后续系统更新会覆盖改动,兼容性极差。
- 破坏设计初衷:
/dev/urandom的核心作用是提供完全随机的字节流,强行加入固定前缀会破坏随机性,违背内核随机设备的设计原则。
用户空间实现需求的两种场景
你的需求本质是两种情况,都可以在用户空间轻松实现:场景1:十六进制格式化时补零到64位(对应示例的满长度零前缀显示)
读取32字节随机数据后,格式化输出时确保每个字节都以两位十六进制表示(高位补零),就能得到满64位的十六进制字符串,符合Python比特币库的格式要求。示例代码:
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <stdint.h> int main() { uint8_t data[32]; int fd = open("/dev/urandom", O_RDONLY); if (fd == -1) { perror("open /dev/urandom"); exit(EXIT_FAILURE); } if (read(fd, data, sizeof(data)) != sizeof(data)) { perror("read /dev/urandom"); close(fd); exit(EXIT_FAILURE); } close(fd); // 格式化输出64位十六进制,每个字节补零到两位 for (size_t i = 0; i < sizeof(data); i++) { printf("%02x", data[i]); } printf("\n"); return EXIT_SUCCESS; }场景2:生成的32字节数据中前N个字节固定为0(掩码)
如果是需要实际二进制数据的前若干字节为0,只需在读取随机数据后,手动将指定范围的字节置0即可,无需改动内核。示例代码(假设前28字节为掩码零):
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <stdint.h> #include <string.h> #define MASK_LENGTH 28 // 前28字节为零掩码 int main() { uint8_t data[32]; int fd = open("/dev/urandom", O_RDONLY); if (fd == -1) { perror("open /dev/urandom"); exit(EXIT_FAILURE); } if (read(fd, data, sizeof(data)) != sizeof(data)) { perror("read /dev/urandom"); close(fd); exit(EXIT_FAILURE); } close(fd); // 设置前MASK_LENGTH字节为0 memset(data, 0, MASK_LENGTH); // 输出十六进制 for (size_t i = 0; i < sizeof(data); i++) { printf("%02x", data[i]); } printf("\n"); return EXIT_SUCCESS; }针对你现有代码的优化
你提供的init_rand函数用于初始化seed结构体,若需要结构体中部分字段为零掩码,只需在调用init_rand后,手动将对应字段赋值为0即可,无需修改内核或随机设备逻辑。
内容的提问来源于stack exchange,提问作者diviserbyzero
相关产品推荐
相关产品推荐

