You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从/dev/urandom等获取随机字节不足,one-time pad密钥长度异常求助

一次性密码本密钥长度“缩水”问题排查与解决

核心原因

  • 你生成的密钥是二进制字节流,其中大概率包含ASCII值为0的'\0'字节,而C语言的字符串操作(如strlen()、printf("%s"))会把'\0'当作字符串结束符,导致你看到的“字符串长度”或文件内容被截断,但实际上getrandom()确实生成了足够的字节数。
  • 你没有检查getrandom()的返回值,如果调用失败(比如被信号中断),内存可能未被完全覆盖,结合calloc()初始化的0值,也会造成密钥“变短”的错觉。

解决方法

  1. 强制检查getrandom()返回值并补全字节
    getrandom()可能因信号中断返回部分字节,需要循环调用直到获取足够长度的密钥。
  2. 将密钥视为二进制数据而非字符串
    • 不要用strlen()判断密钥长度,直接使用传入的length参数。
    • 读写文件时用fwrite()/fread()这类二进制操作函数,避免fputs()/fgets()等字符串函数截断数据。
  3. 改用malloc()替代calloc()
    calloc()会将内存初始化为0,完全没必要,malloc()更高效,反正后续会被getrandom()覆盖。

修正后的代码

#include <sys/random.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#define ERROR(msg) do { perror(msg); exit(EXIT_FAILURE); } while(0)

uint8_t *genkey(const size_t length)
{
    uint8_t *key = malloc(length * sizeof(uint8_t));
    if (!key) ERROR("could not allocate memory");

    ssize_t bytes_read;
    size_t remaining = length;
    uint8_t *ptr = key;

    // 循环读取,确保获取足够字节
    while (remaining > 0) {
        bytes_read = getrandom(ptr, remaining, 0);
        if (bytes_read < 0) {
            // 被信号中断时重试,其他情况直接报错
            if (errno == EINTR) continue;
            ERROR("getrandom failed");
        }
        remaining -= bytes_read;
        ptr += bytes_read;
    }

    return key;
}

密钥读写示例

写入密钥到文件时,必须用二进制模式:

void write_key(const uint8_t *key, size_t length, const char *path)
{
    FILE *fp = fopen(path, "wb");
    if (!fp) ERROR("failed to open key file");
    if (fwrite(key, 1, length, fp) != length) {
        ERROR("failed to write key");
    }
    fclose(fp);
}

读取密钥时同样用fread()读取指定长度,避免字符串截断问题。

内容的提问来源于stack exchange,提问作者nikbott

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 17:48:11