Farbschema: Hell
Sie befinden sich hier: start » de » Dokumentation » Post-Quanten-Kryptografie » WvdS Crypto Service – Überblick » Anleitungen » Den L4Re-Dienst ansprechen

Den L4Re-Dienst ansprechen

Diese Anleitung zeigt, wie eine L4Re-Task über DataspaceEndpoint einen ML-DSA-Schlüssel erzeugen und damit eine Nachricht signieren lässt. Die Beispiele sind C++, weil DataspaceEndpoint eine C++-Klasse ist. Sie brauchen nur wvds_crypto.h und die Headerdatei von DataspaceEndpoint. Die Funktionen build_…, die Nachrichten zusammensetzen, sind reines C und lassen sich unverändert in C-Code übernehmen.

Voraussetzungen:

  • Der Dienst läuft als eigene L4Re-Task; siehe Bauformen im Vergleich.
  • Ihre Task hat Zugriff auf DataspaceEndpoint Ihres Plattformlieferanten und richtet ihn nach dessen Vorgaben ein: Registry-Server als statische Variable, Konstruktor im Hauptthread, Server-Schleife am Ende von main.

1. Endpunkt anlegen

#include "wvds_crypto.h"
#include "DataspaceEndpoint.h"
 
static L4Re::Util::Registry_server<> server;
 
int main()
{
    DataspaceEndpoint ep(&server,
                         "CRYPTO_CLI",   // eigener Name, so erwartet ihn der Dienst
                         "CRYPTO_SVC",   // Name des Dienstes
                         64 * 1024,      // Größe des Bereichs der Gegenseite
                         5000000,        // Zeitlimit für die Gegenseite
                         on_crypto_response);
    // Arbeits-Thread starten, der wait_for_initialization() aufruft und dann Anfragen sendet
    server.loop();
}

Die Namen sind im Dienst fest eingestellt. Eine Task mit anderem Namen findet er nicht.

2. Schlüssel erzeugen lassen

static size_t build_ml_dsa_keygen(uint8_t *buf, uint8_t level)
{
    wvds_init_header((wvds_message_header_t *)buf, WVDS_REQ_ML_DSA_KEYGEN, 0, 1);
    WVDS_PAYLOAD_PTR(buf)[0] = level;
    return WVDS_MESSAGE_SIZE(1);
}
 
/* im Arbeits-Thread, nach wait_for_initialization() */
uint8_t *buf = (uint8_t *)ep.allocate_local_blocking(WVDS_MESSAGE_SIZE(1));
size_t len = build_ml_dsa_keygen(buf, WVDS_ML_DSA_65);
ep.add_new_req(next_id++, WVDS_REQ_ML_DSA_KEYGEN, buf, len);

Die Antwort enthält die neue Kennung in den ersten 4 Byte der Nutzdaten und danach den öffentlichen Schlüssel, bei ML-DSA-65 1952 Byte.

3. Nachricht signieren lassen

static size_t build_ml_dsa_sign(uint8_t *buf, uint32_t key_id,
                                const uint8_t *msg, uint32_t msg_len)
{
    wvds_init_header((wvds_message_header_t *)buf, WVDS_REQ_ML_DSA_SIGN, key_id, 1 + msg_len);
    uint8_t *p = WVDS_PAYLOAD_PTR(buf);
    p[0] = WVDS_ML_DSA_65;            /* wird nicht ausgewertet, die Stufe kommt vom Schlüssel */
    memcpy(p + 1, msg, msg_len);
    return WVDS_MESSAGE_SIZE(1 + msg_len);
}

Die ganze Anfrage, also 16 Byte Kopf, Stufenbyte und Nachricht, muss in den 64 KiB großen Bereich passen, den der Dienst von Ihrer Task einblendet. Halten Sie Nachrichten deshalb deutlich unter 64 KiB und signieren Sie bei größeren Daten einen Hashwert. Die Antwort ist die Signatur selbst, bei ML-DSA-65 genau WVDS_ML_DSA_65_SIG_SIZE Byte.

4. Antworten auswerten

int on_crypto_response(DataspaceEndpoint *self, u_int64_t id, u_int8_t type,
                       const u_int8_t *data, l4_size_t size)
{
    wvds_message_header_t hdr;
 
    if (size >= sizeof hdr) {
        memcpy(&hdr, data, sizeof hdr);
        const uint8_t *payload = data + sizeof hdr;
 
        if (!wvds_validate_header(&hdr) || sizeof hdr + hdr.payload_len != size) {
            /* keine gültige Antwort des Dienstes */
        } else if (wvds_is_error_response(data, size)) {
            uint32_t code;
            memcpy(&code, payload, sizeof code);
            /* wvds_error_name((wvds_error_code_t)code) liefert den Namen */
        } else {
            /* Inhalt je nach offener Anfrage mit dieser id auswerten */
        }
    }
 
    self->free_peer_req(id, type, data, size);   /* immer freigeben */
    return 0;
}

Drei Punkte entscheiden über eine robuste Anbindung:

  • Fehler stehen im Kopf. Der IPC-Typ einer Antwort ist immer 0x80. Ob es ein Fehler ist, sagt allein req_type im Kopf; wvds_is_error_response prüft genau das.
  • Immer freigeben. Rufen Sie free_peer_req für jede Antwort auf, auch für ungültige. Sonst läuft der Bereich des Dienstes voll, und er kann nicht mehr antworten.
  • Zeitlimit vorsehen. Bei Überlast verwirft der Dienst Anfragen ohne Antwort. Merken Sie sich offene id-Werte und geben Sie eine Anfrage nach einer Frist verloren.

Verwandte Themen

de/wiki/pqcrypt/svc/how-to/call-l4re-service.txt · Zuletzt geändert: von Wolfgang van der Stille