HTTPS-Fehler im Link Indication Plugin

Ich setze bereits seit einer Weile das Link Indication Plugin ein, das externe Links mit einem Icon ergänzt, sodass man sie besser erkennen kann. Seitdem jedoch meine und immer mehr externe Seiten HTTPS statt HTTP verwenden, ist mir aufgefallen, dass die Icons nicht mehr angezeigt wurden.

Nun habe ich mir einfach mal den Quelltext des Plugins angesehen, um dem Problem auf die Schliche zu kommen. Und tatsächlich: ein winziger Bug ist der Auslöser des ganzen Problems. Diesen findet man in der Methode "GetDomainnameForUri()", die in der Version 4.4 wie folgt aussieht:

[cc lang="php"] /**
* Retrieve the domain name from the URI. We consider sub domains as well.
*/
function GetDomainnameFromUri($uri){
$exp1 = '/^(http|https|ftp)?(:\/\/)?(www.)?([^\/]+)/i';
preg_match($exp1, $uri, $matches);
if (isset($matches[4])) {
return $matches[4];
} else {
return '';
}
}[/cc]

Hier wird die URL anhand eines regulären Ausdrucks zerteilt. Das Problem ist der erste Teil des Ausdrucks ("(http|https|ftp)?"), der besagt, dass ein Treffer vorhanden ist, sobald entweder "http", "https" oder "ftp" gefunden wird. Leider liefert dieser Ausdruck sofort ein Ergebnis zurück, sobald es "http" gesehen hat, sodass das mittlere "https" nie betrachtet wird.

Um mir das genauer anzusehen, habe ich mir mal einen Testfall geschrieben:

[cc lang="php"][/cc]

Hier die zugehörigen Ergebnisse:

[cc lang="php"]Array
(
)
Array
(
[0] => example.com
[1] =>
[2] =>
[3] =>
[4] => example.com
)
Array
(
[0] => www.example.com
[1] =>
[2] =>
[3] => www.
[4] => example.com
)
Array
(
[0] => example.com
[1] =>
[2] =>
[3] =>
[4] => example.com
)
Array
(
[0] => www.example.com
[1] =>
[2] =>
[3] => www.
[4] => example.com
)
Array
(
[0] => http://example.com
[1] => http
[2] => ://
[3] =>
[4] => example.com
)
Array
(
[0] => http://www.example.com
[1] => http
[2] => ://
[3] => www.
[4] => example.com
)
Array
(
[0] => http://example.com
[1] => http
[2] => ://
[3] =>
[4] => example.com
)
Array
(
[0] => http://www.example.com
[1] => http
[2] => ://
[3] => www.
[4] => example.com
)
Array
(
[0] => https:
[1] => http
[2] =>
[3] =>
[4] => s:
)
Array
(
[0] => https:
[1] => http
[2] =>
[3] =>
[4] => s:
)
Array
(
[0] => https:
[1] => http
[2] =>
[3] =>
[4] => s:
)
Array
(
[0] => https:
[1] => http
[2] =>
[3] =>
[4] => s:
)[/cc]

Wie man sieht, wird durch den ersten Ausdruck ("(http|https|ftp)?") das "http" herausgetrennt, die nächsten beiden Ausdrücke ("(:\/\/)?" und "(www.)?") liefern leere Ergebnisse und erst der letzte Ausdruck ("([^\/]+)") fängt den Rest ab - allerdings nur bis zum ersten Slash. Dementsprechend heißen alle HTTPS-URLs nach dem Parsen nur noch "s:".

In dem Plugin konfiguriert man auch die Adresse seiner eigenen Website. Diese Konfiguration wird mit der gleichen Funktion bearbeitet. Wenn nun also die eigene Seite eine HTTPS-Adresse enthält und gleichzeitig ein externer Link eine HTTPS-Adresse enthält, so führen diese beiden unterschiedlichen Adressen zum selben Ergebnis "s:" in der Funktion "GetDomainnameFromUri()".

Ein weiteres Problem in dieser Funktion dürfte eher wenige Adressen treffen: Der dritte Ausdruck ("(www.)?") hat nämlich ein Problem - den Punkt. Bei regulären Ausdrücken steht der Punkt nicht einfach nur für das Zeichen ".", sondern für alle Zeichen. Daher muss er, wenn das Zeichen "." gemeint ist, escaped werden ("\.").

Nehmen wir mal ein Beispiel, wo dieser Bug zu Problem führt: Wenn ich beispielsweise die URL der Supportseite der IBM hernehme, so lautet diese "http://www.ibm.com/support/entry/portal/de/de". Wenn man diese jedoch besucht, wird man auf "http://www-947.ibm.com/support/entry/portal/support" weitergeleitet. Der Ausdruck ("(www.)?") erkennt nun jedoch "www-" und schneidet es weg. Übrig bleibt dann die nicht existente Domain "947.ibm.com":

[cc lang="php"]Array
(
[0] => http://www-947.ibm.com
[1] => http
[2] => ://
[3] => www-
[4] => 947.ibm.com
)[/cc]

Weiterhin kann die jetzige Funktion weder mit Authentisierungen, noch mit Portnummern umgehen. Diese werden einfach der Domain zugerechnet. Um das alles zu beheben, muss man den Ausdruck ein wenig abändern. Die neue Variante kann dann mit wesentlich mehr Fällen umgehen.

[cc lang="php"][/cc]

Hier dazu der entsprechende Output:

[cc lang="php"]Array
(
)
Array
(
[0] => example.com
[1] =>
[2] =>
[3] =>
[4] =>
[5] =>
[6] =>
[7] => example.com
)
Array
(
[0] => www.example.com
[1] =>
[2] =>
[3] =>
[4] =>
[5] =>
[6] =>
[7] => www.example.com
)
Array
(
[0] => example.com/example
[1] =>
[2] =>
[3] =>
[4] =>
[5] =>
[6] =>
[7] => example.com
[8] =>
[9] =>
[10] => /example
)
Array
(
[0] => www.example.com/example
[1] =>
[2] =>
[3] =>
[4] =>
[5] =>
[6] =>
[7] => www.example.com
[8] =>
[9] =>
[10] => /example
)
Array
(
[0] => http://example.com
[1] => http://
[2] => http://
[3] =>
[4] =>
[5] =>
[6] =>
[7] => example.com
)
Array
(
[0] => http://www.example.com
[1] => http://
[2] => http://
[3] =>
[4] =>
[5] =>
[6] =>
[7] => www.example.com
)
Array
(
[0] => http://example.com/example
[1] => http://
[2] => http://
[3] =>
[4] =>
[5] =>
[6] =>
[7] => example.com
[8] =>
[9] =>
[10] => /example
)
Array
(
[0] => http://www.example.com/example
[1] => http://
[2] => http://
[3] =>
[4] =>
[5] =>
[6] =>
[7] => www.example.com
[8] =>
[9] =>
[10] => /example
)
Array
(
[0] => https://example.com
[1] => https://
[2] => https://
[3] =>
[4] =>
[5] =>
[6] =>
[7] => example.com
)
Array
(
[0] => https://www.example.com
[1] => https://
[2] => https://
[3] =>
[4] =>
[5] =>
[6] =>
[7] => www.example.com
)
Array
(
[0] => https://example.com/example
[1] => https://
[2] => https://
[3] =>
[4] =>
[5] =>
[6] =>
[7] => example.com
[8] =>
[9] =>
[10] => /example
)
Array
(
[0] => https://www.example.com/example
[1] => https://
[2] => https://
[3] =>
[4] =>
[5] =>
[6] =>
[7] => www.example.com
[8] =>
[9] =>
[10] => /example
)
Array
(
[0] => //example.com
[1] => //
[2] =>
[3] => //
[4] =>
[5] =>
[6] =>
[7] => example.com
)
Array
(
[0] => user:password@example.com
[1] =>
[2] =>
[3] =>
[4] => user:password@
[5] => user
[6] => password
[7] => example.com
)
Array
(
[0] => example.com:80
[1] =>
[2] =>
[3] =>
[4] =>
[5] =>
[6] =>
[7] => example.com
[8] => :80
[9] => 80
)
Array
(
[0] => example.com/example?example=example
[1] =>
[2] =>
[3] =>
[4] =>
[5] =>
[6] =>
[7] => example.com
[8] =>
[9] =>
[10] => /example
[11] => ?example=example
[12] => example=example
)
Array
(
[0] => example.com/example#example
[1] =>
[2] =>
[3] =>
[4] =>
[5] =>
[6] =>
[7] => example.com
[8] =>
[9] =>
[10] => /example
[11] =>
[12] =>
[13] => #example
[14] => example
)[/cc]

Die eigentliche Methode sollte also nach Möglichkeit so aussen:

[cc lang="php"] /**
* Retrieve the domain name from the URI. We consider sub domains as well.
*/
function GetDomainnameFromUri($uri){
$exp1 = '/^(([^:]+:\/\/)|(\/\/))?(([^:]+):([^@]+)@)?([^:\/\?\#]+)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/i';
preg_match($exp1, $uri, $matches);
if (isset($matches[7])) {
return $matches[7];
} else {
return '';
}
}[/cc]

Ich habe diese neue Version nun bei mir im Einsatz und sie funktioniert so, wie die alte es von Anfang an hätte tun sollen. 🙂

Linkindikatorgrüße, Kenny

haveged: Entropiesammlung unter Linux

Vor ein paar Tagen hatte ich vorgestellt, wie man den Hardware-Zufallszahlengenerator des Raspberry Pi nutzen kann, um unter Linux weniger Probleme mit hängenden Kryptographievorgängen zu haben. Leider hat nicht jeder Linux-Server einen Hardware-Zufallszahlengenerator, der als Entropiequelle genutzt werden kann - also muss eine andere Quelle herhalten.

Glücklicherweise hat sich das französische Institut IRISA Anfang des Jahrtausends das HAVEGE-Verfahren (HArdware Volatile Entropy Gathering and Expansion) ausgedacht. Dieses basiert darauf, dass in modernen Computersystem unzählige verschiedene Hardwarezustände (Cache-Zustände, das Auftreten von Interrupts, etc.) dafür verantwortlich sind, dass der exakt gleiche Code im Micro- und Nanosekundenbereich unterschiedlich schnell abgearbeitet wird. Die Abweichungen, die bei einer entsprechenden Zeitmessung auftreten, sind - so die Erfinder - nahezu unmöglich zu erahnen oder gar zu reproduzieren. Genau diese Abweichungen wären daher eine gute Quelle für Entropie.

Zwar wird das originale HAVEGE seit Jahren nicht mehr weiterentwickelt, jedoch gibt es den Ableger haveged, der inzwischen in allen großen Distributionen enthalten sein sollte. Sollte deshalb, da z.B. RHEL (Red Hat Enterprise Linux) das Paket nicht standardmäßig mit ausliefert. Hier muss auf das EPEL-Projekt (Extra Packages for Enterprise Linux) des Fedora Project zurückgegriffen werden, das das Paket für RHEL 6 und für RHEL 7 pflegt (RHEL basiert auf Fedora). Die Installation ist dann recht einfach über den rpm-Befehl möglich.

Leider ist haveged zu Unrecht ein wenig in Verruf geraten. Hintergrund ist, dass PolarSSL mbed SSL im Dezember 2011 ein Security Advisory herausgegebene hatte. Diese SSL-Bibliothek verwendete bis dahin HAVEGE als alleinige Entropiequelle für Schlüsselerzeugungen und dergleichen. Jedoch stellte man fest, dass der RDTSC-Befehl, der zum exakten Zeitmessen verwendet wird, auf einigen virtualisierten Maschinen nur schlechte (und damit leicht reproduzierbare) Werte zurücklieferte.

Es ist daher potentiell sinnvoll, vor dem produktiven Einsatz zu prüfen, ob der RDTSC-Befehl korrekt funktioniert. Eine Möglichkeit ist, die Ausgabe von haveged durch einen dieharder Testlauf prüfen zu lassen. Hierzu muss man einfach haveged aufrufen und dessen Output in den Eingang von dieharder leiten:

[cc lang="bash"]sudo haveged -n 0 -f - | dieharder -g 200 -a[/cc]

Trotz der Vorsicht hat haveged auch einige Anhänger: So erklärt beispielsweise Heinlein Support (der Betreiber des sicheren E-Mail-Dienstes mailbox.org) den Einsatz von haveged in seinem Linux-Admin-Blog. Die Distribution SLES (SUSE Linux Enterprise Server) geht sogar noch einen Schritt weiter. Dort ist haveged seit der Version 11.1 standardmäßig installiert und seit der Version 11.2 auch standardmäßig aktiviert. Viele Linux-Administratoren verwenden also potentiell bereits haveged in ihrer Produktumgebung, ohne es überhaupt zu wissen.

Natürlich habe auch ich mir angesehen, ob ich haveged einsetzen kann. Um mir eine abschließende Meinung bilden zu können, habe ich auf jedem in Frage kommenden System den dieharder Testlauf durchgeführt. An dieser Stelle veröffentliche ich auch der Vollständigkeit halber die entsprechenden Ergebnisse.

Auf dem "BCM2835" des Raspberry Pi sehen die Ergebnisse gut aus:

[cc]#=============================================================================#
# dieharder version 3.31.1 Copyright 2003 Robert G. Brown #
#=============================================================================#
rng_name |rands/second| Seed |
stdin_input_raw| 8.48e+05 |3348700180|
#=============================================================================#
test_name |ntup| tsamples |psamples| p-value |Assessment
#=============================================================================#
diehard_birthdays| 0| 100| 100|0.45785536| PASSED
diehard_operm5| 0| 1000000| 100|0.60477535| PASSED
diehard_rank_32x32| 0| 40000| 100|0.29286920| PASSED
diehard_rank_6x8| 0| 100000| 100|0.23237712| PASSED
diehard_bitstream| 0| 2097152| 100|0.05506401| PASSED
diehard_opso| 0| 2097152| 100|0.77736890| PASSED
diehard_oqso| 0| 2097152| 100|0.62599391| PASSED
diehard_dna| 0| 2097152| 100|0.28611820| PASSED
diehard_count_1s_str| 0| 256000| 100|0.75847797| PASSED
diehard_count_1s_byt| 0| 256000| 100|0.27169177| PASSED
diehard_parking_lot| 0| 12000| 100|0.91232487| PASSED
diehard_2dsphere| 2| 8000| 100|0.94904496| PASSED
diehard_3dsphere| 3| 4000| 100|0.21628095| PASSED
diehard_squeeze| 0| 100000| 100|0.32795324| PASSED
diehard_sums| 0| 100| 100|0.00069872| WEAK
diehard_runs| 0| 100000| 100|0.76153066| PASSED
diehard_runs| 0| 100000| 100|0.97532990| PASSED
diehard_craps| 0| 200000| 100|0.69750059| PASSED
diehard_craps| 0| 200000| 100|0.70646049| PASSED
marsaglia_tsang_gcd| 0| 10000000| 100|0.12267708| PASSED
marsaglia_tsang_gcd| 0| 10000000| 100|0.19422474| PASSED
sts_monobit| 1| 100000| 100|0.76342910| PASSED
sts_runs| 2| 100000| 100|0.41068776| PASSED
sts_serial| 1| 100000| 100|0.43901131| PASSED
sts_serial| 2| 100000| 100|0.08832557| PASSED
sts_serial| 3| 100000| 100|0.84110757| PASSED
sts_serial| 3| 100000| 100|0.41468366| PASSED
sts_serial| 4| 100000| 100|0.72012668| PASSED
sts_serial| 4| 100000| 100|0.36171448| PASSED
sts_serial| 5| 100000| 100|0.81674015| PASSED
sts_serial| 5| 100000| 100|0.88818478| PASSED
sts_serial| 6| 100000| 100|0.97895561| PASSED
sts_serial| 6| 100000| 100|0.98733145| PASSED
sts_serial| 7| 100000| 100|0.72348815| PASSED
sts_serial| 7| 100000| 100|0.11691286| PASSED
sts_serial| 8| 100000| 100|0.61923729| PASSED
sts_serial| 8| 100000| 100|0.97185433| PASSED
sts_serial| 9| 100000| 100|0.75444842| PASSED
sts_serial| 9| 100000| 100|0.56167376| PASSED
sts_serial| 10| 100000| 100|0.99999103| WEAK
sts_serial| 10| 100000| 100|0.94590480| PASSED
sts_serial| 11| 100000| 100|0.91257068| PASSED
sts_serial| 11| 100000| 100|0.66909798| PASSED
sts_serial| 12| 100000| 100|0.86817154| PASSED
sts_serial| 12| 100000| 100|0.76794279| PASSED
sts_serial| 13| 100000| 100|0.40705505| PASSED
sts_serial| 13| 100000| 100|0.50118838| PASSED
sts_serial| 14| 100000| 100|0.61229062| PASSED
sts_serial| 14| 100000| 100|0.85491685| PASSED
sts_serial| 15| 100000| 100|0.91714380| PASSED
sts_serial| 15| 100000| 100|0.62863486| PASSED
sts_serial| 16| 100000| 100|0.79024560| PASSED
sts_serial| 16| 100000| 100|0.46711922| PASSED
rgb_bitdist| 1| 100000| 100|0.32027203| PASSED
rgb_bitdist| 2| 100000| 100|0.82936629| PASSED
rgb_bitdist| 3| 100000| 100|0.32836216| PASSED
rgb_bitdist| 4| 100000| 100|0.05014161| PASSED
rgb_bitdist| 5| 100000| 100|0.60319043| PASSED
rgb_bitdist| 6| 100000| 100|0.46447338| PASSED
rgb_bitdist| 7| 100000| 100|0.78238492| PASSED
rgb_bitdist| 8| 100000| 100|0.47473097| PASSED
rgb_bitdist| 9| 100000| 100|0.96469269| PASSED
rgb_bitdist| 10| 100000| 100|0.16923688| PASSED
rgb_bitdist| 11| 100000| 100|0.21372692| PASSED
rgb_bitdist| 12| 100000| 100|0.80306989| PASSED
rgb_minimum_distance| 2| 10000| 1000|0.10142178| PASSED
rgb_minimum_distance| 3| 10000| 1000|0.09184875| PASSED
rgb_minimum_distance| 4| 10000| 1000|0.75662814| PASSED
rgb_minimum_distance| 5| 10000| 1000|0.11774862| PASSED
rgb_permutations| 2| 100000| 100|0.52525569| PASSED
rgb_permutations| 3| 100000| 100|0.56127774| PASSED
rgb_permutations| 4| 100000| 100|0.66925921| PASSED
rgb_permutations| 5| 100000| 100|0.02115162| PASSED
rgb_lagged_sum| 0| 1000000| 100|0.76176860| PASSED
rgb_lagged_sum| 1| 1000000| 100|0.96497209| PASSED
rgb_lagged_sum| 2| 1000000| 100|0.43298109| PASSED
rgb_lagged_sum| 3| 1000000| 100|0.81781736| PASSED
rgb_lagged_sum| 4| 1000000| 100|0.62701591| PASSED
rgb_lagged_sum| 5| 1000000| 100|0.62074437| PASSED
rgb_lagged_sum| 6| 1000000| 100|0.39233421| PASSED
rgb_lagged_sum| 7| 1000000| 100|0.88875393| PASSED
rgb_lagged_sum| 8| 1000000| 100|0.56490272| PASSED
rgb_lagged_sum| 9| 1000000| 100|0.85420827| PASSED
rgb_lagged_sum| 10| 1000000| 100|0.90991238| PASSED
rgb_lagged_sum| 11| 1000000| 100|0.83617905| PASSED
rgb_lagged_sum| 12| 1000000| 100|0.10804203| PASSED
rgb_lagged_sum| 13| 1000000| 100|0.01520972| PASSED
rgb_lagged_sum| 14| 1000000| 100|0.35537614| PASSED
rgb_lagged_sum| 15| 1000000| 100|0.70361276| PASSED
rgb_lagged_sum| 16| 1000000| 100|0.57752259| PASSED
rgb_lagged_sum| 17| 1000000| 100|0.04567487| PASSED
rgb_lagged_sum| 18| 1000000| 100|0.99990241| WEAK
rgb_lagged_sum| 19| 1000000| 100|0.59703607| PASSED
rgb_lagged_sum| 20| 1000000| 100|0.01424569| PASSED
rgb_lagged_sum| 21| 1000000| 100|0.01190246| PASSED
rgb_lagged_sum| 22| 1000000| 100|0.28083614| PASSED
rgb_lagged_sum| 23| 1000000| 100|0.85922233| PASSED
rgb_lagged_sum| 24| 1000000| 100|0.74805305| PASSED
rgb_lagged_sum| 25| 1000000| 100|0.33664323| PASSED
rgb_lagged_sum| 26| 1000000| 100|0.68550123| PASSED
rgb_lagged_sum| 27| 1000000| 100|0.71237718| PASSED
rgb_lagged_sum| 28| 1000000| 100|0.47764816| PASSED
rgb_lagged_sum| 29| 1000000| 100|0.36902623| PASSED
rgb_lagged_sum| 30| 1000000| 100|0.70886921| PASSED
rgb_lagged_sum| 31| 1000000| 100|0.86385367| PASSED
rgb_lagged_sum| 32| 1000000| 100|0.93629132| PASSED
rgb_kstest_test| 0| 10000| 1000|0.16180294| PASSED
dab_bytedistrib| 0| 51200000| 1|0.54526159| PASSED
dab_dct| 256| 50000| 1|0.01211310| PASSED
Preparing to run test 207. ntuple = 0
dab_filltree| 32| 15000000| 1|0.28341243| PASSED
dab_filltree| 32| 15000000| 1|0.40586913| PASSED
Preparing to run test 208. ntuple = 0
dab_filltree2| 0| 5000000| 1|0.99340648| PASSED
dab_filltree2| 1| 5000000| 1|0.94767580| PASSED
Preparing to run test 209. ntuple = 0
dab_monobit2| 12| 65000000| 1|0.43391232| PASSED[/cc]

Mein Hauptserver (auf dem auch WeizenSpr.eu läuft) wird mit einem "Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz" betrieben. Auch dessen Überprüfung liefert gute Ergebnisse:

[cc]#=============================================================================#
# dieharder version 3.31.1 Copyright 2003 Robert G. Brown #
#=============================================================================#
rng_name |rands/second| Seed |
stdin_input_raw| 5.53e+07 |3948260661|
#=============================================================================#
test_name |ntup| tsamples |psamples| p-value |Assessment
#=============================================================================#
diehard_birthdays| 0| 100| 100|0.87942414| PASSED
diehard_operm5| 0| 1000000| 100|0.48126438| PASSED
diehard_rank_32x32| 0| 40000| 100|0.49454734| PASSED
diehard_rank_6x8| 0| 100000| 100|0.57071448| PASSED
diehard_bitstream| 0| 2097152| 100|0.05867636| PASSED
diehard_opso| 0| 2097152| 100|0.92742494| PASSED
diehard_oqso| 0| 2097152| 100|0.87263461| PASSED
diehard_dna| 0| 2097152| 100|0.41023900| PASSED
diehard_count_1s_str| 0| 256000| 100|0.56140444| PASSED
diehard_count_1s_byt| 0| 256000| 100|0.47686501| PASSED
diehard_parking_lot| 0| 12000| 100|0.59549008| PASSED
diehard_2dsphere| 2| 8000| 100|0.85268300| PASSED
diehard_3dsphere| 3| 4000| 100|0.21177774| PASSED
diehard_squeeze| 0| 100000| 100|0.22008717| PASSED
diehard_sums| 0| 100| 100|0.27919825| PASSED
diehard_runs| 0| 100000| 100|0.28528603| PASSED
diehard_runs| 0| 100000| 100|0.88804265| PASSED
diehard_craps| 0| 200000| 100|0.50789926| PASSED
diehard_craps| 0| 200000| 100|0.44794845| PASSED
marsaglia_tsang_gcd| 0| 10000000| 100|0.85094292| PASSED
marsaglia_tsang_gcd| 0| 10000000| 100|0.87826981| PASSED
sts_monobit| 1| 100000| 100|0.34667211| PASSED
sts_runs| 2| 100000| 100|0.87692980| PASSED
sts_serial| 1| 100000| 100|0.92230630| PASSED
sts_serial| 2| 100000| 100|0.42487308| PASSED
sts_serial| 3| 100000| 100|0.47201211| PASSED
sts_serial| 3| 100000| 100|0.45286777| PASSED
sts_serial| 4| 100000| 100|0.99293625| PASSED
sts_serial| 4| 100000| 100|0.95982278| PASSED
sts_serial| 5| 100000| 100|0.72869396| PASSED
sts_serial| 5| 100000| 100|0.15359933| PASSED
sts_serial| 6| 100000| 100|0.29986703| PASSED
sts_serial| 6| 100000| 100|0.90350707| PASSED
sts_serial| 7| 100000| 100|0.82937553| PASSED
sts_serial| 7| 100000| 100|0.69745997| PASSED
sts_serial| 8| 100000| 100|0.76976576| PASSED
sts_serial| 8| 100000| 100|0.94487729| PASSED
sts_serial| 9| 100000| 100|0.21190616| PASSED
sts_serial| 9| 100000| 100|0.95673394| PASSED
sts_serial| 10| 100000| 100|0.28956816| PASSED
sts_serial| 10| 100000| 100|0.59407297| PASSED
sts_serial| 11| 100000| 100|0.97436422| PASSED
sts_serial| 11| 100000| 100|0.68107472| PASSED
sts_serial| 12| 100000| 100|0.40336698| PASSED
sts_serial| 12| 100000| 100|0.80817356| PASSED
sts_serial| 13| 100000| 100|0.89780894| PASSED
sts_serial| 13| 100000| 100|0.97992817| PASSED
sts_serial| 14| 100000| 100|0.56469700| PASSED
sts_serial| 14| 100000| 100|0.75256118| PASSED
sts_serial| 15| 100000| 100|0.04120757| PASSED
sts_serial| 15| 100000| 100|0.21211072| PASSED
sts_serial| 16| 100000| 100|0.38377842| PASSED
sts_serial| 16| 100000| 100|0.44555996| PASSED
rgb_bitdist| 1| 100000| 100|0.81895044| PASSED
rgb_bitdist| 2| 100000| 100|0.64929431| PASSED
rgb_bitdist| 3| 100000| 100|0.65870845| PASSED
rgb_bitdist| 4| 100000| 100|0.56304051| PASSED
rgb_bitdist| 5| 100000| 100|0.75496902| PASSED
rgb_bitdist| 6| 100000| 100|0.06767649| PASSED
rgb_bitdist| 7| 100000| 100|0.30374549| PASSED
rgb_bitdist| 8| 100000| 100|0.65287829| PASSED
rgb_bitdist| 9| 100000| 100|0.77464639| PASSED
rgb_bitdist| 10| 100000| 100|0.25683681| PASSED
rgb_bitdist| 11| 100000| 100|0.65849822| PASSED
rgb_bitdist| 12| 100000| 100|0.50805413| PASSED
rgb_minimum_distance| 2| 10000| 1000|0.02681610| PASSED
rgb_minimum_distance| 3| 10000| 1000|0.22801930| PASSED
rgb_minimum_distance| 4| 10000| 1000|0.27927346| PASSED
rgb_minimum_distance| 5| 10000| 1000|0.43079185| PASSED
rgb_permutations| 2| 100000| 100|0.94898090| PASSED
rgb_permutations| 3| 100000| 100|0.11374383| PASSED
rgb_permutations| 4| 100000| 100|0.72305706| PASSED
rgb_permutations| 5| 100000| 100|0.20417740| PASSED
rgb_lagged_sum| 0| 1000000| 100|0.93883915| PASSED
rgb_lagged_sum| 1| 1000000| 100|0.38840055| PASSED
rgb_lagged_sum| 2| 1000000| 100|0.62008896| PASSED
rgb_lagged_sum| 3| 1000000| 100|0.99204256| PASSED
rgb_lagged_sum| 4| 1000000| 100|0.52115721| PASSED
rgb_lagged_sum| 5| 1000000| 100|0.22550225| PASSED
rgb_lagged_sum| 6| 1000000| 100|0.40715772| PASSED
rgb_lagged_sum| 7| 1000000| 100|0.58505397| PASSED
rgb_lagged_sum| 8| 1000000| 100|0.42592254| PASSED
rgb_lagged_sum| 9| 1000000| 100|0.34891085| PASSED
rgb_lagged_sum| 10| 1000000| 100|0.67645788| PASSED
rgb_lagged_sum| 11| 1000000| 100|0.92966912| PASSED
rgb_lagged_sum| 12| 1000000| 100|0.95439791| PASSED
rgb_lagged_sum| 13| 1000000| 100|0.39471972| PASSED
rgb_lagged_sum| 14| 1000000| 100|0.72890013| PASSED
rgb_lagged_sum| 15| 1000000| 100|0.22923887| PASSED
rgb_lagged_sum| 16| 1000000| 100|0.09437301| PASSED
rgb_lagged_sum| 17| 1000000| 100|0.03021647| PASSED
rgb_lagged_sum| 18| 1000000| 100|0.06593268| PASSED
rgb_lagged_sum| 19| 1000000| 100|0.73484274| PASSED
rgb_lagged_sum| 20| 1000000| 100|0.97718590| PASSED
rgb_lagged_sum| 21| 1000000| 100|0.83580287| PASSED
rgb_lagged_sum| 22| 1000000| 100|0.68984098| PASSED
rgb_lagged_sum| 23| 1000000| 100|0.34944142| PASSED
rgb_lagged_sum| 24| 1000000| 100|0.76720893| PASSED
rgb_lagged_sum| 25| 1000000| 100|0.99808427| WEAK
rgb_lagged_sum| 26| 1000000| 100|0.20922699| PASSED
rgb_lagged_sum| 27| 1000000| 100|0.18887164| PASSED
rgb_lagged_sum| 28| 1000000| 100|0.45387763| PASSED
rgb_lagged_sum| 29| 1000000| 100|0.31425341| PASSED
rgb_lagged_sum| 30| 1000000| 100|0.72639892| PASSED
rgb_lagged_sum| 31| 1000000| 100|0.69995471| PASSED
rgb_lagged_sum| 32| 1000000| 100|0.84789350| PASSED
rgb_kstest_test| 0| 10000| 1000|0.62218468| PASSED
dab_bytedistrib| 0| 51200000| 1|0.37714207| PASSED
dab_dct| 256| 50000| 1|0.81750713| PASSED
Preparing to run test 207. ntuple = 0
dab_filltree| 32| 15000000| 1|0.30697178| PASSED
dab_filltree| 32| 15000000| 1|0.70930339| PASSED
Preparing to run test 208. ntuple = 0
dab_filltree2| 0| 5000000| 1|0.87225976| PASSED
dab_filltree2| 1| 5000000| 1|0.78581557| PASSED
Preparing to run test 209. ntuple = 0
dab_monobit2| 12| 65000000| 1|0.00837857| PASSED[/cc]

Selbst auf meinen alten Mac Minis auf PowerPC-Basis ("PowerMac10,1 MacRISC3 Power Macintosh"), die bei mir Zuhause in einem Testcluster laufen, läuft haveged und liefert auch dort gute Ergebnisse:

[cc]#=============================================================================#
# dieharder version 3.31.1 Copyright 2003 Robert G. Brown #
#=============================================================================#
rng_name |rands/second| Seed |
stdin_input_raw| 3.14e+06 |4220874249|
#=============================================================================#
test_name |ntup| tsamples |psamples| p-value |Assessment
#=============================================================================#
diehard_birthdays| 0| 100| 100|0.57621219| PASSED
diehard_operm5| 0| 1000000| 100|0.32030487| PASSED
diehard_rank_32x32| 0| 40000| 100|0.50211874| PASSED
diehard_rank_6x8| 0| 100000| 100|0.33856755| PASSED
diehard_bitstream| 0| 2097152| 100|0.23514061| PASSED
diehard_opso| 0| 2097152| 100|0.99635255| WEAK
diehard_oqso| 0| 2097152| 100|0.07666882| PASSED
diehard_dna| 0| 2097152| 100|0.28750274| PASSED
diehard_count_1s_str| 0| 256000| 100|0.31583844| PASSED
diehard_count_1s_byt| 0| 256000| 100|0.53449657| PASSED
diehard_parking_lot| 0| 12000| 100|0.79252967| PASSED
diehard_2dsphere| 2| 8000| 100|0.67882318| PASSED
diehard_3dsphere| 3| 4000| 100|0.31379788| PASSED
diehard_squeeze| 0| 100000| 100|0.28002382| PASSED
diehard_sums| 0| 100| 100|0.18598691| PASSED
diehard_runs| 0| 100000| 100|0.98976058| PASSED
diehard_runs| 0| 100000| 100|0.94358199| PASSED
diehard_craps| 0| 200000| 100|0.78532168| PASSED
diehard_craps| 0| 200000| 100|0.71640173| PASSED
marsaglia_tsang_gcd| 0| 10000000| 100|0.93759598| PASSED
marsaglia_tsang_gcd| 0| 10000000| 100|0.88657019| PASSED
sts_monobit| 1| 100000| 100|0.36848114| PASSED
sts_runs| 2| 100000| 100|0.55771580| PASSED
sts_serial| 1| 100000| 100|0.96608134| PASSED
sts_serial| 2| 100000| 100|0.84005443| PASSED
sts_serial| 3| 100000| 100|0.81443597| PASSED
sts_serial| 3| 100000| 100|0.10575160| PASSED
sts_serial| 4| 100000| 100|0.32914026| PASSED
sts_serial| 4| 100000| 100|0.21924627| PASSED
sts_serial| 5| 100000| 100|0.22875732| PASSED
sts_serial| 5| 100000| 100|0.78557652| PASSED
sts_serial| 6| 100000| 100|0.21487008| PASSED
sts_serial| 6| 100000| 100|0.14747939| PASSED
sts_serial| 7| 100000| 100|0.16517074| PASSED
sts_serial| 7| 100000| 100|0.84180240| PASSED
sts_serial| 8| 100000| 100|0.36482950| PASSED
sts_serial| 8| 100000| 100|0.27419346| PASSED
sts_serial| 9| 100000| 100|0.12233420| PASSED
sts_serial| 9| 100000| 100|0.16885151| PASSED
sts_serial| 10| 100000| 100|0.03902614| PASSED
sts_serial| 10| 100000| 100|0.18952175| PASSED
sts_serial| 11| 100000| 100|0.94410153| PASSED
sts_serial| 11| 100000| 100|0.59201848| PASSED
sts_serial| 12| 100000| 100|0.33965647| PASSED
sts_serial| 12| 100000| 100|0.52757585| PASSED
sts_serial| 13| 100000| 100|0.34009610| PASSED
sts_serial| 13| 100000| 100|0.99834388| WEAK
sts_serial| 14| 100000| 100|0.96198264| PASSED
sts_serial| 14| 100000| 100|0.39290279| PASSED
sts_serial| 15| 100000| 100|0.97548718| PASSED
sts_serial| 15| 100000| 100|0.93903378| PASSED
sts_serial| 16| 100000| 100|0.98534676| PASSED
sts_serial| 16| 100000| 100|0.39565376| PASSED
rgb_bitdist| 1| 100000| 100|0.20773717| PASSED
rgb_bitdist| 2| 100000| 100|0.85032130| PASSED
rgb_bitdist| 3| 100000| 100|0.50838307| PASSED
rgb_bitdist| 4| 100000| 100|0.57233304| PASSED
rgb_bitdist| 5| 100000| 100|0.91002860| PASSED
rgb_bitdist| 6| 100000| 100|0.78087088| PASSED
rgb_bitdist| 7| 100000| 100|0.40799300| PASSED
rgb_bitdist| 8| 100000| 100|0.00745902| PASSED
rgb_bitdist| 9| 100000| 100|0.30916578| PASSED
rgb_bitdist| 10| 100000| 100|0.57590644| PASSED
rgb_bitdist| 11| 100000| 100|0.80634610| PASSED
rgb_bitdist| 12| 100000| 100|0.54261773| PASSED
rgb_minimum_distance| 2| 10000| 1000|0.59111346| PASSED
rgb_minimum_distance| 3| 10000| 1000|0.46887953| PASSED
rgb_minimum_distance| 4| 10000| 1000|0.94865190| PASSED
rgb_minimum_distance| 5| 10000| 1000|0.28414726| PASSED
rgb_permutations| 2| 100000| 100|0.75820306| PASSED
rgb_permutations| 3| 100000| 100|0.90669743| PASSED
rgb_permutations| 4| 100000| 100|0.47793456| PASSED
rgb_permutations| 5| 100000| 100|0.69969764| PASSED
rgb_lagged_sum| 0| 1000000| 100|0.26143346| PASSED
rgb_lagged_sum| 1| 1000000| 100|0.89175049| PASSED
rgb_lagged_sum| 2| 1000000| 100|0.96527229| PASSED
rgb_lagged_sum| 3| 1000000| 100|0.99757952| WEAK
rgb_lagged_sum| 4| 1000000| 100|0.47083477| PASSED
rgb_lagged_sum| 5| 1000000| 100|0.93046056| PASSED
rgb_lagged_sum| 6| 1000000| 100|0.09962939| PASSED
rgb_lagged_sum| 7| 1000000| 100|0.07011501| PASSED
rgb_lagged_sum| 8| 1000000| 100|0.23763444| PASSED
rgb_lagged_sum| 9| 1000000| 100|0.09943310| PASSED
rgb_lagged_sum| 10| 1000000| 100|0.79942404| PASSED
rgb_lagged_sum| 11| 1000000| 100|0.02056793| PASSED
rgb_lagged_sum| 12| 1000000| 100|0.56717544| PASSED
rgb_lagged_sum| 13| 1000000| 100|0.20265247| PASSED
rgb_lagged_sum| 14| 1000000| 100|0.90095804| PASSED
rgb_lagged_sum| 15| 1000000| 100|0.51364566| PASSED
rgb_lagged_sum| 16| 1000000| 100|0.36926201| PASSED
rgb_lagged_sum| 17| 1000000| 100|0.46713667| PASSED
rgb_lagged_sum| 18| 1000000| 100|0.94256711| PASSED
rgb_lagged_sum| 19| 1000000| 100|0.94338929| PASSED
rgb_lagged_sum| 20| 1000000| 100|0.92997203| PASSED
rgb_lagged_sum| 21| 1000000| 100|0.36046015| PASSED
rgb_lagged_sum| 22| 1000000| 100|0.83868968| PASSED
rgb_lagged_sum| 23| 1000000| 100|0.52879240| PASSED
rgb_lagged_sum| 24| 1000000| 100|0.61314936| PASSED
rgb_lagged_sum| 25| 1000000| 100|0.37027362| PASSED
rgb_lagged_sum| 26| 1000000| 100|0.81581312| PASSED
rgb_lagged_sum| 27| 1000000| 100|0.66953730| PASSED
rgb_lagged_sum| 28| 1000000| 100|0.28398670| PASSED
rgb_lagged_sum| 29| 1000000| 100|0.95750904| PASSED
rgb_lagged_sum| 30| 1000000| 100|0.94730710| PASSED
rgb_lagged_sum| 31| 1000000| 100|0.38254527| PASSED
rgb_lagged_sum| 32| 1000000| 100|0.88603434| PASSED
rgb_kstest_test| 0| 10000| 1000|0.41777521| PASSED
dab_bytedistrib| 0| 51200000| 1|0.51678719| PASSED
dab_dct| 256| 50000| 1|0.48530283| PASSED
Preparing to run test 207. ntuple = 0
dab_filltree| 32| 15000000| 1|0.09009306| PASSED
dab_filltree| 32| 15000000| 1|0.42145861| PASSED
Preparing to run test 208. ntuple = 0
dab_filltree2| 0| 5000000| 1|0.92140518| PASSED
dab_filltree2| 1| 5000000| 1|0.30032656| PASSED
Preparing to run test 209. ntuple = 0
dab_monobit2| 12| 65000000| 1|0.80367392| PASSED[/cc]

Gespannt war ich auf die Ergebnisse meiner vServer, da diese bei PolarSSL mbed SSL ja der Ursprung des Problems waren. Ich verwende einerseits ein System mit einem KVM-virtualisierten "Intel(R) Core(TM)2 Duo CPU T7700 @ 2.40GHz". Dessen Ergebnisse sehen gut aus:

[cc]#=============================================================================#
# dieharder version 3.31.1 Copyright 2003 Robert G. Brown #
#=============================================================================#
rng_name |rands/second| Seed |
stdin_input_raw| 3.91e+07 |2403861751|
#=============================================================================#
test_name |ntup| tsamples |psamples| p-value |Assessment
#=============================================================================#
diehard_birthdays| 0| 100| 100|0.39303888| PASSED
diehard_operm5| 0| 1000000| 100|0.74496497| PASSED
diehard_rank_32x32| 0| 40000| 100|0.13162974| PASSED
diehard_rank_6x8| 0| 100000| 100|0.72631428| PASSED
diehard_bitstream| 0| 2097152| 100|0.86273136| PASSED
diehard_opso| 0| 2097152| 100|0.56491165| PASSED
diehard_oqso| 0| 2097152| 100|0.72849597| PASSED
diehard_dna| 0| 2097152| 100|0.99485750| PASSED
diehard_count_1s_str| 0| 256000| 100|0.43930506| PASSED
diehard_count_1s_byt| 0| 256000| 100|0.50458767| PASSED
diehard_parking_lot| 0| 12000| 100|0.99584501| WEAK
diehard_2dsphere| 2| 8000| 100|0.26711806| PASSED
diehard_3dsphere| 3| 4000| 100|0.29934754| PASSED
diehard_squeeze| 0| 100000| 100|0.80469876| PASSED
diehard_sums| 0| 100| 100|0.87202688| PASSED
diehard_runs| 0| 100000| 100|0.48564911| PASSED
diehard_runs| 0| 100000| 100|0.72922679| PASSED
diehard_craps| 0| 200000| 100|0.33032863| PASSED
diehard_craps| 0| 200000| 100|0.83274474| PASSED
marsaglia_tsang_gcd| 0| 10000000| 100|0.29574332| PASSED
marsaglia_tsang_gcd| 0| 10000000| 100|0.05451073| PASSED
sts_monobit| 1| 100000| 100|0.77549456| PASSED
sts_runs| 2| 100000| 100|0.04823761| PASSED
sts_serial| 1| 100000| 100|0.64803972| PASSED
sts_serial| 2| 100000| 100|0.82585541| PASSED
sts_serial| 3| 100000| 100|0.30137477| PASSED
sts_serial| 3| 100000| 100|0.87316871| PASSED
sts_serial| 4| 100000| 100|0.62677898| PASSED
sts_serial| 4| 100000| 100|0.59645336| PASSED
sts_serial| 5| 100000| 100|0.35557699| PASSED
sts_serial| 5| 100000| 100|0.11323982| PASSED
sts_serial| 6| 100000| 100|0.21809822| PASSED
sts_serial| 6| 100000| 100|0.19746310| PASSED
sts_serial| 7| 100000| 100|0.97678137| PASSED
sts_serial| 7| 100000| 100|0.96862353| PASSED
sts_serial| 8| 100000| 100|0.27733624| PASSED
sts_serial| 8| 100000| 100|0.47827497| PASSED
sts_serial| 9| 100000| 100|0.26196595| PASSED
sts_serial| 9| 100000| 100|0.20901634| PASSED
sts_serial| 10| 100000| 100|0.69320465| PASSED
sts_serial| 10| 100000| 100|0.50087708| PASSED
sts_serial| 11| 100000| 100|0.87279703| PASSED
sts_serial| 11| 100000| 100|0.43184814| PASSED
sts_serial| 12| 100000| 100|0.74743591| PASSED
sts_serial| 12| 100000| 100|0.92912813| PASSED
sts_serial| 13| 100000| 100|0.76446984| PASSED
sts_serial| 13| 100000| 100|0.41474394| PASSED
sts_serial| 14| 100000| 100|0.43600274| PASSED
sts_serial| 14| 100000| 100|0.34892825| PASSED
sts_serial| 15| 100000| 100|0.39514554| PASSED
sts_serial| 15| 100000| 100|0.91420886| PASSED
sts_serial| 16| 100000| 100|0.12891027| PASSED
sts_serial| 16| 100000| 100|0.25502730| PASSED
rgb_bitdist| 1| 100000| 100|0.47587315| PASSED
rgb_bitdist| 2| 100000| 100|0.88458605| PASSED
rgb_bitdist| 3| 100000| 100|0.93845118| PASSED
rgb_bitdist| 4| 100000| 100|0.47849575| PASSED
rgb_bitdist| 5| 100000| 100|0.94374456| PASSED
rgb_bitdist| 6| 100000| 100|0.86572499| PASSED
rgb_bitdist| 7| 100000| 100|0.36333630| PASSED
rgb_bitdist| 8| 100000| 100|0.86103915| PASSED
rgb_bitdist| 9| 100000| 100|0.85522176| PASSED
rgb_bitdist| 10| 100000| 100|0.80240762| PASSED
rgb_bitdist| 11| 100000| 100|0.26687750| PASSED
rgb_bitdist| 12| 100000| 100|0.16549648| PASSED
rgb_minimum_distance| 2| 10000| 1000|0.14846931| PASSED
rgb_minimum_distance| 3| 10000| 1000|0.19988545| PASSED
rgb_minimum_distance| 4| 10000| 1000|0.80019487| PASSED
rgb_minimum_distance| 5| 10000| 1000|0.95158568| PASSED
rgb_permutations| 2| 100000| 100|0.78900739| PASSED
rgb_permutations| 3| 100000| 100|0.92360523| PASSED
rgb_permutations| 4| 100000| 100|0.06140726| PASSED
rgb_permutations| 5| 100000| 100|0.70150773| PASSED
rgb_lagged_sum| 0| 1000000| 100|0.23235455| PASSED
rgb_lagged_sum| 1| 1000000| 100|0.52120656| PASSED
rgb_lagged_sum| 2| 1000000| 100|0.22766934| PASSED
rgb_lagged_sum| 3| 1000000| 100|0.35038622| PASSED
rgb_lagged_sum| 4| 1000000| 100|0.26125845| PASSED
rgb_lagged_sum| 5| 1000000| 100|0.90298763| PASSED
rgb_lagged_sum| 6| 1000000| 100|0.61490761| PASSED
rgb_lagged_sum| 7| 1000000| 100|0.60879059| PASSED
rgb_lagged_sum| 8| 1000000| 100|0.95659464| PASSED
rgb_lagged_sum| 9| 1000000| 100|0.74259826| PASSED
rgb_lagged_sum| 10| 1000000| 100|0.16243170| PASSED
rgb_lagged_sum| 11| 1000000| 100|0.23525439| PASSED
rgb_lagged_sum| 12| 1000000| 100|0.06598475| PASSED
rgb_lagged_sum| 13| 1000000| 100|0.37754865| PASSED
rgb_lagged_sum| 14| 1000000| 100|0.83798493| PASSED
rgb_lagged_sum| 15| 1000000| 100|0.68802937| PASSED
rgb_lagged_sum| 16| 1000000| 100|0.75693641| PASSED
rgb_lagged_sum| 17| 1000000| 100|0.38717555| PASSED
rgb_lagged_sum| 18| 1000000| 100|0.98063976| PASSED
rgb_lagged_sum| 19| 1000000| 100|0.63458041| PASSED
rgb_lagged_sum| 20| 1000000| 100|0.50550447| PASSED
rgb_lagged_sum| 21| 1000000| 100|0.58518588| PASSED
rgb_lagged_sum| 22| 1000000| 100|0.67293855| PASSED
rgb_lagged_sum| 23| 1000000| 100|0.36934247| PASSED
rgb_lagged_sum| 24| 1000000| 100|0.24675910| PASSED
rgb_lagged_sum| 25| 1000000| 100|0.83818181| PASSED
rgb_lagged_sum| 26| 1000000| 100|0.07111015| PASSED
rgb_lagged_sum| 27| 1000000| 100|0.50390287| PASSED
rgb_lagged_sum| 28| 1000000| 100|0.07887294| PASSED
rgb_lagged_sum| 29| 1000000| 100|0.75449287| PASSED
rgb_lagged_sum| 30| 1000000| 100|0.99969858| WEAK
rgb_lagged_sum| 31| 1000000| 100|0.62793868| PASSED
rgb_lagged_sum| 32| 1000000| 100|0.44864440| PASSED
rgb_kstest_test| 0| 10000| 1000|0.25821702| PASSED
dab_bytedistrib| 0| 51200000| 1|0.65332597| PASSED
dab_dct| 256| 50000| 1|0.51773051| PASSED
Preparing to run test 207. ntuple = 0
dab_filltree| 32| 15000000| 1|0.99425590| PASSED
dab_filltree| 32| 15000000| 1|0.62049359| PASSED
Preparing to run test 208. ntuple = 0
dab_filltree2| 0| 5000000| 1|0.74836623| PASSED
dab_filltree2| 1| 5000000| 1|0.83701400| PASSED
Preparing to run test 209. ntuple = 0
dab_monobit2| 12| 65000000| 1|0.80371447| PASSED[/cc]

Und auch beim zweiten System mit einem KVM-virtualisierten "Intel(R) Xeon(R) CPU E5-2620 0 @ 2.00GHz" gibt es laut dieharder keine Beanstandungen:

[cc]#=============================================================================#
# dieharder version 3.31.1 Copyright 2003 Robert G. Brown #
#=============================================================================#
rng_name |rands/second| Seed |
stdin_input_raw| 1.88e+07 |3966886010|
#=============================================================================#
test_name |ntup| tsamples |psamples| p-value |Assessment
#=============================================================================#
diehard_birthdays| 0| 100| 100|0.86802201| PASSED
diehard_operm5| 0| 1000000| 100|0.93857016| PASSED
diehard_rank_32x32| 0| 40000| 100|0.21554659| PASSED
diehard_rank_6x8| 0| 100000| 100|0.02393864| PASSED
diehard_bitstream| 0| 2097152| 100|0.72146650| PASSED
diehard_opso| 0| 2097152| 100|0.75580499| PASSED
diehard_oqso| 0| 2097152| 100|0.12630607| PASSED
diehard_dna| 0| 2097152| 100|0.08318236| PASSED
diehard_count_1s_str| 0| 256000| 100|0.83369544| PASSED
diehard_count_1s_byt| 0| 256000| 100|0.98448502| PASSED
diehard_parking_lot| 0| 12000| 100|0.74074906| PASSED
diehard_2dsphere| 2| 8000| 100|0.27217962| PASSED
diehard_3dsphere| 3| 4000| 100|0.93449392| PASSED
diehard_squeeze| 0| 100000| 100|0.79591941| PASSED
diehard_sums| 0| 100| 100|0.08260342| PASSED
diehard_runs| 0| 100000| 100|0.55360622| PASSED
diehard_runs| 0| 100000| 100|0.10557804| PASSED
diehard_craps| 0| 200000| 100|0.77589877| PASSED
diehard_craps| 0| 200000| 100|0.85530453| PASSED
marsaglia_tsang_gcd| 0| 10000000| 100|0.98866347| PASSED
marsaglia_tsang_gcd| 0| 10000000| 100|0.68766275| PASSED
sts_monobit| 1| 100000| 100|0.61721117| PASSED
sts_runs| 2| 100000| 100|0.93200830| PASSED
sts_serial| 1| 100000| 100|0.74699081| PASSED
sts_serial| 2| 100000| 100|0.00364348| WEAK
sts_serial| 3| 100000| 100|0.09215616| PASSED
sts_serial| 3| 100000| 100|0.78527182| PASSED
sts_serial| 4| 100000| 100|0.12680579| PASSED
sts_serial| 4| 100000| 100|0.61424014| PASSED
sts_serial| 5| 100000| 100|0.16770237| PASSED
sts_serial| 5| 100000| 100|0.42085097| PASSED
sts_serial| 6| 100000| 100|0.75700309| PASSED
sts_serial| 6| 100000| 100|0.63826119| PASSED
sts_serial| 7| 100000| 100|0.59100282| PASSED
sts_serial| 7| 100000| 100|0.78513054| PASSED
sts_serial| 8| 100000| 100|0.69352480| PASSED
sts_serial| 8| 100000| 100|0.49332202| PASSED
sts_serial| 9| 100000| 100|0.68905397| PASSED
sts_serial| 9| 100000| 100|0.61441861| PASSED
sts_serial| 10| 100000| 100|0.85033554| PASSED
sts_serial| 10| 100000| 100|0.82637215| PASSED
sts_serial| 11| 100000| 100|0.87559146| PASSED
sts_serial| 11| 100000| 100|0.81872729| PASSED
sts_serial| 12| 100000| 100|0.24838052| PASSED
sts_serial| 12| 100000| 100|0.99588877| WEAK
sts_serial| 13| 100000| 100|0.93714484| PASSED
sts_serial| 13| 100000| 100|0.76441555| PASSED
sts_serial| 14| 100000| 100|0.88325579| PASSED
sts_serial| 14| 100000| 100|0.78308466| PASSED
sts_serial| 15| 100000| 100|0.70135646| PASSED
sts_serial| 15| 100000| 100|0.92951300| PASSED
sts_serial| 16| 100000| 100|0.33861480| PASSED
sts_serial| 16| 100000| 100|0.51384470| PASSED
rgb_bitdist| 1| 100000| 100|0.64691596| PASSED
rgb_bitdist| 2| 100000| 100|0.36340761| PASSED
rgb_bitdist| 3| 100000| 100|0.13662446| PASSED
rgb_bitdist| 4| 100000| 100|0.90561258| PASSED
rgb_bitdist| 5| 100000| 100|0.09774341| PASSED
rgb_bitdist| 6| 100000| 100|0.59992552| PASSED
rgb_bitdist| 7| 100000| 100|0.12886912| PASSED
rgb_bitdist| 8| 100000| 100|0.93601521| PASSED
rgb_bitdist| 9| 100000| 100|0.52751789| PASSED
rgb_bitdist| 10| 100000| 100|0.31254677| PASSED
rgb_bitdist| 11| 100000| 100|0.82136358| PASSED
rgb_bitdist| 12| 100000| 100|0.92595382| PASSED
rgb_minimum_distance| 2| 10000| 1000|0.79518024| PASSED
rgb_minimum_distance| 3| 10000| 1000|0.51397031| PASSED
rgb_minimum_distance| 4| 10000| 1000|0.47960772| PASSED
rgb_minimum_distance| 5| 10000| 1000|0.85165830| PASSED
rgb_permutations| 2| 100000| 100|0.50745829| PASSED
rgb_permutations| 3| 100000| 100|0.03006811| PASSED
rgb_permutations| 4| 100000| 100|0.59388689| PASSED
rgb_permutations| 5| 100000| 100|0.23065839| PASSED
rgb_lagged_sum| 0| 1000000| 100|0.67210966| PASSED
rgb_lagged_sum| 1| 1000000| 100|0.33918884| PASSED
rgb_lagged_sum| 2| 1000000| 100|0.75190558| PASSED
rgb_lagged_sum| 3| 1000000| 100|0.74416904| PASSED
rgb_lagged_sum| 4| 1000000| 100|0.70682671| PASSED
rgb_lagged_sum| 5| 1000000| 100|0.49242189| PASSED
rgb_lagged_sum| 6| 1000000| 100|0.84792761| PASSED
rgb_lagged_sum| 7| 1000000| 100|0.89892157| PASSED
rgb_lagged_sum| 8| 1000000| 100|0.38757664| PASSED
rgb_lagged_sum| 9| 1000000| 100|0.87685081| PASSED
rgb_lagged_sum| 10| 1000000| 100|0.87448998| PASSED
rgb_lagged_sum| 11| 1000000| 100|0.94552468| PASSED
rgb_lagged_sum| 12| 1000000| 100|0.69899097| PASSED
rgb_lagged_sum| 13| 1000000| 100|0.61052074| PASSED
rgb_lagged_sum| 14| 1000000| 100|0.40428246| PASSED
rgb_lagged_sum| 15| 1000000| 100|0.41357249| PASSED
rgb_lagged_sum| 16| 1000000| 100|0.50608073| PASSED
rgb_lagged_sum| 17| 1000000| 100|0.73579529| PASSED
rgb_lagged_sum| 18| 1000000| 100|0.88116866| PASSED
rgb_lagged_sum| 19| 1000000| 100|0.01969011| PASSED
rgb_lagged_sum| 20| 1000000| 100|0.93329549| PASSED
rgb_lagged_sum| 21| 1000000| 100|0.06482253| PASSED
rgb_lagged_sum| 22| 1000000| 100|0.67360224| PASSED
rgb_lagged_sum| 23| 1000000| 100|0.11912063| PASSED
rgb_lagged_sum| 24| 1000000| 100|0.62730850| PASSED
rgb_lagged_sum| 25| 1000000| 100|0.92150416| PASSED
rgb_lagged_sum| 26| 1000000| 100|0.88313859| PASSED
rgb_lagged_sum| 27| 1000000| 100|0.17009240| PASSED
rgb_lagged_sum| 28| 1000000| 100|0.52599929| PASSED
rgb_lagged_sum| 29| 1000000| 100|0.99966442| WEAK
rgb_lagged_sum| 30| 1000000| 100|0.66724337| PASSED
rgb_lagged_sum| 31| 1000000| 100|0.29408784| PASSED
rgb_lagged_sum| 32| 1000000| 100|0.67994300| PASSED
rgb_kstest_test| 0| 10000| 1000|0.09623650| PASSED
dab_bytedistrib| 0| 51200000| 1|0.97246947| PASSED
dab_dct| 256| 50000| 1|0.22118329| PASSED
Preparing to run test 207. ntuple = 0
dab_filltree| 32| 15000000| 1|0.89757812| PASSED
dab_filltree| 32| 15000000| 1|0.36526583| PASSED
Preparing to run test 208. ntuple = 0
dab_filltree2| 0| 5000000| 1|0.89963029| PASSED
dab_filltree2| 1| 5000000| 1|0.67162245| PASSED
Preparing to run test 209. ntuple = 0
dab_monobit2| 12| 65000000| 1|0.21033599| PASSED[/cc]

Warum also auf diese zusätzliche Entropiequelle verzichten? Diese wird sowieso nicht direkt genutzt, sondern nach /dev/random eingeleitet, mit dessen restlichen Entropiequellen gemischt, durch einen CSPRNG (Cryptographically Secure PseudoRandom Number Generator) geleitet und erst dieser Output wird verwendet. Bis ein Problem mit dem eigentlichen Verfahren von haveged gefunden wird, werde ich dieses jedenfalls nun auf meinen Systemen einsetzen.

Zeitmessende Grüße, Kenny

P.S.: Dass der Entropiepool leerläuft, kann man über folgenden Befehl beobachten:

[cc lang="bash"]cat /proc/sys/kernel/random/entropy_avail[/cc]

Hardware-Zufallszahlengenerator des Raspberry Pi nutzen

Bei Serversystemen hat man häufig das Problem, dass dem Zufallszahlengenerator nicht genug Nutzerinteraktionen zur Verfügung stehen, um ausreichend Entropie für den Zufallszahlengenerator zu sammeln. Das führt dann - je nach eingesetzter Software - zu hängenden SSH-Verbindungen, zu Timeouts bei HTTPS-Verbindungen oder anderen nicht reproduzierbaren Fehlern.

Aus diesem und anderen Gründen haben CPU-Hersteller begonnen, Hardware-Zufallszahlengeneratoren direkt in ihre Prozessoren zu integrieren. Bei Intel nennt sich diese Technologie "Secure Key" (vormals "Bull Mountain"), bei VIA ist sie als "PadLock" bekannt, einige Broadcom-SOCs haben einen Hardware-Zufallszahlengenerator und auch AMD Zen soll einen bekommen.

Spannenderweise enthält auch der Broadcom-Chip des Raspberry Pi einen Hardware-Zufallszahlengenerator, dessen erzeugte Zufallszahlen man in den Linux-Zufallszahlenpool einfließen lassen kann. Hierfür sind nur wenige Schritte notwendig.

Als erstes muss das entsprechende Kernel-Modul geladen werden. Die Distribution Raspbian liefert zwei Broadcom-Random-Number-Generator-Module mit aus: "bcm2708_rng" und "bcm2835_rng". Obwohl im Raspberry Pi ein Broadcom 2835 steckt, funktioniert in Raspbian nur das "bcm2708_rng" Kernelmodul korrekt (BCM2708 ist die SOC-Familie, zu der auch der BCM2835 gehört).

Überprüfen kann man das auch nochmal anhand der Ausgabe des Befehls:

[cc lang="bash"]cat /proc/cpuinfo[/cc]

In der erscheinenden Ausgabe wird die Hardware explizit als "BCM2708" benannt:

[cc]processor : 0
model name : ARMv6-compatible processor rev 7 (v6l)
BogoMIPS : 2.00
Features : half thumb fastmult vfp edsp java tls
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x0
CPU part : 0xb76
CPU revision : 7

Hardware : BCM2708
Revision : 000e
Serial : ****************[/cc]

Nun heißt es, das passende Kernelmodul zu laden. Testweise könnt ihr das mit folgendem Befehl tun:

[cc lang="bash"]sudo modprobe bcm2708_rng[/cc]

Wenn das ohne Fehler funktioniert hat, sollte nun das Character-Device-File "/dev/hwrng" existieren. Ist das der Fall, benötigt ihr noch die "rng-tools", die ihr einfach per "apt-get" installieren könnt:

[cc lang="bash"]sudo apt-get install rng-tools[/cc]

Nach der Installation sollten diese direkt automatisch starten. Ihr könnt zudem testen, ob diese auch ihre Arbeit verrichten. Dazu ruft ihr das "rngd" Tool im Foreground-Modus auf und beendet es wieder per CTRL+C:

[cc lang="bash"]sudo rngd -f
^C[/cc]

Euch sollten nun die verschiedensten Statistiken angezeigt werden, unter anderen, wieviele FIPS 140-2 Tests erfolgreich bestanden wurden (mit diesen wird die Qualität der Zufallszahlen ermittelt):

[cc]rngd 2-unofficial-mt.14 starting up...
entropy feed to the kernel ready
stats: bits received from HRNG source: 60064
stats: bits sent to kernel pool: 512
stats: entropy added to kernel pool: 512
stats: FIPS 140-2 successes: 3
stats: FIPS 140-2 failures: 0
stats: FIPS 140-2(2001-10-10) Monobit: 0
stats: FIPS 140-2(2001-10-10) Poker: 0
stats: FIPS 140-2(2001-10-10) Runs: 0
stats: FIPS 140-2(2001-10-10) Long run: 0
stats: FIPS 140-2(2001-10-10) Continuous run: 0
stats: HRNG source speed: (min=752.012; avg=782.220; max=807.043)Kibits/s
stats: FIPS tests speed: (min=5.249; avg=5.533; max=6.076)Mibits/s
stats: Lowest ready-buffers level: 2
stats: Entropy starvations: 0
stats: Time spent starving for entropy: (min=0; avg=0.000; max=0)us
Exiting...[/cc]

Wenn das alles funktioniert hat, könnt ihr die Verwendung des Kernel-Moduls permanent machen, indem ihr in die Datei "/etc/modules" eine neue Zeile mit dem Namen des Kernel-Moduls einfügt:

[cc]bcm2708_rng[/cc]

Na dann wünsche ich euch viel Spaß mit eurem eigenen Hardware-Zufallszahlengenerator. 🙂

Update:
Um sicherzugehen, dass die bereitgestellten Zufallszahlen wirklich eine gute Qualität haben, habe ich in der letzten Zeit den vollständigen Satz an Dieharder-Tests laufen lassen. Hierzu habe ich erst einmal Dieharder selbst installiert:

[cc lang="bash"]sudo apt-get install dieharder[/cc]

Da der Zufallszahlengenerator nicht sonderlich schnell ist, musste ich den Dieharder-Test via nohup starten. Dieses sorgt dafür, dass der Prozess weiterläuft, obwohl die SSH-Session, in der der Aufruf erfolgte, bereits geschlossen wurde. Der gesamte Dieharder-Testlauf dauerte den gesamten November über:

[cc lang="bash"]sudo nohup sh -c "cat /dev/hwrng | dieharder -g 200 -a"[/cc]

Die Ergebnisse der Dieharder-Tests sind aus meiner Sicht vielversprechend. Fast alle Testläufe wurden ohne Probleme bestanden. Lediglich zwei Testläufe zeigen ein "weak"-Ergebnis, was bei einem echten Zufallszahlengenerator jedoch durchaus mal vorkommen kann:

[cc]#=============================================================================#
# dieharder version 3.31.1 Copyright 2003 Robert G. Brown #
#=============================================================================#
rng_name |rands/second| Seed |
stdin_input_raw| 2.49e+04 |1848243654|
#=============================================================================#
test_name |ntup| tsamples |psamples| p-value |Assessment
#=============================================================================#
diehard_birthdays| 0| 100| 100|0.80754184| PASSED
diehard_operm5| 0| 1000000| 100|0.46154223| PASSED
diehard_rank_32x32| 0| 40000| 100|0.24741511| PASSED
diehard_rank_6x8| 0| 100000| 100|0.98544914| PASSED
diehard_bitstream| 0| 2097152| 100|0.74214657| PASSED
diehard_opso| 0| 2097152| 100|0.62926414| PASSED
diehard_oqso| 0| 2097152| 100|0.65459762| PASSED
diehard_dna| 0| 2097152| 100|0.05329859| PASSED
diehard_count_1s_str| 0| 256000| 100|0.93984253| PASSED
diehard_count_1s_byt| 0| 256000| 100|0.73264960| PASSED
diehard_parking_lot| 0| 12000| 100|0.82688871| PASSED
diehard_2dsphere| 2| 8000| 100|0.81340970| PASSED
diehard_3dsphere| 3| 4000| 100|0.81943245| PASSED
diehard_squeeze| 0| 100000| 100|0.20437793| PASSED
diehard_sums| 0| 100| 100|0.01259559| PASSED
diehard_runs| 0| 100000| 100|0.40514608| PASSED
diehard_runs| 0| 100000| 100|0.83339986| PASSED
diehard_craps| 0| 200000| 100|0.11679660| PASSED
diehard_craps| 0| 200000| 100|0.42675629| PASSED
marsaglia_tsang_gcd| 0| 10000000| 100|0.96356183| PASSED
marsaglia_tsang_gcd| 0| 10000000| 100|0.84443650| PASSED
sts_monobit| 1| 100000| 100|0.86875820| PASSED
sts_runs| 2| 100000| 100|0.76068017| PASSED
sts_serial| 1| 100000| 100|0.44501629| PASSED
sts_serial| 2| 100000| 100|0.08213384| PASSED
sts_serial| 3| 100000| 100|0.40056497| PASSED
sts_serial| 3| 100000| 100|0.84781124| PASSED
sts_serial| 4| 100000| 100|0.67540322| PASSED
sts_serial| 4| 100000| 100|0.67479165| PASSED
sts_serial| 5| 100000| 100|0.93910920| PASSED
sts_serial| 5| 100000| 100|0.78108786| PASSED
sts_serial| 6| 100000| 100|0.36072231| PASSED
sts_serial| 6| 100000| 100|0.10943079| PASSED
sts_serial| 7| 100000| 100|0.33454672| PASSED
sts_serial| 7| 100000| 100|0.84662732| PASSED
sts_serial| 8| 100000| 100|0.56239211| PASSED
sts_serial| 8| 100000| 100|0.85989154| PASSED
sts_serial| 9| 100000| 100|0.09053360| PASSED
sts_serial| 9| 100000| 100|0.76921152| PASSED
sts_serial| 10| 100000| 100|0.65164012| PASSED
sts_serial| 10| 100000| 100|0.98802936| PASSED
sts_serial| 11| 100000| 100|0.16490199| PASSED
sts_serial| 11| 100000| 100|0.43350451| PASSED
sts_serial| 12| 100000| 100|0.97347736| PASSED
sts_serial| 12| 100000| 100|0.35755776| PASSED
sts_serial| 13| 100000| 100|0.61727927| PASSED
sts_serial| 13| 100000| 100|0.70426071| PASSED
sts_serial| 14| 100000| 100|0.96653473| PASSED
sts_serial| 14| 100000| 100|0.72003802| PASSED
sts_serial| 15| 100000| 100|0.33951664| PASSED
sts_serial| 15| 100000| 100|0.65324653| PASSED
sts_serial| 16| 100000| 100|0.79539647| PASSED
sts_serial| 16| 100000| 100|0.29465210| PASSED
rgb_bitdist| 1| 100000| 100|0.29377788| PASSED
rgb_bitdist| 2| 100000| 100|0.26581318| PASSED
rgb_bitdist| 3| 100000| 100|0.68619130| PASSED
rgb_bitdist| 4| 100000| 100|0.65469598| PASSED
rgb_bitdist| 5| 100000| 100|0.94194728| PASSED
rgb_bitdist| 6| 100000| 100|0.06186682| PASSED
rgb_bitdist| 7| 100000| 100|0.99989483| WEAK
rgb_bitdist| 8| 100000| 100|0.94851172| PASSED
rgb_bitdist| 9| 100000| 100|0.55403191| PASSED
rgb_bitdist| 10| 100000| 100|0.42372957| PASSED
rgb_bitdist| 11| 100000| 100|0.69930031| PASSED
rgb_bitdist| 12| 100000| 100|0.10435458| PASSED
rgb_minimum_distance| 2| 10000| 1000|0.06686667| PASSED
rgb_minimum_distance| 3| 10000| 1000|0.73245892| PASSED
rgb_minimum_distance| 4| 10000| 1000|0.21902555| PASSED
rgb_minimum_distance| 5| 10000| 1000|0.98142677| PASSED
rgb_permutations| 2| 100000| 100|0.52202354| PASSED
rgb_permutations| 3| 100000| 100|0.01765637| PASSED
rgb_permutations| 4| 100000| 100|0.54444953| PASSED
rgb_permutations| 5| 100000| 100|0.98885119| PASSED
rgb_lagged_sum| 0| 1000000| 100|0.19012074| PASSED
rgb_lagged_sum| 1| 1000000| 100|0.52956823| PASSED
rgb_lagged_sum| 2| 1000000| 100|0.95958846| PASSED
rgb_lagged_sum| 3| 1000000| 100|0.95145243| PASSED
rgb_lagged_sum| 4| 1000000| 100|0.13284355| PASSED
rgb_lagged_sum| 5| 1000000| 100|0.50651321| PASSED
rgb_lagged_sum| 6| 1000000| 100|0.67578443| PASSED
rgb_lagged_sum| 7| 1000000| 100|0.28159075| PASSED
rgb_lagged_sum| 8| 1000000| 100|0.70439598| PASSED
rgb_lagged_sum| 9| 1000000| 100|0.95701984| PASSED
rgb_lagged_sum| 10| 1000000| 100|0.11591970| PASSED
rgb_lagged_sum| 11| 1000000| 100|0.79622842| PASSED
rgb_lagged_sum| 12| 1000000| 100|0.30363114| PASSED
rgb_lagged_sum| 13| 1000000| 100|0.66673746| PASSED
rgb_lagged_sum| 14| 1000000| 100|0.08939797| PASSED
rgb_lagged_sum| 15| 1000000| 100|0.15096120| PASSED
rgb_lagged_sum| 16| 1000000| 100|0.31977071| PASSED
rgb_lagged_sum| 17| 1000000| 100|0.27180216| PASSED
rgb_lagged_sum| 18| 1000000| 100|0.69988188| PASSED
rgb_lagged_sum| 19| 1000000| 100|0.47622405| PASSED
rgb_lagged_sum| 20| 1000000| 100|0.69420826| PASSED
rgb_lagged_sum| 21| 1000000| 100|0.99297760| PASSED
rgb_lagged_sum| 22| 1000000| 100|0.60131473| PASSED
rgb_lagged_sum| 23| 1000000| 100|0.62287604| PASSED
rgb_lagged_sum| 24| 1000000| 100|0.70013973| PASSED
rgb_lagged_sum| 25| 1000000| 100|0.65860222| PASSED
rgb_lagged_sum| 26| 1000000| 100|0.93448843| PASSED
rgb_lagged_sum| 27| 1000000| 100|0.99635422| WEAK
rgb_lagged_sum| 28| 1000000| 100|0.29584189| PASSED
rgb_lagged_sum| 29| 1000000| 100|0.81313054| PASSED
rgb_lagged_sum| 30| 1000000| 100|0.64124408| PASSED
rgb_lagged_sum| 31| 1000000| 100|0.94116582| PASSED
rgb_lagged_sum| 32| 1000000| 100|0.96364896| PASSED
rgb_kstest_test| 0| 10000| 1000|0.13971491| PASSED
dab_bytedistrib| 0| 51200000| 1|0.65378962| PASSED
dab_dct| 256| 50000| 1|0.86099385| PASSED
Preparing to run test 207. ntuple = 0
dab_filltree| 32| 15000000| 1|0.80254877| PASSED
dab_filltree| 32| 15000000| 1|0.56933154| PASSED
Preparing to run test 208. ntuple = 0
dab_filltree2| 0| 5000000| 1|0.71661701| PASSED
dab_filltree2| 1| 5000000| 1|0.34205581| PASSED
Preparing to run test 209. ntuple = 0
dab_monobit2| 12| 65000000| 1|0.80589488| PASSED[/cc]

Zufällige Grüße, Kenny

Kanboard und PHP 5.6

Vor ein paar Monaten hatte ich davon erzählt, worauf man achten muss, wenn man Roundcube mit PHP 5.6 betreiben will. Heute möchte ich einmal darauf eingehen, was es bedeutet, Kanboard unter PHP 5.6 zu betreiben.

Vorab: Wie der Name schon vermuten lässt, handelt es sich bei Kanboard um ein webbasiertes Kanban-Board. Damit ist es möglich, den Status von Aufgaben zu verfolgen. Die Verwendung von Kanban-Boards ist vielfältig - angefangen bei einfachen ToDo-Listen für die private Nutzung, über einfache Softwareentwicklungsprozesse bis hin zu ausgewachsenen Businessprozessen mit Freigaben lässt sich so einiges realisieren.

Kanboard Beispielübersichten Kanboard Beispielübersichten

Kanboard Beispielübersichten

Bisher habe ich als Kanban-Board das Produkt Atlassian Jira verwendet, das mit dem Plugin Greenhopper Jira Agile auch ein Kanban-Board anbot. Leider hat Atlassian sich dazu entschieden, Jira in drei getrennte Softwareprodukte aufzuspalten. Ihrer Meinung nach soll damit die User Experience verbessert werden, indem jede Variante spezifische Funktionen erhalten soll (Jira Software für Softwareentwicklungsprozesse, Jira Service-Desk für IT-Supportprozesse und Jira Core für Businessprozesse). Meiner Meinung nach versuchen sie damit, dreimal so viel Geld von ihren abhängigen Kunden abzugreifen, die bisher eine Lizenz für alle drei Nutzungsszenarien verwenden konnten.

Jedenfalls machte ich mich aufgrund dessen auf die Suche nach einem einfach handhabbaren Ersatz und wurde bei Kanboard fündig. Aufgrund seiner einfachen Struktur hat es leider ein paar fehlende Features, die jedoch im kleineren Nutzungsrahmen kein größeres Problem darstellen. Beispielsweise gibt es nur drei Rollen: Softwareadministrator (administriert Kanboard), Projektadministrator (legt neue Projekte an und administriert diese) und Projektmitglied (legt neue Tasks an und arbeitet diese ab). Jedes Projektmitglied kann beispielsweise jeden Task aus jedem Status in jeden Status versetzen und ebenso neue Tasks in jedem Status anlegen. Damit lassen sich beispielsweise keine Freigabeprozesse realisieren. Es wird wohl aber gerade an einem komplexeren Rollen-Rechte-Modell gearbeitet, sodass solche Dinge hoffentlich zukünftig ebenfalls abbildbar sind.

Aber kommen wir zum eigentlichen Problem: Kanboard ist in der Lage, E-Mail-Benachrichtigungen zu versenden. Dazu gibt es in der Konfigurationsdatei mehrere Parameter, mit denen der SMTP-Server einkonfiguriert werden kann. Leider wurde dabei jedoch nicht berücksichtigt, dass seit PHP 5.6 standardmäßig das Serverzertifikat bei TLS-Verbindungen überprüft wird. Erschwerend kommt hinzu, dass Kanboard als Mail-Framework SwiftMailer verwendet, das in der aktuellen Version 5.4.1 hartcodierte Socket-Parameter verwendet. Erst in der (seit Monaten nicht veröffentlichten) Version 5.4.2 soll das Problem wohl behoben werden.

Um also Kanboard trotzdem dazu zu bewegen, E-Mails über SMTPS zu versenden, muss man das mitgelieferte SwiftMailer-Framework selbst anpassen. Hierzu öffnet man die Datei "./kanboard/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php" und sucht die Methode "_establishSocketConnection()". In der Zeile 263 gibt es einen Aufruf zu "stream_socket_client()" und genau davor müssen wir folgenden Code einfügen:

[cc lang="php"]$options['ssl']['verify_peer'] = MAIL_SMTP_SSL_VERIFY_PEER;
$options['ssl']['peer_name'] = MAIL_SMTP_SSL_PEER_NAME;
$options['ssl']['ciphers'] = MAIL_SMTP_SSL_CIPHERS;
$options['ssl']['cafile'] = MAIL_SMTP_SSL_CAFILE;[/cc]

Im Anschluss daran kann die "./conf.php" um folgende Parameter erweitert werden:

[cc lang="php"]define("MAIL_SMTP_SSL_VERIFY_PEER", true);
define("MAIL_SMTP_SSL_PEER_NAME", "smtp.example.com");
define("MAIL_SMTP_SSL_CIPHERS", "HIGH:!aNULL:!eNULL:!3DES:!MD5:!RC4:@STRENGTH");
define("MAIL_SMTP_SSL_CAFILE", "/etc/ssl/certs/smtp-certificate-authority.pem");[/cc]

Wenn man diese Änderungen durchgeführt hat, werden die E-Mail-Benachrichtigungen, wie erwartet, verschickt. Natürlich habe ich zu dem Thema im Github-Repository von Kanboard schon ein entsprechendes Issue aufgemacht, allerdings wird es wohl noch ein wenig dauern, bis das Problem tatsächlich behoben worden ist.

Kanban-Grüße, Kenny

Java: Klasse mit korrektem Interface dynamisch laden

Bei größeren Anwendungen, die flexibel in verschiedenen Bereichen einsetzbar sein sollen, kommt schnell der Wunsch auf, diese erweiterbar zu gestalten, sodass andere Nutzer zur Not eigene Erweiterungen schreiben können. Java bietet hierfür mit seinen von Hause aus mitgebrachten Classloadern bereits die passende Grundlage - diese muss nur noch richtig zusammengesetzt werden.

Um das Vorgehen einmal darzustellen, habe ich ein kleines Projekt ("LoadClass") aufgesetzt, das aus drei Teilen besteht:

  • die Klassenbibliothek "lib", in der ein Interface definiert ist: Das Interface dient als Schnittstelle zwischen der eigentlichen Anwendung und der Erweiterung. Durch Zuhilfenahme eines Interfaces müssen die späteren Methodenaufrufe des Plugins nicht über Reflection realisiert werden.
  • die Klassenbibliothek "plugin", in der die Erweiterung implementiert ist: Die Erweiterung ist eine Klasse, die das Interface aus der Klassenbiliothek "lib" implementiert.
  • die Anwendung "app", die die eigentliche Anwendungslogik implementiert: Die Anwendung ist der eigentliche Nutznießer der Erweiterbarkeit. Sie lädt das Plugin und führt den darin enthaltenen Code aus.

Fangen wir mit der Implementierung der Klassenbibliothek "lib" an. Die beschriebenen Schritte sind beispielhaft für die Entwicklungsumgebung Netbeans, sollten in anderen IDEs jedoch genauso einfach umsetzbar sein.

  1. Zuerst legen wir ein neues Projekt an und wähle als Projektart "Java Class Library" aus. Als Projektnamen vergeben wir einfach den Namen "lib".
  2. Als nächstes legen wir im Projekt eine neue Datei an und wähle als Typ das "Java Package" aus. Als Namen erhält es in diesem Beispiel "com.example.loadclass.lib".
  3. Innerhalb des Packages wiederum legen wir eine neue Datei vom Typ "Java Interface" an. Die Klasse erhält den Namen "ExampleInterface."
  4. Der Inhalt der Interface-Datei ist in diesem Beispiel minimal: [cc lang="java"]package com.example.loadclass.lib;

    public interface ExampleInterface {

    public String returnValue();

    }[/cc]

Nun machen wir weiter mit der Implementierung des Plugins.

  1. Wir legen ein weiteres Projekt an und wähle als Projektart wieder die "Java Class Library" aus. Als Projektnamen vergeben wir dieses Mal den Namen "plugin".
  2. Mit einem Rechtsklick auf den Projekteintrag im Projektbrowser gehen wir auf "Properties" und im Konfigurationsfenster auf die Kategorie "Libraries". Hier können wir über "Add Project..." nun das vorhin angelegte Projekt "lib" als Abhängigkeit aufnehmen. Nach einem Klick auf "OK" geht es weiter.
  3. Wir legen im Projekt eine neue Datei an und wählen als Typ das "Java Package" aus. Als Namen erhält es nun "com.example.loadclass.plugin".
  4. Innerhalb des Packages legen wir eine neue Datei vom Typ "Java Class" an. Die Klasse erhält den Namen "ExamplePlugin."
  5. Die Funktion des Plugins ist entsprechend des Interfaces ebenfalls minimal: [cc lang="java"]package com.example.loadclass.plugin;

    import com.example.loadclass.lib.ExampleInterface;

    public class ExamplePlugin implements ExampleInterface {

    @Override
    public String returnValue() {
    return "Hello world!";
    }

    }[/cc]

Bis hierhin gibt es, abgesehen davon, dass wir Interface und Implementierung in eigene Projekte auslagern, wenig Neues im Vergleich zu einer einfachen Java-Anwendung. Spannend wird es in der eigentlichen Anwendung, die wir nun anlegen.

  1. Wir legen ein weiteres Projekt an und wählen nun als Typ die "Java Application" aus. Als Namen erhält das Projekt dieses Mal den Wert "app". Zudem wählen wir aus, dass eine Main-Klasse mit dem Namen "com.example.loadclass.app.Main" erstellt werden soll. Das daraus entstehende Gerüst ist ziemlich schmalspurig: [cc lang="java"]package com.example.loadclass.app;

    public class Main {

    public static void main(String[] args) {
    }

    }[/cc]

  2. Als nächsten Schritt machen wir wieder einen Rechtsklick auf den Projekteintrag im Projektbrowser, gehen auf "Properties" und im Konfigurationsfenster auf die Kategorie "Libraries". Über "Add Project..." nehmen wir das Projekt "lib" wieder als Abhängigkeit auf und klicken abschließend auf "OK".
  3. In die Main-Klasse nehmen wir nun als erstes ein paar Definitionen auf, die später in den Methoden benötigt werden. [cc lang="java"] protected static final String LOADCLASS_CLASS_EXTENSION = ".class";
    protected static final char LOADCLASS_CLASS_SEPARATOR = '.';
    protected static final String LOADCLASS_JAR_EXTENSION = ".jar";
    protected static final char LOADCLASS_PATH_SEPARATOR = '@';
    protected static final String LOADCLASS_URL_PREFIX = "file://";

    protected static final String APP_PLUGIN_CLASS = "com.example.loadclass.plugin.ExamplePlugin";
    protected static final String APP_PLUGIN_JAR = "/Users/kenny/Desktop/loadClass/plugin/dist/plugin.jar";
    protected static final String APP_PLUGIN_PATH = APP_PLUGIN_CLASS + "@" + APP_PLUGIN_JAR;[/cc]

  4. Als nächstes fügen wir mehrere Methoden hinzu. Die erste dient dazu, herauszufinden, ob ein angegebener Plugin-Pfad tatsächlich korrekt ist. Als Pluginpfad verwenden wir an dieser Stelle die Form "<Klassenname>@<Bibliothekspfad>". Das bedeutet beispielsweise auch, dass wir sicherheitshalber in einer *.jar Datei nach der angegebenen Klassendatei suchen. [cc lang="java"] // structure is "@", where "" may be a folder or a *.jar file
    public static boolean checkName(String aString) {
    boolean lResult = false;

    if (null != aString) {
    // the combinator must not be at the very beginning or at the very end
    if ((aString.indexOf(LOADCLASS_PATH_SEPARATOR) > 0) &&
    (aString.indexOf(LOADCLASS_PATH_SEPARATOR) < aString.length()-1)) { String lClassName = aString.substring(0, aString.indexOf(LOADCLASS_PATH_SEPARATOR)); String lPathName = aString.substring(aString.indexOf(LOADCLASS_PATH_SEPARATOR)+1); File lPath = new File(lPathName); if (lPath.exists()) { if (lPath.isFile()) { if (lPathName.endsWith(LOADCLASS_JAR_EXTENSION)) { try (JarFile lJarFile = new JarFile(lPath)) { if (null != lJarFile.getJarEntry(lClassName.replace(LOADCLASS_CLASS_SEPARATOR, File.separatorChar) + LOADCLASS_CLASS_EXTENSION)) { lResult = true; } } catch (Exception lException) {} } } else { if (lPath.isDirectory()) { // fix path delimiter if (File.separatorChar != lPathName.charAt(lPathName.length()-1)) { lPathName = lPathName + File.separator; } // check if the class exists lPath = new File(lPathName + lClassName.replace(LOADCLASS_CLASS_SEPARATOR, File.separatorChar) + LOADCLASS_CLASS_EXTENSION); if (lPath.isFile()) { lResult = true; } } } } } } return lResult; }[/cc]

  5. Wenn wir sicher sind, dass wir eine Klasse laden könnten, gehen wir den nächsten Schritt und tun das auch. Hierfür verwenden wir den URLClassLoader, der neben Ordnern und *.jar Dateien auch mit Webressourcen umgehen kann (die wir an dieser Stelle jedoch nicht verwenden). [cc lang="java"] public static Class loadClass(String aName) {
    Class lResult = null;

    if (checkName(aName)) {
    // get name parts of parameter
    String lClassName = aName.substring(0, aName.indexOf(LOADCLASS_PATH_SEPARATOR));
    String lPathName = aName.substring(aName.indexOf(LOADCLASS_PATH_SEPARATOR)+1);

    // check that directory name ends with path separator
    if (new File(lPathName).isDirectory()) {
    if (File.separatorChar != lPathName.charAt(lPathName.length()-1)) {
    lPathName = lPathName + File.separator;
    }
    }

    try {
    URL lURL = new URL(LOADCLASS_URL_PREFIX + lPathName);

    URLClassLoader lClassLoader = new URLClassLoader(new URL[]{lURL},
    ClassLoader.getSystemClassLoader());

    lResult = lClassLoader.loadClass(lClassName);
    } catch (Exception lException) {}
    }

    return lResult;
    }[/cc]

  6. Mit dem Laden der Klasse ist es jedoch noch nicht getan, denn wir wollen ja schlussendlich eine Instanz der geladenen Klasse erhalten. Hierbei sollten wir natürlich prüfen, dass die geladene Klasse das erwartete Interface auch tatsächlich implementiert hat. [cc lang="java"] protected static Object createObject(String aName, Class aInterface) {
    Object lResult = null;

    if (null != aInterface) {
    Class lClass = loadClass(aName);
    if (null != lClass) {
    boolean lCorrectInterface = false;

    for (Class lInterface : lClass.getInterfaces()) {
    if (aInterface.equals(lInterface)) {
    lCorrectInterface = true;
    break;
    }
    }

    if (lCorrectInterface) {
    try {
    lResult = lClass.newInstance();
    } catch (Exception lException) {}
    }
    }
    }

    return lResult;
    }[/cc]

  7. Mit Hilfe dieser Methoden können wir unsere main() Methode nun so erweitern, dass wir die angegebene Klasse aus ihrer Bibliothek laden, instanziieren und auch nutzen. [cc lang="java"] public static void main(String[] args) {
    ExampleInterface lObject = (ExampleInterface)createObject(APP_PLUGIN_PATH,
    ExampleInterface.class);
    if (null != lObject) {
    System.out.println(lObject.returnValue());
    }
    }[/cc]
  8. Sollte sich eure IDE nicht automatisch um das Einfügen benötigter Import-Befehle kümmern, müsst ihr diese selbst ergänzen. [cc lang="java"]import com.example.loadclass.lib.ExampleInterface;
    import java.io.File;
    import java.net.URL;
    import java.net.URLClassLoader;
    import java.util.jar.JarFile;[/cc]

Wenn ihr alles korrekt zusammengefügt habt und die Pakete alle einmal erzeugt habt ("lib.jar", "plugin.jar" und "app.jar"), müsst ihr euch ansehen, unter welchem Dateipfad das Plugin-Paket erreichbar ist (in meinem Beispiel ist es "/Users/kenny/Desktop/loadClass/plugin/dist/plugin.jar"). Diesen vollständigen Pfad müsst ihr in die Variable "APP_PLUGIN_JAR" schreiben. In einem tatsächlichen Anwendungsfall würde man solche Informationen dann wahrscheinlich eher aus einer Konfigurationsdatei auslesen.

Wie gezeigt, ist es dank der vielen Hilfsmittel der Java Runtime recht einfach möglich, eine erweiterbare Anwendung zu implementieren. Voraussetzung ist, dass man die Hilfsmittel kennt und sie richtig zusammenfügen kann.

Dynamische Kaffee-Grüße, Kenny

P.S.: Der Code wurde nur unter unixoiden Betriebssystemen getestet. Wenn ein Windows-Nutzer einen Test damit durchführen sollte, würde ich mich freuen, zu erfahren, ob er auf Anhieb funktioniert hat. 🙂

Seite 3 von 87« Erste...234...Letzte »