OPENSSL RAND_bytes 输出不可靠

OPENSSL RAND_bytes output isn't reliable

我在尝试使用 OPENSSL 的 RAND_bytes() 函数生成随机数组时遇到问题。

OPENSSL 版本:

OpenSSL 1.1.0g  2 Nov 2017 (Library: OpenSSL 1.1.1  11 Sep 2018)
built on: Tue Nov 12 16:58:35 2019 UTC
platform: debian-amd64
compiler: gcc -fPIC -pthread -m64 -Wa,--noexecstack -Wall -Wa,--noexecstack -g -O2 -fdebug-prefix-map=/build/openssl-kxN_24/openssl-1.1.1=. -fstack-protector-strong -Wformat -Werror=format-security -DOPENSSL_USE_NODELETE -DL_ENDIAN -DOPENSSL_PIC -DOPENSSL_CPUID_OBJ -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DKECCAK1600_ASM -DRC4_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DGHASH_ASM -DECP_NISTZ256_ASM -DX25519_ASM -DPADLOCK_ASM -DPOLY1305_ASM -DNDEBUG -Wdate-time -D_FORTIFY_SOURCE=2
OPENSSLDIR: "/usr/lib/ssl"
ENGINESDIR: "/usr/lib/x86_64-linux-gnu/engines-1.1"

generate_salt.c

#include <openssl/rand.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>

uint8_t *generate_salt()
{
    uint8_t *res = malloc(16 * sizeof(uint8_t));
    RAND_bytes(res, 16);
    return res;
}

void print_hexa(uint8_t *message)
{
    int message_length = 0;
    while (message[message_length] != '[=12=]')
    {
        message_length += 1;
    }
    for (int i = 0; i < message_length; i++)
    {
        printf("%02x", message[i]);
    }
    printf(";\n");
}
int main()
{
    for (int i = 0; i < 20; i++)
    {
        print_hexa(generate_salt());
    }
}

输出:

05b3c470b709ef345b;
862c53a9;
1aa1665fe26aa04a7cdc9e63a14b8859;
e093b250e55172c6a12eb21a14146b52;
7de470cf708249bd81571a9fe1362618;
7fccff3509fb0189a954784ce198e3cd;
ba98881d1023a5f4d4c5a2c829ce26c3;
63e0f027a057de8f0e32e595f7cd4df2;
6faa5ab05413c5566a3b05783dfaa086;
ae2e91741d0dabd6ba7d0ae55885540f;
cd49f8c218cfdaf02dfd6fa53e523e51;
2fd24cb9e2d6e7b992eb28a2ffa5af44;
5c6f6ffb62784c87cc25ba25c6ba;
56a0cc97d008ee65b0b6f78eb094fcee;
9d1ef2ef40966dca1991364fa83d134d;
2ab61566cdd9a0d2bf09b2634b112cd2;
7064ffe72ccb9f9eb2954c0c59477fd8;
100e0c34e64d2f6f788c6fe7b908b181;
67bb8b232d1ab2ada5632c0e5fbb0f4f;
f55df4049bf0c477fdf6121399e5c116;

我的问题是某些结果不符合给定长度(16 字节)。我在 openssl/evp.h 模块中使用的功能也有类似的问题。我首先以为我有一些与内存泄漏相关的问题,这就是为什么我制作了一个单独的 generate_salt.c 文件,这似乎证明我错了。

有没有人遇到过这个问题并知道如何解决?

我正在使用 WSL(Linux Bash on Windows),这可能是它无法正常工作的另一个原因。也许 OPENSSL 需要一个实际的 Linux 内核。

编辑:正如接受的答案中所建议的那样,print_hexa 的实现是错误的。当 0x00 字节出现在字节数组中时,while 条件会导致显示错误(也可能导致段错误)。长度应作为参数给出或在函数中硬编码。 在 C 中无法获取指针的 length

您对 print_hexa 的实施是错误的。随机字节可能包含 0x00 并且函数可能会停在那里。 更糟糕的是,如果随机字节不包含 0x00,它将执行 out-of-range 访问以查找 0x00.

为避免此问题,打印长度应单独提供给 print_hexa

#include <openssl/rand.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>

uint8_t *generate_salt()
{
    uint8_t *res = malloc(16 * sizeof(uint8_t));
    RAND_bytes(res, 16);
    return res;
}

void print_hexa(uint8_t *message, int message_length)
{
    for (int i = 0; i < message_length; i++)
    {
        printf("%02x", message[i]);
    }
    printf(";\n");
}
int main()
{
    for (int i = 0; i < 20; i++)
    {
        print_hexa(generate_salt(), 16);
    }
}

另一种选择是 hard-coding 您在 generate_salt 函数中所做的长度。

#include <openssl/rand.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>

uint8_t *generate_salt()
{
    uint8_t *res = malloc(16 * sizeof(uint8_t));
    RAND_bytes(res, 16);
    return res;
}

void print_hexa(uint8_t *message)
{
    for (int i = 0; i < 16; i++)
    {
        printf("%02x", message[i]);
    }
    printf(";\n");
}
int main()
{
    for (int i = 0; i < 20; i++)
    {
        print_hexa(generate_salt());
    }
}

将长度定义为宏比直接写幻数16要好。

#include <openssl/rand.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>

#define LENGTH 16

uint8_t *generate_salt()
{
    uint8_t *res = malloc(LENGTH * sizeof(uint8_t));
    RAND_bytes(res, LENGTH);
    return res;
}

void print_hexa(uint8_t *message)
{
    for (int i = 0; i < LENGTH; i++)
    {
        printf("%02x", message[i]);
    }
    printf(";\n");
}
int main()
{
    for (int i = 0; i < 20; i++)
    {
        print_hexa(generate_salt());
    }
}