randomSeed(analogRead(x))
จะสร้างตัวเลขขึ้นมา 255 ลำดับเท่านั้นซึ่งทำให้มันยากที่จะลองคอมโบทั้งหมดและสร้าง oracle ที่สามารถจับคู่กับเอาต์พุตสตรีมของคุณและทำนายผลลัพธ์ทั้งหมดได้ 100% คุณอยู่ในเส้นทางที่ถูกต้อง แต่เป็นเพียงเกมตัวเลขและคุณต้องการมากกว่านั้น ตัวอย่างเช่นการอ่านอะนาล็อก 100 ครั้งจาก 4 ADCs รวมพวกเขาทั้งหมดและให้อาหารที่randomSeed
จะดีกว่ามาก เพื่อความปลอดภัยสูงสุดคุณต้องมีทั้งอินพุตที่ไม่แน่นอนและการผสมที่ไม่สามารถกำหนดได้
ฉันไม่ใช่นักเขียนรหัส แต่ฉันใช้เวลาหลายพันชั่วโมงในการค้นคว้าและสร้างเครื่องกำเนิดไฟฟ้าแบบสุ่มฮาร์ดแวร์และซอฟต์แวร์ดังนั้นให้ฉันแบ่งปันสิ่งที่ฉันได้เรียนรู้:
อินพุตที่คาดเดาไม่ได้:
- analogRead () (บนหมุดลอย)
- GetTemp ()
อินพุตที่คาดเดาไม่ได้:
- micros () (w / a ช่วงเวลาตัวอย่างที่ไม่ได้กำหนดค่า)
- clock jitter (แบนด์วิธต่ำ แต่ใช้ได้)
- readVCC () (หากไม่ใช่แบตเตอรี่)
อินพุตที่คาดเดาไม่ได้ภายนอก:
- เซ็นเซอร์อุณหภูมิความชื้นและความดัน
- ไมโครโฟน
- ตัวแบ่งแรงดัน LDR
- เสียงทรานซิสเตอร์อคติย้อนกลับ
- เข็มทิศ / กระวนกระวายใจเร่ง
- สแกนฮอตสปอตไร้สาย esp8266 (ssid, db, ฯลฯ )
- esp8266 เวลา (งาน wifi พื้นหลังทำให้ micros ที่กำหนดไว้ () นำมาซึ่งไม่แน่นอน)
- esp8266 HWRNG -
RANDOM_REG32
รวดเร็วมากและคาดเดาไม่ได้หยุด 1 ครั้ง
การรวบรวม
สิ่งสุดท้ายที่คุณต้องการทำคือคายเอนโทรปีออกมา ง่ายกว่าที่จะคาดเดาการพลิกเหรียญมากกว่าการฝากเหรียญ ข้อสรุปเป็นสิ่งที่ดี unsigned long bank;
หลังจากbank+= thisSample;
นั้นก็ดี มันจะเกลือกกลิ้ง bank[32]
ดียิ่งขึ้นอ่านต่อ คุณต้องการรวบรวมตัวอย่างอย่างน้อย 8 ตัวอย่างสำหรับแต่ละชิ้นของผลลัพธ์
การป้องกันการเป็นพิษ
หากการให้ความร้อนแก่บอร์ดทำให้เกิดสัญญาณนาฬิกาสั่นมากนั่นเป็นเวคเตอร์การโจมตี เช่นเดียวกันกับการระเบิด RFI ไปยังอินพุต analogRead () การโจมตีทั่วไปอื่น ๆ เพียงแค่ถอดปลั๊กดังนั้นจึงทิ้งเอนโทรปีที่สะสมไว้ทั้งหมด คุณไม่ควรส่งออกหมายเลขจนกว่าคุณจะรู้ว่าปลอดภัยที่จะทำเช่นนั้นแม้จะใช้ความเร็ว
นี่คือเหตุผลที่คุณต้องการให้เอนโทรปีในระยะยาวโดยใช้ EEPROM, SD และอื่น ๆ ดูที่Fortuna PRNGซึ่งใช้ 32 ธนาคารแต่ละแห่งอัพเดทครึ่งหนึ่งบ่อยเท่าที่เคยเป็นมา ทำให้เป็นการยากที่จะโจมตีธนาคารทั้ง 32 แห่งในเวลาที่เหมาะสม
การประมวลผล
เมื่อคุณรวบรวม "เอนโทรปี" คุณต้องทำความสะอาดและหย่าจากการป้อนข้อมูลในวิธีที่ยากต่อการย้อนกลับ SHA / 1/256 ดีสำหรับเรื่องนี้ คุณสามารถใช้ SHA1 (หรือแม้กระทั่ง MD5 จริง ๆ ) เพื่อความเร็วเนื่องจากคุณไม่มีช่องโหว่แบบธรรมดา ในการเก็บเกี่ยวอย่าใช้ธนาคาร entopy เต็มรูปแบบและทำการเพิ่ม "เกลือ" ลงในเอาต์พุตที่แตกต่างกันในแต่ละครั้งเพื่อป้องกันผลลัพธ์ที่เหมือนกันเนื่องจากไม่มีการเปลี่ยนแปลงของเอนโทรปี: output = sha1( String(micros()) + String(bank[0]) + [...] );
ฟังก์ชัน sha จะซ่อนอินพุตและขาวเอาท์พุท การสะสมต่ำและปัญหาทั่วไปอื่น ๆ
ในการใช้อินพุตไทม์เมอร์คุณต้องกำหนดค่าอินสแตนซ์ นี่เป็นเรื่องง่ายเหมือนdelayMicroseconds(lastSample % 255)
; ซึ่งหยุดระยะเวลาที่คาดเดาไม่ได้ทำให้นาฬิกา "ต่อเนื่อง" อ่านไม่เหมือนกัน ทำแบบกึ่งประจำเช่นที่if(analogRead(A1)>200){...}
จัดไว้ให้ A1 มีเสียงดังหรือติดอยู่กับอินพุตแบบไดนามิก การแยกแต่ละส่วนของการไหลของคุณค่อนข้างยากที่จะตรวจสอบจะป้องกันการเข้ารหัสลับในเอาต์พุตที่แยกส่วน / ฉีกขาด
การรักษาความปลอดภัยที่แท้จริงคือเมื่อผู้โจมตีรู้จักทั้งระบบของคุณและยังไม่มีทางเอาชนะมันได้
สุดท้ายตรวจสอบงานของคุณ รันเอาต์พุตของคุณผ่านENT.EXE (มีให้สำหรับ nix / mac) และดูว่ามันดีหรือไม่ ที่สำคัญที่สุดคือการแจกแจงแบบไคสแควร์ซึ่งโดยปกติควรอยู่ระหว่าง 33% ถึง 66% หากคุณได้รับ 1.43% หรือ 99.999% หรืออะไรทำนองนั้นการทดสอบมากกว่าหนึ่งครั้งในหนึ่งแถวการสุ่มของคุณจะไร้สาระ คุณยังต้องการรายงานเอนโทรปี ENT ที่ใกล้เคียงกับ 8 บิตต่อไบต์มากที่สุด> 7.9 อย่างแน่นอน
TLDR: วิธีป้องกันคนโง่ที่ง่ายที่สุดคือ HWRNG ของ uthe ESP8266 มันรวดเร็วสม่ำเสมอและคาดเดาไม่ได้ เรียกใช้สิ่งนี้บน ESP8266 ที่รัน Ardunio core และใช้ซีเรียลเพื่อพูดคุยกับ AVR:
// ESP8266 Arduino core code:
void setup(){
Serial.begin(9600); // or whatever
}
void loop() {
// Serial.write((char)(RANDOM_REG32 % 256)); // "bin"
Serial.print( String(RANDOM_REG32, HEX).substring(1)); // "hex"
}
** แก้ไข
ที่นี่เป็นกระดานร่าง HWRNG ที่เปลือยเปล่าที่ฉันเขียนไปสักพักใช้งานไม่ได้เป็นแค่นักสะสม แต่ CSPRNG ทั้งหมดแยกออกจากพอร์ตอนุกรม มันถูกสร้างขึ้นสำหรับ pro-mini แต่ควรปรับให้เข้ากับบอร์ดอื่นได้ง่าย คุณสามารถใช้เพียงหมุดอะนาล็อกที่ลอยได้ แต่มันจะเป็นการดีกว่าถ้าคุณเพิ่มสิ่งต่าง ๆ ลงไปมันจะมีสิ่งที่แตกต่างกัน เช่นเดียวกับไมโครโฟน LDRs เทอร์มิสเตอร์ (ตัดให้มีอุณหภูมิสูงสุดถึงอุณหภูมิห้อง) และแม้แต่สายที่ยาว มันค่อนข้างดีใน ENT ถ้าคุณมีเสียงรบกวนปานกลาง
ร่างรวมความคิดหลายอย่างที่ฉันได้กล่าวถึงในคำตอบและความคิดเห็นติดตามของฉัน: การสะสมเอนโทรปีการยืดโดยเอนโทรปีที่มีการสุ่มตัวอย่างน้อยเกินไป (ฟอนนอยมันน์บอกว่ามันเท่ห์) มันลืมการประเมินคุณภาพเอนโทรปีในความโปรดปรานของ "Gimme อะไรที่อาจเป็นไปได้แบบไดนามิก" และการผสมโดยใช้การเข้ารหัสแบบดั้งเดิม
// AVR (ardunio) HWRNG by dandavis. released to public domain by author.
#include <Hash.h>
unsigned long read[8] = {0, 0, 0, 0, 0, 0, 0, 0};
const int pincount = 9; // adjust down for non pro-mini boards
int pins[9] = {A0, A1, A2, A3, A4, A5, A6, A7, A0}; // adjust for board, name analog inputs to be sampled
unsigned int ticks = 0;
String buff = ""; // holds one round of derivation tokens to be hashed.
String cache; // the last read hash
void harvest() { // String() slows down the processing, making micros() calls harder to recreate
unsigned long tot = 0; // the total of all analog reads
buff = String(random(2147483647)) + String(millis() % 999);
int seed = random(256) + (micros() % 32);
int offset = random(2147483647) % 256;
for (int i = 0; i < 8; i++) {
buff += String( seed + read[i] + i + (ticks % 65), HEX );
buff += String(random(2147483647), HEX);
tot += read[i];
}//next i
buff += String( (micros() + ticks + offset) % 99999, HEX);
if (random(10) < 3) randomSeed(tot + random(2147483647) + micros());
buff = sha1( String(random(2147483647)) + buff + (micros()%64) + cache); // used hash to uniform output and waste time
Serial.print( buff ); // output the hash
cache = buff;
spin();
}//end harvest()
void spin() { // add entropy and mix
ticks++;
int sample = 128;
for (int i = 0; i < 8; i++) { // update ~6/8 banks 8 times
read[ read[i] % 8] += (micros() % 128);
sample = analogRead( pins[i] ); // a read from each analog pin
read[ micros() % 8] += ( read[i] % 64 ); // mix timing and 6LSBs from read
read[i] += sample; // mix whole raw sample
read[(i + 1) % 8] += random(2147483647) % 1024; // mix prng
read[ticks % 8] += sample % 16; // mix the best nibble of the read
read[sample % 8] += read[ticks % 8] % 2147483647; // intra-mix banks
}
}//end spin()
void setup() {
Serial.begin(9600);
delay(222);
int mx = 2028 + ((analogRead(A0) + analogRead(A1) + analogRead(A2) + analogRead(A3)) % 256);
while (ticks < mx) {
spin();
delay(1);
randomSeed(read[2] + read[1] + read[0] + micros() + random(4096) + ticks);
}// wend
}// end setup()
void loop() {
spin();
delayMicroseconds((read[ micros() % 8] % 2048) + 333 );
delay(random(10));
//if (millis() < 500) return;
if ((ticks % 16) == (millis() % 16) ) harvest();
}// end loop()