Fragen? Antworten! Siehe auch: Alternativlos
libsodium nimmt man, weil das API so brutal einfach ist. Da kann man nicht viel falsch machen.
Du willst einen Buffer signieren?
crypto_sign(signed_message, &signed_message_len, MESSAGE, MESSAGE_LEN, secret_key);Der tut unter der Haube, was man erwarten würde: SHA512 über den Buffer, dann Ed25519 über den Hash. Dann gibt er einem im Zielbuffer die Signatur und dahinter die signierten Daten.
Du willst einen Buffer signieren, aber nur die Signatur haben?
crypto_sign_detached(sig, &sig_len, MESSAGE, MESSAGE_LEN, secret_key);Die Nachricht passt nicht in den Speicher, du willst die stückweise signieren? Kein Problem!
crypto_sign_init(&state);Das ideale API, um es Leuten in die Hand zu drücken, und "mach mal" zu sagen.
crypto_sign_update(&state, MESSAGE_PART1, MESSAGE_PART1_LEN);
crypto_sign_update(&state, MESSAGE_PART2, MESSAGE_PART2_LEN);
crypto_sign_final_create(&state, sig, &sig_len, secret_key);
Bis … ja bis die Leute dann eine Signatur mit crypto_sign_detached erzeugen und dann auf der Gegenseite mit der Multi-Chunk-Validierungsfunktion prüfen wollen. Denn dann failed die Validierung.
Ich hab also mal ein bisschen in den Quelle von libsodium herumgepopelt. Alle drei Funktionen machen SHA512 über den Buffer und dann Ed25519 über das Ergebnis davon. Aber das Multi-Chunk-API hasht vor dem Buffer noch einen konstanten String:
static const unsigned char DOM2PREFIX[32 + 2] = {Nun bin ich kein Kryptologe, aber aus meiner Sicht ergibt das überhaupt gar keinen Sinn. Hash-APIs gibt es seit vielen Jahren, und da hat es noch nie eine Rolle gespielt, ob man die Daten in einer oder in 15 Raten einzahlt.
'S', 'i', 'g', 'E', 'd', '2', '5', '5', '1', '9', ' ',
'n', 'o', ' ',
'E', 'd', '2', '5', '5', '1', '9', ' ',
'c', 'o', 'l', 'l', 'i', 's', 'i', 'o', 'n', 's', 1, 0
};
Tja, libsodium. Damit habt ihr den Hauptgrund weggeschossen, wieso ich euch immer empfohlen habe. Weil eure APIs einfach und unüberraschend aussahen. Das ist übrigens absichtlich so. Die libsodium-Doku sagt dazu:
Note: Ed25519ph(m) is intentionally not equivalent to Ed25519(SHA512(m)).
Oh ach so. Na DANN ist ja alles gut.m(
Update: Der Autor von libsodium erklärt:
The prefix is mandated by the specification: https://tools.ietf.org/html/rfc8032#section-5.1.
Ja, schon, aber dann nenne das API halt anders, wenn das eine andere Sache tut als was der Name impliziert.
Update: Ich habe den DOM2PREFIX da explizit gepasted, weil man das viel besser machen kann. Ein Leser weist mich jetzt darauf hin, dass das vielleicht nicht alle wissen. Hier:
static const unsigned char DOM2PREFIX[] = {
"SigEd25519 "
"no "
"Ed25519 "
"collisions\x01"
};
Oder halt in einer Zeile.
Update: Der technische Hintergrund ist übrigens, dass crypto_sign_detached die Nachricht zweimal hashen will. Beim ersten Mal fällt eine Nonce raus, mit der macht man eine Berechnung und die hasht man dann und dahinter nochmal die Nachricht. Da lässt sich Chunking nicht mal eben einbauen. Daher macht das Chunking-API was anderes: Einmal die Nachricht hashen und dann crypto_sign_detached auf den Hash der Nachricht. Und so haben wir eine Situation, in der eine syntaktische Änderung (ich möchte das mal mit "Leerzeile in Code einfügen" oder "Kommentar editieren") überraschend die Semantik ändert. Und das kann man nur fixen, indem man die Semantik von crypto_hash ändert, dass es auch diese Indirektion macht. Der Autor von libsodium schrieb mir, dass er das in seiner anderen Crypto-Lib, libhydrogen, auch so macht. Schön, aber zu spät für libsodium.