আমি সবচেয়ে বড় ত্রুটিটি যুক্তি দিয়ে বলব std::random_device
যে কোনও সিএসপিআরএনজি উপলব্ধ না হলে এটি একটি নির্দোষ ফলব্যাকের অনুমতি দেওয়া হয়। এটিই পিআরএনজি ব্যবহার না করার একটি ভাল কারণ std::random_device
, যেহেতু উত্পাদিত বাইটগুলি নির্জনবাদী হতে পারে। দুর্ভাগ্যক্রমে এটি কখন ঘটে তা অনুসন্ধান করার জন্য, বা নিম্নমানের এলোমেলো সংখ্যার পরিবর্তে ব্যর্থতার জন্য অনুরোধ করার জন্য একটি API সরবরাহ করে না।
এটি হ'ল, কোনও সম্পূর্ণ পোর্টেবল সমাধান নেই: তবে, একটি শালীন, ন্যূনতম পদ্ধতির রয়েছে। sysrandom
PRNG বীজ করতে আপনি কোনও সিএসপিআরএনজি ( নীচে হিসাবে সংজ্ঞায়িত ) এর চারপাশে একটি ন্যূনতম মোড়ক ব্যবহার করতে পারেন ।
উইন্ডোজ
আপনি নির্ভর করতে পারেন CryptGenRandom
, একটি সিএসপিআরএনজি। উদাহরণস্বরূপ, আপনি নিম্নলিখিত কোড ব্যবহার করতে পারেন:
bool acquire_context(HCRYPTPROV *ctx)
{
if (!CryptAcquireContext(ctx, nullptr, nullptr, PROV_RSA_FULL, 0)) {
return CryptAcquireContext(ctx, nullptr, nullptr, PROV_RSA_FULL, CRYPT_NEWKEYSET);
}
return true;
}
size_t sysrandom(void* dst, size_t dstlen)
{
HCRYPTPROV ctx;
if (!acquire_context(&ctx)) {
throw std::runtime_error("Unable to initialize Win32 crypt library.");
}
BYTE* buffer = reinterpret_cast<BYTE*>(dst);
if(!CryptGenRandom(ctx, dstlen, buffer)) {
throw std::runtime_error("Unable to generate random bytes.");
}
if (!CryptReleaseContext(ctx, 0)) {
throw std::runtime_error("Unable to release Win32 crypt library.");
}
return dstlen;
}
ইউনিক্স-সদৃশ
অনেকগুলি ইউনিক্স-মতো সিস্টেমে আপনার যখন সম্ভব হয় তখন / dev / urandom ব্যবহার করা উচিত (যদিও এটি পসিক্স-কমপ্লায়েন্ট সিস্টেমে উপস্থিত থাকার গ্যারান্টিযুক্ত নয়)।
size_t sysrandom(void* dst, size_t dstlen)
{
char* buffer = reinterpret_cast<char*>(dst);
std::ifstream stream("/dev/urandom", std::ios_base::binary | std::ios_base::in);
stream.read(buffer, dstlen);
return dstlen;
}
অন্যান্য
যদি কোনও সিএসপিআরএনজি উপলব্ধ না হয় তবে আপনি নির্ভর করতে পারেন std::random_device
। তবে সম্ভব হলে আমি এড়াতে পারব, যেহেতু বিভিন্ন সংকলক ( মূলত মিনজিডাব্লু ) এটি পিআরএনজি হিসাবে বাস্তবায়িত করে (বাস্তবে, প্রতিটি সময় একই ক্রম উত্পাদন করে মানুষকে সতর্ক করতে যে এটি সঠিকভাবে এলোমেলো নয়)।
seeding
এখন আমাদের ন্যূনতম ওভারহেড সহ টুকরো রয়েছে, আমরা আমাদের পিআরএনজি বীজ করতে এলোমেলো এন্ট্রপির পছন্দসই বিট তৈরি করতে পারি। উদাহরণটি PRNG বীজ করতে 32-বিট ব্যবহার করে (স্পষ্টতই অপ্রতুল) এবং আপনার এই মানটি বাড়ানো উচিত (যা আপনার সিএসপিআরএনজি উপর নির্ভরশীল)।
std::uint_least32_t seed;
sysrandom(&seed, sizeof(seed));
std::mt19937 gen(seed);
তুলনা বুস্ট
উত্স কোডটি তাত্ক্ষণিকভাবে দেখার পরে আমরা :: এলোমেলো_দেখার (সত্যিকারের সিএসপিআরএনজি) উন্নয়নের সমান্তরাল দেখতে পাই । MS_DEF_PROV
উইন্ডোজে বুস্ট ব্যবহারগুলি সরবরাহ করে, যা এর জন্য সরবরাহকারী প্রকার PROV_RSA_FULL
। শুধু অনুপস্থিত ক্রিপ্টোগ্রাফিক কনটেক্সট, যা দিয়ে কাজ করা যেতে পারে যাচাই করা হবে CRYPT_VERIFYCONTEXT
। * নিক্সে, বুস্ট ব্যবহার করে /dev/urandom
। আইই, এই সমাধানটি বহনযোগ্য, ভাল-পরীক্ষিত এবং সহজেই ব্যবহারযোগ্য।
লিনাক্স বিশেষায়িতকরণ
আপনি যদি সুরক্ষার জন্য সংক্ষিপ্ততা ত্যাগ করতে ইচ্ছুক getrandom
হন তবে লিনাক্স ৩.১17 এবং তারপরে এবং সাম্প্রতিক সোলারিতে এটি একটি দুর্দান্ত পছন্দ। কার্নেলটি বুট করার পরেও তার সিএসপিআরএনজি আরম্ভ করে না দিলে এটি ব্লক করা ব্যতীত getrandom
একইরকম আচরণ করে /dev/urandom
। নিম্নলিখিত স্নিপেটটি লিনাক্স getrandom
উপলব্ধ কিনা এবং যদি ফিরে না আসে তা সনাক্ত করে /dev/urandom
।
#if defined(__linux__) || defined(linux) || defined(__linux)
# // Check the kernel version. `getrandom` is only Linux 3.17 and above.
# include <linux/version.h>
# if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
# define HAVE_GETRANDOM
# endif
#endif
// also requires glibc 2.25 for the libc wrapper
#if defined(HAVE_GETRANDOM)
# include <sys/syscall.h>
# include <linux/random.h>
size_t sysrandom(void* dst, size_t dstlen)
{
int bytes = syscall(SYS_getrandom, dst, dstlen, 0);
if (bytes != dstlen) {
throw std::runtime_error("Unable to read N bytes from CSPRNG.");
}
return dstlen;
}
#elif defined(_WIN32)
// Windows sysrandom here.
#else
// POSIX sysrandom here.
#endif
OpenBSD
সেখানে এক চূড়ান্ত সতর্কীকরণ হল: আধুনিক OpenBSD নেই /dev/urandom
। পরিবর্তে আপনার জেন্টেন্ট্রপি ব্যবহার করা উচিত ।
#if defined(__OpenBSD__)
# define HAVE_GETENTROPY
#endif
#if defined(HAVE_GETENTROPY)
# include <unistd.h>
size_t sysrandom(void* dst, size_t dstlen)
{
int bytes = getentropy(dst, dstlen);
if (bytes != dstlen) {
throw std::runtime_error("Unable to read N bytes from CSPRNG.");
}
return dstlen;
}
#endif
অন্যান্য চিন্তা
আপনার যদি ক্রিপ্টোগ্রাফিকভাবে সুরক্ষিত এলোমেলো বাইটের প্রয়োজন হয়, আপনার সম্ভবত পসিক্সের আনফারড খোলা / পঠন / বন্ধের সাথে fstream প্রতিস্থাপন করা উচিত। এটি উভয় কারণ basic_filebuf
এবং FILE
একটি অভ্যন্তরীণ বাফার ধারণ করে, যা একটি স্ট্যান্ডার্ড বরাদ্দকারীর মাধ্যমে বরাদ্দ করা হবে (এবং সেইজন্য স্মৃতি থেকে মুছে ফেলা হয় না)।
এটি সহজেই এতে পরিবর্তন করে sysrandom
করা যেতে পারে :
size_t sysrandom(void* dst, size_t dstlen)
{
int fd = open("/dev/urandom", O_RDONLY);
if (fd == -1) {
throw std::runtime_error("Unable to open /dev/urandom.");
}
if (read(fd, dst, dstlen) != dstlen) {
close(fd);
throw std::runtime_error("Unable to read N bytes from CSPRNG.");
}
close(fd);
return dstlen;
}
ধন্যবাদ
FILE
বাফার রিডগুলি উল্লেখ করার জন্য বেন ভয়েগটকে বিশেষ ধন্যবাদ এবং তাই ব্যবহার করা উচিত নয়।
আমি উল্লেখ করার জন্য পিটার কর্ডেস getrandom
এবং ওপেনবিএসডি এর অভাবকেও ধন্যবাদ জানাতে চাই /dev/urandom
।