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:

  • Hochperformanten Code im Browser
  • Sprachen wie C/C++ im Web nutzen
  • Blazor WebAssembly Anwendungen

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:

  • openssl.js - JavaScript-Loader
  • openssl.wasm - WebAssembly-Modul
  • C-Wrapper für Post-Quantum-Funktionen

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

Zuletzt geändert: den 29.01.2026 um 15:14