Inhaltsverzeichnis
WasmCryptoProvider
Namespace: WvdS.System.Security.Cryptography.Providers
JavaScript Interop-osnovan kriptografski ponudnik za Blazor WebAssembly. Komunicira preko IJSRuntime z openssl.wasm.
Pregled
WasmCryptoProvider omogoča post-kvantno kriptografijo v aplikacijah Blazor WebAssembly preko:
- JavaScript Interop do WebAssembly-prevedenega OpenSSL
- Popolnoma asinhroni API (obvezen za JS Interop)
- Enaka funkcionalnost kot
NativeCryptoProvider
Arhitektura
Blazor WebAssembly
│
▼
┌─────────────────┐
│ WasmCrypto- │
│ Provider │
│ (C#) │
└────────┬────────┘
│ IJSRuntime.InvokeAsync
▼
┌─────────────────┐
│ wvds-crypto.js │
│ (JavaScript) │
└────────┬────────┘
│
▼
┌─────────────────┐
│ openssl.wasm │
│ (WebAssembly) │
└─────────────────┘
Lastnosti
| Lastnost | Tip | Opis |
|---|---|---|
Name | string | "WASM (JS Interop)" |
IsAvailable | bool | true če je inicializiran |
Dependency Injection
// Program.cs (Blazor WebAssembly) builder.Services.AddScoped<ICryptoProvider>(sp => new WasmCryptoProvider(sp.GetRequiredService<IJSRuntime>()));
Inicializacija
@inject ICryptoProvider CryptoProvider @code { protected override async Task OnInitializedAsync() { await CryptoProvider.InitializeAsync(); if (CryptoProvider.IsAvailable) { var version = CryptoProvider.GetOpenSslVersion(); Console.WriteLine($"OpenSSL WASM: {version}"); } } }
Zahtevane JS/WASM datoteke
V wwwroot/index.html:
<head> <!-- OpenSSL WASM modul --> <script src="_content/WvdS.Crypto/openssl.js"></script> <!-- WvdS Crypto ovoj --> <script src="_content/WvdS.Crypto/wvds-crypto.js"></script> </head>
Operacije ML-DSA
GenerateMlDsaKeyPairAsync
var (publicKey, privateKey) = await provider.GenerateMlDsaKeyPairAsync("ML-DSA-65");
SignMlDsaAsync
byte[] data = Encoding.UTF8.GetBytes("V brskalniku podpisani podatki"); byte[] signature = await provider.SignMlDsaAsync(data, privateKey);
VerifyMlDsaAsync
bool isValid = await provider.VerifyMlDsaAsync(data, signature, publicKey);
Operacije ML-KEM
GenerateMlKemKeyPairAsync
var (publicKey, privateKey) = await provider.GenerateMlKemKeyPairAsync("ML-KEM-768");
EncapsulateAsync
var (sharedSecret, ciphertext) = await provider.EncapsulateAsync(recipientPublicKey);
DecapsulateAsync
byte[] sharedSecret = await provider.DecapsulateAsync(ciphertext, privateKey);
Operacije izpeljave ključev
Pbkdf2Async
PBKDF2 preko Web Crypto API.
byte[] salt = await provider.RandomBytesAsync(32); byte[] derivedKey = await provider.Pbkdf2Async( password: "UserPassword", salt: salt, iterations: 100000, outputLength: 32, hash: "SHA-256");
Pbkdf2WithPqSaltAsync
PBKDF2 s PQ-okrepljeno soljo.
byte[] key = await provider.Pbkdf2WithPqSaltAsync( password: "UserPassword", baseSalt: baseSalt, pqPublicKey: recipientPqPublicKey, iterations: 100000, outputLength: 32);
Argon2idAsync
Memory-hard KDF preko OpenSSL WASM.
byte[] key = await provider.Argon2idAsync( password: passwordBytes, salt: salt, outputLength: 32, iterations: 3, memoryKiB: 65536, parallelism: 4);
Stream/Chunked šifriranje
EncryptChunkedAsync / DecryptChunkedAsync
Za velike kolicine podatkov s chunk-obdelavo.
byte[] key = await provider.RandomBytesAsync(32); // Šifriranje byte[] encrypted = await provider.EncryptChunkedAsync( plaintext, key, chunkSize: 65536); // 64 KB chunki // Dešifriranje byte[] decrypted = await provider.DecryptChunkedAsync(encrypted, key);
EncryptStreamWithPqKeyAsync / DecryptStreamWithPqKeyAsync
Kombinira ML-KEM izmenjavo ključev s chunk-šifriranjem.
// Šifriranje za prejemnika var (kemCiphertext, encryptedData) = await provider.EncryptStreamWithPqKeyAsync( plaintext, recipientPublicKey, chunkSize: 65536); // Dešifriranje byte[] decrypted = await provider.DecryptStreamWithPqKeyAsync( kemCiphertext, encryptedData, privateKey);
Operacije HKDF
HkdfExtractAsync
byte[] prk = await provider.HkdfExtractAsync(salt, inputKeyMaterial);
HkdfExpandAsync
byte[] okm = await provider.HkdfExpandAsync(prk, info, outputLength: 32);
HkdfDeriveKeyAsync
Extract + Expand v enem koraku.
byte[] key = await provider.HkdfDeriveKeyAsync( ikm: sharedSecret, length: 32, salt: optionalSalt, info: contextInfo);
DeriveHybridKeyAsync
Kombinira klasično in PQ skrivnost.
byte[] hybridKey = await provider.DeriveHybridKeyAsync( classicSecret: ecdhSecret, pqSecret: mlKemSecret, outputLength: 32);
TLS 1.3 izpeljava ključev
DeriveTls13KeysAsync
Tls13KeyMaterial keys = await provider.DeriveTls13KeysAsync( sharedSecret, clientHello, serverHello); // Dostop do izpeljanih skrivnosti var clientKey = keys.ClientHandshakeTrafficSecret; var serverKey = keys.ServerHandshakeTrafficSecret;
Hibridni podpisi
CreateHybridSignatureAsync
Ustvari hibridni podpis iz klasičnega podpisa in ML-DSA.
// Ustvarjanje klasičnega podpisa (npr. ECDSA) byte[] classicSig = CreateEcdsaSignature(data); // Ustvarjanje hibridnega podpisa byte[] hybridSig = await provider.CreateHybridSignatureAsync( data, classicSig, mlDsaPrivateKey);
Pomožne metode
RandomBytesAsync
Kriptografsko varna naključna števila preko Web Crypto API.
byte[] random = await provider.RandomBytesAsync(32);
Operacije s certifikati
CreateEphemeralCertificateAsync
byte[] certBytes = await provider.CreateEphemeralCertificateAsync( "CN=Certifikat brskalnika", TimeSpan.FromHours(1), mlDsaPrivateKey);
SignCertificateAsync
byte[] signedCert = await provider.SignCertificateAsync(tbsCertificate, privateKey);
Pregled metod
ML-DSA
| Metoda | Parametri | Vrnjeno |
|---|---|---|
GenerateMlDsaKeyPairAsync | string algorithm | Task<(byte[], byte[])> |
SignMlDsaAsync | byte[] data, byte[] privateKey | Task<byte[]> |
VerifyMlDsaAsync | byte[] data, byte[] signature, byte[] publicKey | Task<bool> |
ML-KEM
| Metoda | Parametri | Vrnjeno |
|---|---|---|
GenerateMlKemKeyPairAsync | string algorithm | Task<(byte[], byte[])> |
EncapsulateAsync | byte[] publicKey | Task<(byte[], byte[])> |
DecapsulateAsync | byte[] ciphertext, byte[] privateKey | Task<byte[]> |
Izpeljava ključev
| Metoda | Parametri | Vrnjeno |
|---|---|---|
Pbkdf2Async | string password, byte[] salt, int iterations, int outputLength, string hash | Task<byte[]> |
Pbkdf2WithPqSaltAsync | string password, byte[] baseSalt, byte[] pqPublicKey, int iterations, int outputLength | Task<byte[]> |
Argon2idAsync | byte[]/string password, byte[] salt, int outputLength, int iterations, int memoryKiB, int parallelism | Task<byte[]> |
HKDF
| Metoda | Parametri | Vrnjeno |
|---|---|---|
HkdfExtractAsync | byte[] salt, byte[] ikm | Task<byte[]> |
HkdfExpandAsync | byte[] prk, byte[] info, int length | Task<byte[]> |
HkdfDeriveKeyAsync | byte[] ikm, int length, byte[]? salt, byte[]? info | Task<byte[]> |
DeriveHybridKeyAsync | byte[] classicSecret, byte[] pqSecret, int outputLength | Task<byte[]> |
Šifriranje
| Metoda | Parametri | Vrnjeno |
|---|---|---|
EncryptChunkedAsync | byte[] plaintext, byte[] key, int chunkSize | Task<byte[]> |
DecryptChunkedAsync | byte[] ciphertext, byte[] key | Task<byte[]> |
EncryptStreamWithPqKeyAsync | byte[] plaintext, byte[] publicKey, int chunkSize | Task<(byte[], byte[])> |
DecryptStreamWithPqKeyAsync | byte[] kemCiphertext, byte[] encryptedData, byte[] privateKey | Task<byte[]> |
Pomožno
| Metoda | Parametri | Vrnjeno |
|---|---|---|
RandomBytesAsync | int length | Task<byte[]> |
CreateHybridSignatureAsync | byte[] data, byte[] classicSig, byte[] pqPrivKey | Task<byte[]> |
DeriveTls13KeysAsync | byte[] sharedSecret, byte[] clientHello, byte[] serverHello | Task<Tls13KeyMaterial> |
Popoln primer
// Blazor komponenta @page "/crypto-demo" @inject ICryptoProvider CryptoProvider <h3>PQ Crypto Demo</h3> <p>Status: @_status</p> @code { private string _status = "Inicializacija..."; protected override async Task OnInitializedAsync() { try { await CryptoProvider.InitializeAsync(); // Demo izmenjave ključev var (alicePublic, alicePrivate) = await CryptoProvider.GenerateMlKemKeyPairAsync(); var (sharedSecret, ciphertext) = await CryptoProvider.EncapsulateAsync(alicePublic); var decapsulated = await CryptoProvider.DecapsulateAsync(ciphertext, alicePrivate); bool keysMatch = sharedSecret.SequenceEqual(decapsulated); // Demo podpisa var (sigPub, sigPriv) = await CryptoProvider.GenerateMlDsaKeyPairAsync(); byte[] message = Encoding.UTF8.GetBytes("Testno sporočilo"); byte[] signature = await CryptoProvider.SignMlDsaAsync(message, sigPriv); bool isValid = await CryptoProvider.VerifyMlDsaAsync(message, signature, sigPub); _status = $"Ključi se ujemajo: {keysMatch}, Podpis veljaven: {isValid}"; } catch (Exception ex) { _status = $"Napaka: {ex.Message}"; } } }
Varnostni nasveti
- Zahteva .NET 8.0+ z Blazor WebAssembly
- Pomnilnik brskalnika je manj varen kot strežniški pomnilnik
- Zasebni ključi ne bi smeli biti dolgoročno shranjeni v brskalniku
- Za občutljive operacije: Prednostno strežniška obdelava
openssl.wasminwvds-crypto.jsmorata biti pravilno naložena
- Uporabljajte efemerne ključe za sejo-osnovano šifriranje
- Občutljive zasebne ključe pustite na strežniku
- Ne uporabljajte IndexedDB/localStorage za nešifrirane ključe
- Pravilno konfigurirajte CSP-glave za WASM
Glej tudi
Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional