Sicherer "Zufall"?

Hallo zusammen

Schon einmal fragte ich hier, ob eine Verschlüsselungsidee, die ich hatte, gut ist. Das war Sie nicht, es mangelte bereits bei den Zufallswerten für die Schlüssel. Heut hab ich mich einmal NUR diesem "Problem" angenommen. Ich wüsste gerne, was Ihr davon haltet. :)

Ich bin nicht gerade der grösste Crypto-Mensch und denke, das es sowieso noch Verbesserungswürdig ist, obwohl ich für meinen Teil relativ zufrieden bin.

Code:
function randValue($min, $max, $hash){
	$ran = rand(100, substr(microtime(), 4, 9));
	for($i = 0; $i < $ran ; $i++){
		$t[] = chr(rand(1, 2000));
	}
	$endran = rand($min, $max);
	for($i = 0; $i < $endran; $i++){
		$end = $end.$t[$i];
	}
	if(!$hash){
		return $end;
	}
	else{
		$ok = false;
		$hash[2] = strtolower($hash[2]);
		foreach(hash_algos() as $algo){
			if($algo == $hash[2]){
			$ok = true;
			}
		}
		if($ok){
			$end = hash($hash[2], $end);
			for($i = 0; $i < $hash[1]; $i++){
				$add = hash($hash[2], $t[$i]);
				$end = $end.$add;
			}
			return $end;
		}
			else{
				return $end;
			}
	}
}
$hash[1] = 2;
$hash[2] = "SHA512";
echo (randValue(2, 1000, $hash));
 
Hallo,
Original von skamster19
Hallo zusammen

Schon einmal fragte ich hier, ob eine Verschlüsselungsidee, die ich hatte, gut ist. Das war Sie nicht, es mangelte bereits bei den Zufallswerten für die Schlüssel. Heut hab ich mich einmal NUR diesem "Problem" angenommen. Ich wüsste gerne, was Ihr davon haltet. :)

Ich bin nicht gerade der grösste Crypto-Mensch und denke, das es sowieso noch Verbesserungswürdig ist, obwohl ich für meinen Teil relativ zufrieden bin.
Das solltest du nicht sein, denn deine randValue ist leider totaler Mist.

Die PHP-Methode rand() (auch nicht mt_rand()) in PHP eignet sich eigentlich gar nicht für kryptographische Anwendungen und man kann diese total vergessen.
Zum einen ist die Seed des Zufallsgenerator viel zu kurz, ich mein nur 32 Bit => 2^32 mögliche randValue() Ergebnisse, dann ist die Seed auch leicht zu erraten, denn dafür wird nur die time + mircotime() verwendet, was schonmal sehr schlecht ist, wenn ein Angreifer den ungefähren Zeitraum der Erstellung kennt.
Dann kommt noch dazu, dass rand() (auch nicht mit_rand()) keine kryptograpisch sicheren Zufallszahlen bestimmt, d.h., es ist unter Umständen möglich, die Zufallsfolgen vorherzusagen.

Kurzum: Du kannst rand/mt_rand total vergessen.

Dann kommt es noch dazu, dass du die bereits schwache rand() Funktion noch katastrophal verwendest.
Du machst leider den Fehler, zu versuchen, möglichst kompliziert an Zufallszahlen zu kommen. Der größte Feind der Sicherheit ist aber die Komplexilität. Deswegen sollte man lieber auf irgendwelche verrückten Expertiemente verzichten und dies ganz schlicht machen.
Schleifen, die eine zufällige Anzahl an Durchlaufen durchlaufen sind sehr schwachsinnig.
Mal ganz davon abgesehen, dass deine Implementierung auch noch Fehlerhaft ist (was passiert, wenn z.B. $ran=543 aber $endran=1234?).



Fazit:
In PHP an gute Zufallszahlen zu kommen ist sehr sehr schwer. Das beste ist, du kannst /dev/random oder /dev/urandom auslesen.

Oder ansonsten generiert man einen String aus möglichst vielen Zufallsquellen und wendet dann einen Hash-Algorithmus (SHA1) darauf an.

PHP:
function randValue() {
  $string = microtime();
  $string .= rand().mt_rand().rand().mt_rand().rand().mt_rand();
  $string .= implode("", $_GLOBALS); //Hier evt. auf $_SERVER + $_GET + $_COOKIE umsteigen, wenn per $_POST viel übertragen wird
  $string .= memory_get_usage().memory_ get_ peak_ usage();
  $string .= getmygid().getmyinode().getmypid().getmyuid().implode("",@getrusage());

 //Evt. noch auf mcrypt_create_iv() zurückgreifen
 //Weitere 'zufällige' Werte die einem einfallen

 return sha1($string);
}

Ist nicht nur deutlich leichter zu verstehen, sondern auch noch deutlich sicherer.

Wobei wirklich sicher gegen Personen die den Verkehr mitschneiden, ist es auch nicht, da diese die Zeit+$_GET/$_SERVER etc. kennen, und die anderen Werte lassen sich meistens auch leicht erraten/bestimmen.
 
ich weiss, das es wahrscheinlich nicht das beste ist, aber als totalen mist würde ich es nicht bezeichnen!

ich frag mcih ein wenig, was sicherer ist.. ein 128 bit lange variable mit hexadezimalzahlen oder eine 128 bit lange variable mit allen zeichen aus der ascii-tabelle, die sha512-gehasht sind.

es sollte eine methode (wird noch in die klasse eingebaut) werden, die den programmierer bestimmen lässt, wie lange die variable wird und mit welche hashform diese gemacht wird.

und, vieleicht täusche ich mich, aber ist sha512 im gegensatz zu sha1 nicht noch ungeknackt? müsste der "cracker" nicht zuerst sha512 oder whirlpool (je nach wahl) auflösen?

mir gefällt die methode mit den ascii-zeichen eigentlich recht gut. oder täusche ich mich, wenn ich denke, das eine grössere vielfalt von zeichen sicherer ist?
 
Hallo,
also:
1. chr(rand(1, 2000)); ist totaler Unsinn, es gibt nur 256 Ascii Werte, weswegen das keinen Sinn macht, zufallszahlen bis 2000 zu verwenden.

und, vieleicht täusche ich mich, aber ist sha512 im gegensatz zu sha1 nicht noch ungeknackt? müsste der "cracker" nicht zuerst sha512 oder whirlpool (je nach wahl) auflösen?
Nein, ein Angreifer würde nicht sha512 o.ä. auflösen, sondern ______das_____ (!!!) entscheidene ist dein Entropy-Pool. Hast du einen großen entropy pool, d.h., viele zufällige, schwer/nicht erratbare Zufallsquellen, ist es nahezu ein Kinderspiel daraus 1 Zufallszahl zu erzeugen [*].
Man kann auf den entropy pool sogut wie jede Funktion verwenden, um eine gute Zufallszahl zu erhalten, solange die gesamte Eingabe gleichmäßig gewichtet wird (also nicht das die ersten 5 Bytes zu 99,9% das Ergebnis bestimmen). Selbst CRC32 o.ä. würde bei einem guten entropy pool keine Probleme erstellen.

Hat man stattdessen einen miserablen (=kleinen) entropy pool, wie z.B. es bei OpenSSL unter Debian war, nur 16 Bit, ist es absolut unmöglich daraus eine gute Zufallszahl zu gewinnen, egal welche weiteren Algorithmen und Tricks du anwendest.

Mal davon abgesehen das deine Implementierung haufenweise Fehler hat, ist dein entropy pool viel zu klein, um die Zufallszahl halbwegs ernst zu nehmen, da du dich ausschließlich auf die Seed von rand() verlässt, die nur 32 Bit beträgt.

Egal was du machst, könntest einen nachweisbar 100% sicheren Hash-Algorithmus verwenden (der nicht existiert), deine Zufallszahlen sind und bleiben miserabel. Über diese 32 Bit wirst du nicht herauskommen, sondern im Gegenteil, mit jeder weiteren Finesse reduzierst du potenziell die Anzahl an zufälligen Kombinationen.


mir gefällt die methode mit den ascii-zeichen eigentlich recht gut.
Mir eigentlich gar nicht.

oder täusche ich mich, wenn ich denke, das eine grössere vielfalt von zeichen sicherer ist?
Ja. Nur weil es scheinbar mehr Zeichen gibt, erhöht dies nicht die Anzahl an Kombinationen.
ASCII Zeichen ist nichts anderes als Representanten im 256er System.

Sagen wir du hast eine 32 Bit Zahl, ob du diese nun Binär, Dezimal oder Hexadezimal darstellen lässt, ändert dies nichts an der Anzahl der möglichen Kombinationen, was soweit hoffentlich klar ist.
Aber, wie erwähnt, sind ASCII (o.ä.) Zeichen nur Representanten im 256er System, ähnlich wie z.B. die 9 im Dez. System für etwas steht oder das A im Hexadezimalsystem.
Konvertierst du nun deine 32 Bit Zahl ins ASCII System, hast du im best case immer noch soviele Kombinationen, als hättest du die 32 Bit Zahl direkt verwendet.
Aber!!: Bei (der sinnlosen) Konvertierung können sehr schnell Informationen verloren gehen, womit sich die Anzahl der möglichen Kombinationen drastisch reduzieren kann.
Deswegen bringt solch eine ASCII Representation null Sicherheitsgewinn, sondern im Gegenteil, reduziert erheblich die Sicherheit deines Systems und es ist jedem unbedingt davon abzuraten, dieses zu verwenden.

Sollte eigentlich auch klar sein, dein Computer kann nur mit Binärzahlen etwas anfangen, und A ist im Speicher nichts anders als die Zahl 65 (Dez) oder 01000001 Binär. Weswegen sollte man also eine Zufallszahl, z.B. 99, in das ASCII Zeichen 'c' umwandeln, wenn 'c' im Speicher als 01100011 = 99 hinterlegt wird? Irgendwie schwachsinnig, oder?
Aber wie erwähnt, bei jeder dieser Konvertierung kann verlust entstehen, d.h. du könntest Zufallszahlen zwischen 0-100 erzeugen, aber evt. gibts nach der Konvertierung nur noch 80 Zahlen/Zeichen.


Ansonsten wie erwähnt: Das wichtigste ist nicht, welche tollen Hash-Algorithmus man bekommt, sondern wie groß der entropy pool ist. Bei deiner jetzigen Implementierung ist dieser 32 Bit groß (und mehr wird man ausschließlich rand() auch _nie_ erreichen), wobei deine sehr merkwürdigen Schleifen und konstrukte diesen entropy pool erheblich Reduzieren können (und wahrscheinlich auch tun).

Das primäre Ziel ist also, möglich viele Zufallsquellen zu bekommen, ich habe dir bereits einen Ansatz geliefert. Diese Zufallsquellen kann man dann z.B. per sha1() oder md5() zusammenfassen, um eine kürzer zufällige Zahl zu erhalten.
Ob sha1/md5 nun gebrochen ist oder nicht, was so nicht stimmt, ist egal, solange deine Funktion 'full diffusion' besitzt, d.h., alle Ausgangsbits beruhen auf allen Eingangsbits und nur 1 Bit-Änderung am Eingang ändert im Schnitt 50% der Ausgangsbits, und genau dieses bieten sha1/md5.


Ansonsten mehr zu Thema schau mal hier:
Cryptanalytic Attacks on Pseudorandom Number Generators


[*]: Wenn man nur 1 Zufallszahl aus einem entropy pool erzeugen möchte, ist dies recht leicht.
Oft möchte man aber mehrere Zufallszahlen hintereinander generieren, und da stellt sich dann die Frage wie man dieses macht.
Was man gut machen kann, ist per md5/sha1 aus allen Zufallsquellen einen zufälligen Wert erstellen und diesen dann als Seed für einen kryptographisch sicheren Pseudozufallsgenerator verwenden, sofern dieser z.B. nur eine 128 Bit seed erlaubt.
Ansonsten kann man die Zufallsquellen, sofern nicht zu groß, direkt als Seed verwenden.
In PHP ist das vorhaben deutlich schwieriger, da man in PHP selbst schlecht einen globalen Zufallsgenerator implementieren kann und man oft pro Script-Aufruf darauf angewiesen, den Zufallsgenerator neu zu initialisieren.
Wenn man nur 1 Zufallszahl braucht, kann man die obige Methode bedenkenlos verwenden. Benötigt man mehrere Werte, wäre eine Implementierung mit Gedächtnis nicht schlecht.

Könnte in etwa aussehen (ungetestet):
PHP:
<?php
$initialisieren = true;
$int_value = "";
$alt ="";

function randValue() {
   global $initialisieren, $alt, $int_value; 
   $string = $alt.microtime();  
   $string .= rand().mt_rand().rand().mt_rand().rand().mt_rand();
   $string .= memory_get_usage().memory_ get_ peak_ usage();
  
   if($initialisieren) {      
  $string .= implode("", $_GLOBALS); //Hier evt. auf $_SERVER + $_GET + $_COOKIE umsteigen, wenn per $_POST viel übertragen wird  
  $string .= getmygid().getmyinode().getmypid().getmyuid().implode("",@getrusage());

 //Evt. noch auf mcrypt_create_iv() zurückgreifen
 //Weitere 'zufällige' Werte die einem einfallen

  $int_value = sha1($string);
  $initialisieren = false;  
 } 

 $alt = sha1($string.$int_value);
 return $alt;
}
?>
 
wow, danke für die erklärung..

jetzt bleibt eig. nur noch eine frage..

was ist besser?

eher was al?

Code:
    $size = mcrypt_get_iv_size(MCRYPT_CAST_256, MCRYPT_MODE_CFB);
    $iv = mcrypt_create_iv($size, MCRYPT_DEV_RANDOM);

oder eher was al?

Code:
	$filename = "/dev/urandom";
	$handle = fopen ($filename, "r");
	$content = fread ($handle, mt_rand($min, $max));
	fclose ($handle);

?

ich denke, bei beiden braucht man leserechte für /dev/random, bsw urandom (wobei beide methoden ja auf beide dateien einsetzbar sind..)
 
Hallo,
sofern möglich, ist deutlich die 2. Variante zu empfehlen. An eine IV werden nicht die gleichen Anforderungen bzgl. Zufälligkeit gestellt wie an einen (zufälligen) Key.

Die IV nimmt man als bekannt an und trägt nicht zur sicherheit bei, deswegen gibts auch viele Anwendungen die als IV einen aufsteigende Nummer oder nur die Systemzeit verwenden, was auch ausreichend ist.
Bei Keys ist das anders.

Wie mcrypt nun genau die Zufallszahlen bekommt, kann ich nicht sagen, sollte es aber direkt aus /dev/urandom (bzw. /dev/random) auslesen, dann wären die Ansätze gleichwertig. Aber dafür kann man sich einfach mal den Source Code von Mcrypt angucken ;)

Was nun kompatibler ist, musst du selber testen, könnte mir aber vorstellen, dass mcrypt evt. mehr Rechte hat als der Script.

Das Problem ist aber leider, dass man oft keine Möglichkeit hat auf /dev/(u)random zuzugreifen, womit dies leider entfällt.
 
Zurück
Oben