randomSeed(analogRead(x))yalnızca 255 dizi sayı üretecek, bu da tüm kombinasyonları denemeyi ve çıktı akışınıza bağlanabilecek bir kârı üretmeyi önemsiz hale getirerek tüm çıktıyı% 100 tahmin ediyor. Ancak doğru yoldasınız, bu sadece bir sayı oyunu ve bunlardan çok daha fazlasına ihtiyacınız var. Örneğin, 4 ADC'den 100 analog okuma almak, hepsini toplamak ve bunu beslemek randomSeedçok daha iyi olurdu. Maksimum güvenlik için hem öngörülemeyen girdilere hem de deterministik olmayan karıştırmaya ihtiyacınız vardır.
Ben bir kriptograf değilim, ancak donanım ve yazılım rastgele jeneratörlerini araştırmak ve inşa etmek için binlerce saat harcadım, bu yüzden öğrendiklerimin bazılarını paylaşmama izin verin:
Öngörülemeyen Girdi:
- analogRead () (kayan pinlerde)
- GetTemp ()
Potansiyel Olarak Tahmin Edilemeyen Girdi:
- micros () (deterministik olmayan örnekleme periyodu hariç)
- saat titreşimi (düşük bant genişliği, ancak kullanılabilir)
- readVCC () (pille çalışmazsa)
Harici Tahmin Edilemeyen Girdi:
- sıcaklık, nem ve basınç sensörleri
- mikrofonlar
- LDR voltaj bölücüler
- ters yönlü transistör gürültüsü
- pusula / hızlanma titreşimi
- esp8266 wifi hotspot taraması (ssid, db, vb.)
- esp8266 zamanlaması (arka plan wifi görevleri planlanan mikroları yapar () belirsizdir)
- esp8266 HWRNG -
RANDOM_REG32son derece hızlı ve tahmin edilemez, 1 kademeli
toplama
Yapmak istediğiniz son şey, geldiği gibi entropi tükürmek. Bir bozuk parayı tahmin etmek bir kova madeni paradan daha kolaydır. Toplamak iyidir. unsigned long bank;o zaman sonra bank+= thisSample;iyidir; devrilir. bank[32]daha da iyi, okumaya devam edin. Her bir çıktı grubu için en az 8 girdi örneği toplamak istiyorsunuz, ideal olarak çok daha fazlası.
Zehirlenmeye karşı koruma
Tahtayı ısıtmak belirli bir maksimum saat titreşimine neden oluyorsa, bu bir saldırı vektörüdür. AnalogRead () girişlerine doğru patlayan RFI ile aynı. Başka bir yaygın saldırı sadece ünitenin fişini çekerek biriken tüm entropiyi boşaltır. Hız pahasına bile olsa güvenli olduğunu bilinceye kadar sayılar çıkarmamalısınız.
Eğer içine vb EEPROM, SD, Bak kullanarak, etrafında uzun vadeli bazı entropi tutmak istiyoruz nedeni budur Fortuna PRNG 32 banka kullanır, yarım güncellenen her biri genellikle daha önce biri. Bu, 32 bankaya makul bir sürede saldırmayı zorlaştırır.
İşlem
"Entropi" yi topladıktan sonra, onu temizlemeniz ve ters-ters bir şekilde girişten boşaltmanız gerekir. SHA / 1/256 bunun için iyidir. Düz metin güvenlik açığına sahip olmadığınız için hız için SHA1'i (hatta gerçekten MD5'i) kullanabilirsiniz. Hasat etmek için asla tam entopy bankasını kullanmayın ve DAİMA her zaman entropi banka değişikliği yapılmadan aynı çıktıları önlemek için çıktıya her zaman farklı bir "tuz" ekleyin: output = sha1( String(micros()) + String(bank[0]) + [...] );Sha işlevi hem girdileri gizler hem de çıktıyı beyazlatır, zayıf tohumlara karşı korur, düşük birikmiş ent ve diğer yaygın sorunlar.
Zamanlayıcı girişlerini kullanmak için, onları belirsiz yapmanız gerekir. Bu basit delayMicroseconds(lastSample % 255); bu da öngörülemeyen bir süreyi duraklatır ve "ardışık" saat okumasını farktan eşit olmayan bir şekilde yapar. if(analogRead(A1)>200){...}A1'in gürültülü olması veya dinamik bir girişe bağlanması koşuluyla bunu yarı düzenli olarak yapın . Akışınızın her bir çatalının belirlenmesini oldukça zorlaştırmak, ayrıştırılmış / yırtılmış çıktıda kriptoanalizi önleyecektir.
Gerçek güvenlik, saldırganın tüm sisteminizi tanıdığı ve üstesinden gelmek için hala çaresiz olduğu zamandır.
Son olarak, çalışmanızı kontrol edin. Çıktınızı ENT.EXE (nix / mac için de kullanılabilir) aracılığıyla çalıştırın ve bunun iyi olup olmadığını görün. En önemlisi, genellikle% 33 ile% 66 arasında olması gereken ki kare dağılımıdır. % 1.43 veya% 99.999 veya bunun gibi sinirli bir şey alırsanız, arka arkaya birden fazla test yaparsanız, rastgele boktur. Ayrıca entropi KBB raporlarını bayt başına mümkün olduğunca 8 bite yakın,> 7,9 kesin istersiniz.
TLDR: En basit aptalca yol ESP8266'nın HWRNG'sidir. Hızlı, tek tip ve öngörülemez. Ardunio çekirdeğini çalıştıran bir ESP8266'da böyle bir şey çalıştırın ve AVR ile konuşmak için seriyi kullanın:
// 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"
}
** Düzenle
Burada sadece bir koleksiyoncu olarak değil, seri porttan tüküren bir CSPRNG olan bir süre önce yazdığım çıplak tahta HWRNG çizimi. Bir pro-mini için üretilmiştir, ancak diğer kartlara kolayca uyarlanabilir olmalıdır. Sadece kayan analog pimleri kullanabilirsiniz, ancak bunlara, tercihen farklı şeyler eklemek daha iyidir. Mikrofonlar, LDR'ler, termistörler (oda sıcaklığına maksimum yayılmak üzere kesilmiş) ve hatta uzun teller gibi. Eğer orta derecede gürültüye sahipseniz, KBB'de oldukça iyi sonuç verir.
Taslak, cevap ve takip yorumlarımda bahsettiğim birkaç kavramı birleştiriyor: entropinin biriktirilmesi, ideal olmayan entropiden daha az örnekleme ile germe (von neumann serin olduğunu söyledi) ve tekdüzelik için karma. Entropi kalite tahminini "muhtemelen dinamik olan herhangi bir şeyi ver" ve kriptografik bir ilkel kullanarak karıştırma lehine terk eder.
// 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()