ฉันต้องการใช้ /dev/random
หรือ /dev/urandom
ใน C จะต้องทำอย่างไร? ฉันไม่รู้ว่าจะจัดการพวกมันใน C ได้อย่างไร หากใครรู้ช่วยบอกฉันหน่อยว่าต้องทำอย่างไร ขอบคุณ
จะใช้ /dev/random หรือ urandom ใน C ได้อย่างไร?
คำตอบ (5)
โดยทั่วไป ควรหลีกเลี่ยงการเปิดไฟล์เพื่อรับข้อมูลแบบสุ่ม เนื่องจากมีจุดที่เกิดความล้มเหลวในขั้นตอนนี้กี่จุด
ในลีนุกซ์รุ่นใหม่ล่าสุด สามารถใช้การเรียกระบบ getrandom
เพื่อ รับตัวเลขสุ่มที่ปลอดภัยด้วยการเข้ารหัสลับ และไม่สามารถล้มเหลวได้ หาก GRND_RANDOM
ไม่ได้ ระบุเป็นแฟล็ก และจำนวนการอ่านสูงสุด 256 ไบต์
ณ เดือนตุลาคม 2017 ขณะนี้ OpenBSD, Darwin และ Linux (ที่มี -lbsd
) ต่างก็มีการใช้งาน arc4random
ที่ปลอดภัยด้วยการเข้ารหัสลับและไม่สามารถล้มเหลวได้ นั่นทำให้มันเป็นตัวเลือกที่น่าสนใจมาก:
char myRandomData[50];
arc4random_buf(myRandomData, sizeof myRandomData); // done!
มิฉะนั้น คุณสามารถใช้อุปกรณ์สุ่มราวกับว่ามันเป็นไฟล์ได้ คุณอ่านจากพวกเขาแล้วคุณจะได้รับข้อมูลแบบสุ่ม ฉันใช้ open
/read
ที่นี่ แต่ fopen
/fread
ก็ใช้ได้เช่นกัน
int randomData = open("/dev/urandom", O_RDONLY);
if (randomData < 0)
{
// something went wrong
}
else
{
char myRandomData[50];
ssize_t result = read(randomData, myRandomData, sizeof myRandomData);
if (result < 0)
{
// something went wrong
}
}
คุณอาจอ่านไบต์แบบสุ่มได้อีกมากมายก่อนที่จะปิดตัวอธิบายไฟล์ /dev/urandom จะไม่บล็อกและเติมไบต์ตามที่คุณร้องขอเสมอ เว้นแต่ว่าการเรียกของระบบจะถูกขัดจังหวะด้วยสัญญาณ ถือว่ามีความปลอดภัยแบบเข้ารหัสและควรเป็นอุปกรณ์สุ่มที่คุณเข้าถึงได้
/dev/random นั้นพิถีพิถันมากกว่า บนแพลตฟอร์มส่วนใหญ่ ระบบสามารถส่งคืนไบต์น้อยกว่าที่คุณขอ และสามารถบล็อกได้หากมีไบต์ไม่เพียงพอ สิ่งนี้ทำให้เรื่องราวการจัดการข้อผิดพลาดซับซ้อนมากขึ้น:
int randomData = open("/dev/random", O_RDONLY);
if (randomData < 0)
{
// something went wrong
}
else
{
char myRandomData[50];
size_t randomDataLen = 0;
while (randomDataLen < sizeof myRandomData)
{
ssize_t result = read(randomData, myRandomData + randomDataLen, (sizeof myRandomData) - randomDataLen);
if (result < 0)
{
// something went wrong
}
randomDataLen += result;
}
close(randomData);
}
/dev/urandom
หากมีการเพาะอย่างเพียงพอ หนึ่งครั้ง มันจะส่งออกตัวเลขสุ่มหลอกจำนวนไม่จำกัดซึ่งเหมาะสำหรับใช้ในสกุลเงินดิจิทัล สิ่งเดียวที่ต้องกังวลก็คือการเพาะเมล็ดครั้งแรกอาจไม่เพียงพอ ปัญหาที่สุ่มน้อยกว่าเกิดขึ้นคือกรณีพิเศษบางกรณีที่เกิดขึ้นไม่บ่อยนัก เช่น ในช่วงต้นของกระบวนการบูตบนอุปกรณ์ฝังตัวหรือเครื่องเสมือนโคลน
- person CodesInChaos; 27.10.2013
/dev/urandom
ก็ใช้ได้
- person CodesInChaos; 27.10.2013
read
ฉันว่าโดยทั่วไปคุณควรตรวจสอบเงื่อนไขข้อผิดพลาดเสมอ นอกจากนี้ หากแอปพลิเคชันของคุณมีความสำคัญต่อความปลอดภัย อาจเป็นความคิดที่ดีที่จะตรวจสอบว่าไฟล์นั้นเป็นอุปกรณ์แบบอักขระ
- person zneak; 02.01.2015
randomData
นอกเหนือจากการปิดมันด้วยซ้ำ คุณแน่ใจว่ามันไม่ควรอ่าน read(randomData ...
? แสดงความสำคัญของการตั้งชื่อ
- person BoppreH; 01.08.2015
/dev/random
และ /dev/urandom
อยู่หลัง CSPRNG เดียวกัน (คำแนะนำของคุณในการเลือก /dev/urandom
มากกว่า /dev/random
ยังคงอยู่)
- person Sebastian; 23.03.2017
มีคำตอบที่ถูกต้องอื่นๆ ข้างต้น ฉันจำเป็นต้องใช้สตรีม FILE*
นี่คือสิ่งที่ฉันทำ...
int byte_count = 64;
char data[64];
FILE *fp;
fp = fopen("/dev/urandom", "r");
fread(&data, 1, byte_count, fp);
fclose(fp);
fread((char*)(&myInt),sizeof(myInt),1,fp)
- person Azeem Bande-Ali; 25.05.2013
byte_count
? มันไม่ได้ใช้.
- person CalculatorFeline; 10.08.2017
เพียงเปิดไฟล์เพื่ออ่านแล้วอ่านข้อมูล ใน C ++ 11 คุณอาจต้องการใช้ std::random_device
ซึ่งให้การเข้าถึงข้ามแพลตฟอร์มไปยังอุปกรณ์ดังกล่าว
std::random_device
ไม่ผ่านมาตรฐานปี 2011 โดยปรากฏในฉบับร่าง N3797
- person Keith Thompson; 02.01.2015
std::random_device
ได้ ทำให้เป็น C ++ 11 ในตอนท้าย
- person legends2k; 26.06.2015
std::random_device
อยู่ใน C++ และไม่ใช่ใน C และ OP ถามวิธีใช้ /dev/random
หรือ /dev/urandom
ไม่ใช่วิธีใช้ std::random_device
แม้ว่าจะเป็นทางเลือกที่ดีที่จะใช้ std::random_device
และมีประโยชน์ แต่ก็ไม่ได้เป็นเพียงสิ่งที่ OP ขอ
- person Nfagie Yansaneh; 08.08.2017
Zneak ถูกต้อง 100% เป็นเรื่องปกติมากที่จะอ่านบัฟเฟอร์ของตัวเลขสุ่มที่มีขนาดใหญ่กว่าที่คุณต้องการเมื่อเริ่มต้นเล็กน้อย จากนั้นคุณสามารถเติมอาร์เรย์ในหน่วยความจำหรือเขียนลงในไฟล์ของคุณเองเพื่อนำกลับมาใช้ใหม่ในภายหลังได้
การใช้งานทั่วไปของสิ่งข้างต้น:
typedef struct prandom {
struct prandom *prev;
int64_t number;
struct prandom *next;
} prandom_t;
สิ่งนี้จะกลายเป็นเหมือนเทปที่เลื่อนไปข้างหน้าซึ่งสามารถเติมด้ายอื่นได้อย่างน่าอัศจรรย์ตามต้องการ มี จำนวนมาก จาก บริการ ที่ให้การถ่ายโอนไฟล์ขนาดใหญ่ซึ่งไม่มีอะไรเลยนอกจากตัวเลขสุ่มที่สร้างขึ้นด้วยตัวสร้างที่แข็งแกร่งกว่ามาก เช่น:
- การสลายตัวของสารกัมมันตรังสี
- พฤติกรรมทางแสง (โฟตอนชนกระจกกึ่งโปร่งใส)
- เสียงบรรยากาศ (ไม่แรงเท่าข้างต้น)
- ฟาร์มลิงขี้เมาพิมพ์คีย์บอร์ดและหนูเคลื่อนไหว (ล้อเล่น)
อย่าใช้เอนโทรปี "บรรจุล่วงหน้า" สำหรับเมล็ดที่เข้ารหัส ในกรณีที่ไม่ได้ดำเนินการโดยไม่บอกกล่าว ชุดเหล่านั้นใช้ได้สำหรับการจำลอง ไม่ดีเลย สำหรับการสร้างคีย์และอื่นๆ
ไม่ต้องกังวลเรื่องคุณภาพ หากคุณต้องการตัวเลขจำนวนมากสำหรับบางอย่างเช่นการจำลองมอนติคาร์โล จะดีกว่ามากถ้ามีตัวเลขเหล่านั้นในลักษณะที่ไม่ทำให้ read() ถูกบล็อก
อย่างไรก็ตาม โปรดจำไว้ว่า การสุ่มของตัวเลขนั้นขึ้นอยู่กับปัจจัยที่กำหนดพอๆ กับความซับซ้อนในการสร้างตัวเลขนั้น /dev/random
และ /dev/urandom
สะดวก แต่ไม่แรงเท่ากับการใช้ HRNG (หรือการดาวน์โหลดดัมพ์ขนาดใหญ่จาก HRNG) นอกจากนี้ ควรสังเกตด้วยว่า /dev/random
เติมผ่านเอนโทรปี ดังนั้นจึงสามารถบล็อกได้ค่อนข้างมาก ในขณะที่ขึ้นอยู่กับสถานการณ์
คำตอบของ zneak ครอบคลุมอย่างเรียบง่าย แต่ความจริงนั้นซับซ้อนกว่านั้น ตัวอย่างเช่น คุณต้องพิจารณาว่า /dev/{u}random เป็นอุปกรณ์ตัวเลขสุ่มจริงๆ หรือไม่ตั้งแต่แรก สถานการณ์ดังกล่าวอาจเกิดขึ้นได้หากเครื่องของคุณถูกโจมตีและอุปกรณ์แทนที่ด้วยลิงก์สัญลักษณ์ไปที่ /dev/zero หรือไฟล์กระจัดกระจาย หากสิ่งนี้เกิดขึ้น กระแสสุ่มก็สามารถคาดเดาได้อย่างสมบูรณ์แล้ว
วิธีที่ง่ายที่สุด (อย่างน้อยบน Linux และ FreeBSD) คือทำการเรียก ioctl บนอุปกรณ์ที่จะสำเร็จก็ต่อเมื่ออุปกรณ์นั้นเป็นเครื่องกำเนิดแบบสุ่ม:
int data;
int result = ioctl(fd, RNDGETENTCNT, &data);
// Upon success data now contains amount of entropy available in bits
หากดำเนินการนี้ก่อนที่จะอ่านอุปกรณ์สุ่มครั้งแรก ก็ถือว่ามีเดิมพันที่ยุติธรรมว่าคุณมีอุปกรณ์สุ่ม ดังนั้นคำตอบของ @zneak จึงสามารถขยายเป็น:
int randomData = open("/dev/random", O_RDONLY);
int entropy;
int result = ioctl(randomData, RNDGETENTCNT, &entropy);
if (!result) {
// Error - /dev/random isn't actually a random device
return;
}
if (entropy < sizeof(int) * 8) {
// Error - there's not enough bits of entropy in the random device to fill the buffer
return;
}
int myRandomInteger;
size_t randomDataLen = 0;
while (randomDataLen < sizeof myRandomInteger)
{
ssize_t result = read(randomData, ((char*)&myRandomInteger) + randomDataLen, (sizeof myRandomInteger) - randomDataLen);
if (result < 0)
{
// error, unable to read /dev/random
}
randomDataLen += result;
}
close(randomData);
บล็อก Insane Coding กล่าวถึงเรื่องนี้ และข้อผิดพลาดอื่นๆเมื่อไม่นานมานี้ ฉันขอแนะนำให้อ่านบทความทั้งหมด ฉันต้องให้เครดิตพวกเขาว่าโซลูชันนี้ถูกดึงมาจากไหน
แก้ไขเพื่อเพิ่ม (25-07-2557)...
บังเอิญฉันอ่านเจอเมื่อคืนนี้ว่าเป็นส่วนหนึ่งของ ความพยายามของ LibReSSL ดูเหมือน Linux จะได้รับ GetRandom() syscall. ในขณะที่เขียนยังไม่มีคำว่าจะพร้อมใช้งานในเคอร์เนลทั่วไปเมื่อใด อย่างไรก็ตาม นี่จะเป็นอินเทอร์เฟซที่ต้องการเพื่อรับข้อมูลสุ่มที่มีความปลอดภัยแบบเข้ารหัส เนื่องจากจะลบข้อผิดพลาดทั้งหมดที่เข้าถึงผ่านไฟล์ที่มีให้ ดูเพิ่มเติมที่ LibReSSL การใช้งานที่เป็นไปได้
getrandom()
เปิดตัวในเคอร์เนล 3.17 ดังนั้นหุ้น Ubuntu 16.04 จึงไม่มี ณ วันที่ 17-01-2018 เรียกใช้ uname -a
ในเทอร์มินัลเพื่อตรวจสอบเวอร์ชันเคอร์เนลของคุณ
- person erapert; 17.01.2018