.NET6 C# Encoding.UTF8.GetString转换加密字节数组返回Unicode乱码问题
问题根源
- 你不能直接用
Encoding.UTF8.GetString()转换任意二进制字节数组:ProtectedData.Protect()返回的加密结果是无规则的二进制数据,不符合UTF8编码规范,强制转换会出现不可逆的字符损坏、乱码,你再把字符串转回字节数组时得到的内容和原加密数组完全不一致,自然会导致解密失败、程序崩溃。 PrintValues方法中直接把字节强制转为char打印,加密后的字节大多是不可见控制字符,也会输出乱码。
修复方案
把加密后的二进制字节数组转为Base64字符串再存入环境变量,Base64可以用可打印的标准ASCII字符无损表示任意二进制数据,不会出现编码丢失。
修复后的代码如下:
using System; using System.Security.Cryptography; using System.Text; namespace Crrypto { class Program { static byte[] s_additionalEntropy = Encoding.UTF8.GetBytes("hello"); static void Main(string[] args) { // 创建待加密的字节数组 byte[] secret = Encoding.UTF8.GetBytes("password"); // 加密数据 byte[] encryptedSecret = Protect(secret); // 转Base64字符串再存环境变量,不要用UTF8转 string store = Convert.ToBase64String(encryptedSecret); Environment.SetEnvironmentVariable("passwordLA", store); Console.WriteLine("加密后的字节数组(十六进制表示):"); PrintValues(encryptedSecret); // 从环境变量读取并解密 string secretFromEnv = Environment.GetEnvironmentVariable("passwordLA"); // 把Base64字符串转回字节数组再解密 byte[] loaded = Convert.FromBase64String(secretFromEnv); byte[] originalData = Unprotect(loaded); Console.WriteLine($"{Environment.NewLine}解密后的原始数据:"); PrintValues(originalData); // 可以直接转字符串查看原始密码 Console.WriteLine($"原始密码明文:{Encoding.UTF8.GetString(originalData)}"); } public static byte[] Protect(byte[] data) { try { return ProtectedData.Protect(data, s_additionalEntropy, DataProtectionScope.CurrentUser); } catch (CryptographicException e) { Console.WriteLine("加密失败,发生错误:"); Console.WriteLine(e.ToString()); return null; } } public static byte[] Unprotect(byte[] data) { try { return ProtectedData.Unprotect(data, s_additionalEntropy, DataProtectionScope.CurrentUser); } catch (CryptographicException e) { Console.WriteLine("解密失败,发生错误:"); Console.WriteLine(e.ToString()); return null; } } // 修改PrintValues,打印字节的十六进制值,不要强转char public static void PrintValues(Byte[] myArr) { foreach (Byte b in myArr) { Console.Write($"{b:X2} "); } Console.WriteLine(); } } }
内容的提问来源于stack exchange,提问作者TheLegend27
相关产品推荐
相关产品推荐

