SILC ist im einfachen Sinne betrachtet ein Chatprotokoll, ähnlich wie IRC. Allerdings achtete man beim Design auf die Vertraulichkeit der Gesprächsinhalte, so dass die Kommunikation nun verschlüsselt abläuft, ähnlich wie bei GGZ.
Man kann über eine Bibliothek namens libsilcclient diese Funktionalität in eigene Anwendungen mit aufnehmen. So soll beispielsweise unser Chatbot die Möglichkeit bekommen, über SILC die Leute aus dem c3d2-Channel zu ärgern. Vor allem Mandy hat es ihm ja angetan.
Nun, wie geht man als C-Programmierer vor? Zuerst bindet man zwei Headerdateien ein, die jede Menge Systembibliotheken schon enthalten, also stdio, unistd, TRUE/FALSE und dergleichen. Das spart Schreibarbeit.
Desweiteren benötigt man ein globales SilcClient-Objekt. Dies ist eine Struktur, die noch initialisiert wird. Als dritte Sache im globalen Namensraum werden noch (möglichst statische) Callback-Funktionen benötigt. Dazu später mehr, man sollte sich jedoch schon mal die Datei client_ops_example.c aus den SILC-Quellen anschauen.
In einer Funktion, die die Verbindung herstellt, legt man nun zuerst ein paar weitere Objekte auf den Stacks, und zwar von den Strukturtypen SilcPKCS, SilcPrivateKey und SilcPublicKey. Dann allokiert man sein globales client-Objekt über:
client = silc_client_alloc(&ops, /*¶ms*/NULL, NULL, silc_version_string);
Die Operationen sind dabei vom Typ SilcClientOperations. Diese müssen nur dann vorinitialisiert sein, wenn nicht die oben genannte Beispieldatei herangezogen wird. In meinem Fall hingegen werden etliche Funktionspointer nicht benötigt. Da die API-Dokumentation leider verschweigt, dass diese nicht NULL sein dürfen, habe ich sie mit einem speziellen Präfix belegt (no_silc_…), so dass die ops-Struktur damit initialisiert werden muss. Der zweite Parameter sollte zu Beginn immer NULL sein, man kann hierüber später nette Einstellungen wie die Darstellung des Nicknames vornehmen. Die Variable silc_version_string ist global verfügbar.
Die Client-Variablen username, hostname und realname müssen anschließend gesetzt werden. Es ist darauf zu achten, dass all diese Felder auch nach dem Verlassen der Funktion verfügbar sein müssen, also empfiehlt sich ein strdup(), welches zum Schluss wieder mit free() gradegebogen wird.
Der nächste Punkt betrifft die Kryptographie. Hier ist Handarbeit angesagt, aber zum Glück gibt es Standardfunktionen:
ret = silc_pkcs_register_default();
ret = silc_hash_register_default();
ret = silc_cipher_register_default();
ret = silc_hmac_register_default();
ret = silc_create_key_pair(NULL, 0, NULL, NULL, NULL, NULL, &pkcs, &pubkey, &privkey, FALSE);
Die Rückgabewerte sind dabei als boolesche Variablen aufzufassen, sollten also nicht Null sein. Man kann natürlich alle Ergebnisse mit OR verknüpfen und dann auf Nullverschiedenheit prüfen.
Nun hat man auch pkcs, pubkey und privkey, welche man ebenfalls den gleichnamigen Feldern des globalen silcclient-Objektes zuweist. Und nun geht es los auf die Datenreise:
ret = silc_client_init(client);
silc_client_connect_to_server(client, NULL, 706, hostname, NULL);
Dies alles ist für eine Konsolenapplikation gedacht, d.h. die Passphrase muss man auch beim Start der Anwendung eingeben. Graphische Anwendungen wie silky nutzen die SILC-PKCS-Funktionen zum Auslesen dieser Werte aus einer Datei, und Eingabe über Dialogfelder über diverse Callbacks. Das soll hier aber noch nicht Gegenstand des Tutorials sein, denn für heute reicht das obige sicherlich erstmal zu.
Beim Compilieren muss darauf geachtet werden, dass man sowohl gegen die libsilcclient als auch die libsilc linkt. Besonders bei Plugins/Bibliotheken sieht man dies nicht auf den ersten Blick.
Weitere Informationen findet der geneigte Hackspecht in der SILC-API-Dokumentation.