C# WASM通过JS互操作加解密报错:组件渲染未处理异常
AES-GCM解密失败问题排查(Blazor WASM + JS互操作)
问题描述
通过Blazor WASM结合JS互操作实现AES-GCM加解密时,解密操作始终失败,抛出错误:DOM异常:提供的数据过小。已确认加密生成的密文、Key、IV格式均正确,但解密无法完成。
完整代码实现
Blazor页面(Encryption.razor)
<div class="input-container"> <label for="plainText">Input string</label> <div class="input-wrapper"> <input id="plainText" type="text" @bind="plainText" title="Input string" /> </div> </div> <div class="button-container"> <button @onclick="Encrypt" class="button-style button-one">Encrypt</button> <button @onclick="Decrypt" class="button-style">Decrypt</button> </div> <div class="input-container"> <label for="encryptedMessage">Encrypted/Decrypted Message</label> <div class="input-wrapper"> <input id="encryptedMessage" type="text" @bind="encryptedMessage" /> </div> </div> @code { private string plainText = ""; private string encryptedMessage = ""; private string keyBase64 = ""; private string ivBase64 = ""; // Method to generate a key and IV private async Task GenerateKeyAndIV() { keyBase64 = await JSRuntime.InvokeAsync<string>("generateKey"); ivBase64 = await JSRuntime.InvokeAsync<string>("generateIV"); } private async Task Encrypt() { await GenerateKeyAndIV(); encryptedMessage = await encryptionService.Encrypt(plainText, keyBase64, ivBase64); } private async Task Decrypt() { await GenerateKeyAndIV(); plainText = await encryptionService.Decrypt(encryptedMessage, keyBase64, ivBase64); } // Call GenerateKeyAndIV when the component is initialized protected override async Task OnInitializedAsync() { await GenerateKeyAndIV(); } }
EncryptionService.cs
using Microsoft.JSInterop; using System.Threading.Tasks; public class EncryptionService { private readonly IJSRuntime _jsRuntime; public EncryptionService(IJSRuntime jsRuntime) { _jsRuntime = jsRuntime; } public async Task<string> Encrypt(string text, string keyBase64, string iv) { return await _jsRuntime.InvokeAsync<string>("encryptText", text, keyBase64, iv); } public async Task<string> Decrypt(string encryptedBase64, string keyBase64, string iv) { return await _jsRuntime.InvokeAsync<string>("decryptText", encryptedBase64, keyBase64, iv); } }
index.html中的JS脚本
<script> window.generateKey = async () => { const key = await crypto.subtle.generateKey( { name: 'AES-GCM', length: 128 }, true, ['encrypt', 'decrypt'] ); const keyBytes = await crypto.subtle.exportKey('raw', key); return btoa(String.fromCharCode.apply(null, new Uint8Array(keyBytes))); }; </script> <!-- Function to generate IV --> <script> window.generateIV = async () => { const iv = crypto.getRandomValues(new Uint8Array(12)); return btoa(String.fromCharCode.apply(null, iv)); }; </script> <!-- Function to encrypt text using AES-GCM algorithm --> <script> async function encryptText(text, keyBase64, ivBase64) { const iv = new Uint8Array(atob(ivBase64).split('').map(char => char.charCodeAt(0))); const keyBytes = new Uint8Array(atob(keyBase64).split('').map(char => char.charCodeAt(0))); const encodedText = new TextEncoder().encode(text); const encodedKey = await crypto.subtle.importKey("raw", keyBytes, "AES-GCM", false, ["encrypt"]); const encryptedBytes = await crypto.subtle.encrypt({ name: "AES-GCM", iv }, encodedKey, encodedText); return btoa(String.fromCharCode.apply(null, new Uint8Array(encryptedBytes))); } </script> <!-- Function to decrypt text using AES-GCM algorithm --> <script> async function decryptText(encryptedBase64, keyBase64, ivBase64) { const iv = new Uint8Array(atob(ivBase64).split('').map(char => char.charCodeAt(0))); const keyBytes = new Uint8Array(atob(keyBase64).split('').map(char => char.charCodeAt(0))); const encryptedBytes = new Uint8Array(atob(encryptedBase64).split('').map(char => char.charCodeAt(0))); const importedKey = await crypto.subtle.importKey("raw", keyBytes, "AES-GCM", false, ["decrypt"]); const decryptedBytes = await crypto.subtle.decrypt({ name: "AES-GCM", iv }, importedKey, encryptedBytes); return new TextDecoder().decode(decryptedBytes); } </script>
问题根源
解密失败的核心原因是每次调用Decrypt方法时都重新生成了新的Key和IV。AES-GCM算法要求解密必须使用与加密时完全相同的Key和IV:
- 新生成的Key无法匹配加密时的密文,导致解密过程中无法正确解析数据
- AES-GCM会自动附加认证标签用于校验数据完整性,不匹配的Key/IV会触发校验失败,最终抛出"提供的数据过小"的异常(本质是无法识别有效密文结构)
修复方案
修改Decrypt方法,移除重新生成Key和IV的逻辑,直接使用加密时保存的keyBase64和ivBase64:
修改后的Blazor组件代码(Decrypt方法部分)
private async Task Decrypt() { // 移除GenerateKeyAndIV()调用,复用加密时的Key和IV plainText = await encryptionService.Decrypt(encryptedMessage, keyBase64, ivBase64); }
额外说明
- 如果需要持久化密文(比如保存到后端或本地存储),必须同时保存密文、Key(需加密存储)和IV(IV无需保密,但必须与加密时一致)
- AES-GCM的IV推荐每次加密都使用随机值,但同一组密文必须对应唯一的Key+IV组合
内容的提问来源于stack exchange,提问作者er280652
相关产品推荐
相关产品推荐

