我正在尝试用 C++ 编写密码加密函数(注意:仅用于教育目的。我实际上不会用它来存储我的密码。)但我不确定如何创建一个随机的 32 字节盐使用预定义的字符集。我该怎么做?
#include <random>
#include <iostream>
using namespace std;
void genSalt() {
const char charset[] = {
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"!£$%^&*():@~#'?/><.,|`¬¦"
};
}
代码应根据定义的字符集“charset”生成一个随机的 32 字节字符串。我不确定如何实现这一目标。
最佳答案
首先要注意的是源文件中某些字符的存储。根据编码,£
、¬
或 ¦
可能超过一个字节,这可能会搞砸您的结果;如果您希望事情顺利进行而不管编码如何,您应该将它们存储为硬编码字节:
const char charset[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"!\xA3$%^&*():@~#'?/><.,|`\xAC\xA6";
// \xA3 = single-byte extended encoding for £
// \xAC = ¬
// \xA6 = ¦
(顺便说一句,我的意思是无论如何在你的 salt 中使用这些字符都是一个坏主意,因为它们可能与使用 salt 的其他编码冲突。)
至于生成密码盐,我不是密码学家,但使用加密安全伪随机数生成器以外的任何东西对我来说似乎有点不确定。如果它只是一个 C++ 练习,内置的随机生成器就可以了。我从未真正使用过 C++11 PRNG 函数,所以这对我来说也是一个很好的练习。
您首先制作一个random_device
,然后制作一个随机化器引擎:
#include <random>
std::random_device my_random_device;
std::default_random_engine my_random_engine(my_random_device());
您可以选择不同的引擎来微调您的随机数,默认情况下是一个实现定义的选择(我假设您也可以轻松地插入加密安全生成器)。
random_device
自动处理播种,而如果您使用旧的 C 风格 rand
函数,您需要调用 srand
使用种子(如系统时间)在生成任何内容之前对其进行初始化。
要从您的 salt 源中选择字符,您需要选择一种分发方法,您可以在此处获得更多详细信息:https://en.cppreference.com/w/cpp/numeric/random
在这种情况下,您希望在盐字符集中均匀分布:
std::uniform_int_distribution<int> random_number(0, sizeof(charset) - 1);
您可以将其调用为 random_number(my_random_engine)
以获取介于 0 和最后一个字符索引之间的数字(不要忘记减 1 以跳过空终止符)。
然后很容易对字符进行采样并构建一个字符串:
std::string salt;
salt.reserve( 32 );
for( int i = 0; i < 32; i++ ) {
salt.push_back(charset[random_number(my_random_engine)]);
}
std::cout << "salt result: " << salt << std::endl;
工作示例:https://wandbox.org/permlink/mGd8pYP9Y3injuuG
我想提及的另一件事是对随机数使用 %
的常见陷阱。例如,考虑这个使用旧 C 风格的 rand()
函数的测试用例:
int main() {
// Seed randomizer
srand( time(0) );
// Print a random number between 0 and 1999
int number = rand() % 2000;
std::cout << number;
}
通常人们不在乎,因为它“足够随机”,但您不会得到模数 (%
) 的均匀分布。 rand()
生成一个介于 0
和 RAND_MAX
之间的数字,您应该缩放返回的范围以适应您想要的范围。
// Sample random number between 0 and 1999. (add 1 to rand max to make 2000 not slightly possible)
int number = rand() * 2000 / (RAND_MAX+1)
请记住选择合适的 PRNG 函数来满足您的需求,尤其是在寻找非常困难的赔率时。如果您要搜索百万分之一,如果 PRNG 函数没有统一覆盖所需范围,您可能永远找不到结果。
关于c++ - 如何生成伪随机 32 字节字符串以用作加密哈希函数中的盐?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56357869/