Inhaltsverzeichnis

3.3 WASM Build für Blazor

Diese Anleitung erklärt, wie Sie OpenSSL für Blazor WebAssembly kompilieren.


Was ist WebAssembly?

WebAssembly (WASM) ist ein binäres Format, das im Browser läuft. Es ermöglicht:

Wann brauche ich WASM?

Anwendungstyp WASM nötig?
————–————-
Blazor WebAssembly Ja
Blazor Server Nein (nutzt Windows/Linux Build)
ASP.NET Core API Nein
Desktop App (.NET) Nein

Voraussetzungen

Zusätzlich zu den Standard-Tools benötigen Sie:

WASM-Builds sind nur unter Linux/WSL möglich, nicht direkt unter Windows!


Build-Übersicht

Der WASM-Build erstellt:


Build-Schritte

Schritt 1: WSL öffnen

# WSL Terminal öffnen
wsl

Schritt 2: Emscripten aktivieren

# Emscripten Environment laden
source /opt/emsdk/emsdk_env.sh
 
# Prüfen
emcc --version
# Sollte zeigen: emcc (Emscripten gcc/clang-like replacement) 3.x.x

Schritt 3: Build-Verzeichnis vorbereiten

# Verzeichnisse erstellen
mkdir -p /mnt/d/Projects/openssl-3.6.0/wasm-build
mkdir -p /mnt/d/Projects/openssl-3.6.0/wasm-install
 
cd /mnt/d/Projects/openssl-3.6.0/wasm-build

Schritt 4: OpenSSL für WASM konfigurieren

emconfigure /mnt/d/Projects/openssl-3.6.0/src/Configure \
    linux-generic32 \
    --prefix=/mnt/d/Projects/openssl-3.6.0/wasm-install \
    --openssldir=/mnt/d/Projects/openssl-3.6.0/wasm-install/ssl \
    no-asm \
    no-threads \
    no-shared \
    no-dso \
    no-engine \
    no-hw \
    no-async \
    no-sock \
    no-dgram \
    no-tests \
    no-apps \
    -DOPENSSL_NO_SECURE_MEMORY \
    CC=emcc \
    AR=emar \
    RANLIB=emranlib

Erklärung der Optionen:

Option Bedeutung
——–———–
linux-generic32 Generische 32-bit Plattform
no-asm Keine Assembly (WASM kann kein x86 Assembly)
no-threads Keine Threads (Web Workers separat)
no-shared Nur statische Library
no-sock Keine Socket-Unterstützung
no-tests Keine Tests bauen
no-apps Kein openssl CLI Tool

Schritt 5: Kompilieren

emmake make -j$(nproc) build_libs

Schritt 6: Installieren

emmake make install_sw

JavaScript-Wrapper erstellen

Für die Integration in Blazor brauchen wir einen Wrapper:

wvds_crypto_wrapper.c

// WvdS Crypto WASM Wrapper
#include <emscripten.h>
#include <openssl/evp.h>
#include <openssl/x509.h>
#include <openssl/err.h>
#include <string.h>
#include <stdlib.h>
 
// Initialisierung
EMSCRIPTEN_KEEPALIVE
int wvds_init(void) {
    OPENSSL_init_crypto(
        OPENSSL_INIT_LOAD_CRYPTO_STRINGS |
        OPENSSL_INIT_ADD_ALL_CIPHERS |
        OPENSSL_INIT_ADD_ALL_DIGESTS, NULL);
    return 1;
}
 
// OpenSSL Version
EMSCRIPTEN_KEEPALIVE
const char* wvds_get_version(void) {
    return OPENSSL_VERSION_TEXT;
}
 
// ML-DSA Schlüsselgenerierung
EMSCRIPTEN_KEEPALIVE
int wvds_mldsa_keygen(const char* algorithm,
                       unsigned char** pub_key, int* pub_len,
                       unsigned char** priv_key, int* priv_len) {
    EVP_PKEY_CTX *ctx = NULL;
    EVP_PKEY *pkey = NULL;
    int ret = 0;
 
    // Algorithmus-Name für OpenSSL
    const char* ossl_alg = algorithm;
    if (strcmp(algorithm, "ML-DSA-44") == 0) ossl_alg = "mldsa44";
    else if (strcmp(algorithm, "ML-DSA-65") == 0) ossl_alg = "mldsa65";
    else if (strcmp(algorithm, "ML-DSA-87") == 0) ossl_alg = "mldsa87";
 
    ctx = EVP_PKEY_CTX_new_from_name(NULL, ossl_alg, NULL);
    if (!ctx) goto err;
 
    if (EVP_PKEY_keygen_init(ctx) <= 0) goto err;
    if (EVP_PKEY_keygen(ctx, &pkey) <= 0) goto err;
 
    // Public Key exportieren
    *pub_len = i2d_PUBKEY(pkey, NULL);
    *pub_key = malloc(*pub_len);
    unsigned char *p = *pub_key;
    i2d_PUBKEY(pkey, &p);
 
    // Private Key exportieren
    *priv_len = i2d_PrivateKey(pkey, NULL);
    *priv_key = malloc(*priv_len);
    p = *priv_key;
    i2d_PrivateKey(pkey, &p);
 
    ret = 1;
 
err:
    EVP_PKEY_free(pkey);
    EVP_PKEY_CTX_free(ctx);
    return ret;
}
 
// ML-DSA Signieren
EMSCRIPTEN_KEEPALIVE
int wvds_mldsa_sign(const unsigned char* data, int data_len,
                    const unsigned char* priv_key, int priv_len,
                    unsigned char** sig, int* sig_len) {
    // ... (vollständige Implementierung im Build-Skript)
    return 1;
}
 
// ML-DSA Verifizieren
EMSCRIPTEN_KEEPALIVE
int wvds_mldsa_verify(const unsigned char* data, int data_len,
                      const unsigned char* sig, int sig_len,
                      const unsigned char* pub_key, int pub_len) {
    // ... (vollständige Implementierung im Build-Skript)
    return 1;
}
 
// Speicher freigeben
EMSCRIPTEN_KEEPALIVE
void wvds_free(void* ptr) {
    free(ptr);
}

Wrapper kompilieren

INSTALL_DIR=/mnt/d/Projects/openssl-3.6.0/wasm-install
OUTPUT=/mnt/d/Projects/openssl-3.6.0/wasm-build
 
emcc $OUTPUT/wvds_crypto_wrapper.c \
    -I"$INSTALL_DIR/include" \
    -L"$INSTALL_DIR/lib" \
    -lcrypto \
    -Os \
    -s WASM=1 \
    -s MODULARIZE=1 \
    -s EXPORT_NAME="OpenSSLModule" \
    -s EXPORTED_FUNCTIONS='["_wvds_init","_wvds_get_version","_wvds_mldsa_keygen","_wvds_mldsa_sign","_wvds_mldsa_verify","_wvds_free","_malloc","_free"]' \
    -s EXPORTED_RUNTIME_METHODS='["ccall","cwrap","getValue","setValue","UTF8ToString"]' \
    -s ALLOW_MEMORY_GROWTH=1 \
    -o "$OUTPUT/openssl.js"

Ergebnis

Nach dem Build:

wasm-build/
├── openssl.js    # JavaScript Loader (~150 KB)
└── openssl.wasm  # WebAssembly Modul (~2 MB)

In Blazor einbinden

1. Dateien kopieren

cp openssl.js openssl.wasm /mnt/d/MeinProjekt/wwwroot/

2. In index.html laden

<script src="openssl.js"></script>
<script>
    var cryptoModule = null;
 
    OpenSSLModule().then(function(module) {
        cryptoModule = module;
        module._wvds_init();
        console.log("OpenSSL Version:", module.ccall('wvds_get_version', 'string', [], []));
    });
</script>

3. In Blazor aufrufen

// In Ihrer Blazor-Komponente
@inject IJSRuntime JS
 
public async Task<string> GetOpenSslVersion()
{
    return await JS.InvokeAsync<string>("eval",
        "cryptoModule.ccall('wvds_get_version', 'string', [], [])");
}

Vollständiges Build-Skript

Für den kompletten Build mit ML-DSA und ML-KEM:

#!/bin/bash
# build-wasm.sh - OpenSSL 3.6.0 WASM Build
 
set -e
 
OPENSSL_SRC="/mnt/d/Projects/openssl-3.6.0/src"
OUTPUT_DIR="/mnt/d/Projects/openssl-3.6.0/wasm-build"
INSTALL_DIR="/mnt/d/Projects/openssl-3.6.0/wasm-install"
 
echo "=== OpenSSL WASM Build ==="
 
# Emscripten aktivieren
source /opt/emsdk/emsdk_env.sh
 
# Verzeichnisse erstellen
mkdir -p "$OUTPUT_DIR" "$INSTALL_DIR"
cd "$OUTPUT_DIR"
 
# Konfigurieren
emconfigure "$OPENSSL_SRC/Configure" \
    linux-generic32 \
    --prefix="$INSTALL_DIR" \
    no-asm no-threads no-shared no-dso no-engine \
    no-async no-sock no-dgram no-tests no-apps \
    CC=emcc AR=emar RANLIB=emranlib
 
# Bauen
emmake make -j$(nproc) build_libs
 
# Installieren
emmake make install_sw
 
echo "=== Build abgeschlossen ==="

Weiter zu


Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional