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());
}
}
我在尝试使用 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());
}
}