====== 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(sp => new WasmCryptoProvider(sp.GetRequiredService())); ===== 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'': ===== 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 | | ''VerifyMlDsaAsync'' | byte[] data, byte[] signature, byte[] publicKey | Task | ==== ML-KEM ==== ^ Metoda ^ Parametri ^ Vrnjeno ^ | ''GenerateMlKemKeyPairAsync'' | string algorithm | Task<(byte[], byte[])> | | ''EncapsulateAsync'' | byte[] publicKey | Task<(byte[], byte[])> | | ''DecapsulateAsync'' | byte[] ciphertext, byte[] privateKey | Task | ==== Izpeljava ključev ==== ^ Metoda ^ Parametri ^ Vrnjeno ^ | ''Pbkdf2Async'' | string password, byte[] salt, int iterations, int outputLength, string hash | Task | | ''Pbkdf2WithPqSaltAsync'' | string password, byte[] baseSalt, byte[] pqPublicKey, int iterations, int outputLength | Task | | ''Argon2idAsync'' | byte[]/string password, byte[] salt, int outputLength, int iterations, int memoryKiB, int parallelism | Task | ==== HKDF ==== ^ Metoda ^ Parametri ^ Vrnjeno ^ | ''HkdfExtractAsync'' | byte[] salt, byte[] ikm | Task | | ''HkdfExpandAsync'' | byte[] prk, byte[] info, int length | Task | | ''HkdfDeriveKeyAsync'' | byte[] ikm, int length, byte[]? salt, byte[]? info | Task | | ''DeriveHybridKeyAsync'' | byte[] classicSecret, byte[] pqSecret, int outputLength | Task | ==== Šifriranje ==== ^ Metoda ^ Parametri ^ Vrnjeno ^ | ''EncryptChunkedAsync'' | byte[] plaintext, byte[] key, int chunkSize | Task | | ''DecryptChunkedAsync'' | byte[] ciphertext, byte[] key | Task | | ''EncryptStreamWithPqKeyAsync'' | byte[] plaintext, byte[] publicKey, int chunkSize | Task<(byte[], byte[])> | | ''DecryptStreamWithPqKeyAsync'' | byte[] kemCiphertext, byte[] encryptedData, byte[] privateKey | Task | ==== Pomožno ==== ^ Metoda ^ Parametri ^ Vrnjeno ^ | ''RandomBytesAsync'' | int length | Task | | ''CreateHybridSignatureAsync'' | byte[] data, byte[] classicSig, byte[] pqPrivKey | Task | | ''DeriveTls13KeysAsync'' | byte[] sharedSecret, byte[] clientHello, byte[] serverHello | Task | ===== Popoln primer ===== // Blazor komponenta @page "/crypto-demo" @inject ICryptoProvider CryptoProvider

PQ Crypto Demo

Status: @_status

@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.wasm'' in ''wvds-crypto.js'' morata biti pravilno naložena **Najboljše prakse za kriptografijo v brskalniku:** * 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 ===== * [[.:start|Providers Namespace]] * [[.:icryptoprovider|ICryptoProvider]] * [[.:nativecryptoprovider|NativeCryptoProvider]] * [[.:cryptoproviderfactory|CryptoProviderFactory]] * [[sl:int:pqcrypt:developer:integration:blazor-wasm|Integracija Blazor WASM]] ---- //Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//