关于AES加密Byte[]在HttpRequest头传递及编码的技术问询
技术问题:AES加密结果的编码与请求头传输问题
场景与代码实现
我尝试创建一个会话,会话内容为经AES密钥加密的随机字符串,加密结果以byte[]形式返回。相关代码如下:
CryptoService类
public class CryptoService : ICryptoService { const int PASSWORD_LENGTH = 32; private static Encoding encoder = Encoding.UTF8; public byte[] EncrpyRandomPassword(string nonceValue) { var randomString = RandomPasswordGenerator.RandomString(PASSWORD_LENGTH); var keyByte = encoder.GetBytes(nonceValue); using Aes myAes = Aes.Create(); byte[] encrypted = EncryptStringToBytes_Aes(randomString, keyByte, myAes.IV); return encrypted; } }
Session类与接口
public interface ISession { byte[] SessionKey { get; } string SessionKeyASCI { get; } string SessionKeyUTF8 { get; } bool IsValid { get; } void ValidateSession(); } public class Session : ISession { private byte[] m_SessionKey; private bool m_IsValid; public byte[] SessionKey => m_SessionKey; public bool IsValid => m_IsValid; public string SessionKeyASCI => Encoding.ASCII.GetString(m_SessionKey); public string SessionKeyUTF8 => Encoding.UTF8.GetString(m_SessionKey); }
控制器代码
public async Task<IActionResult> CreateSessionAsync(string nonceValue) { if (string.IsNullOrEmpty(nonceValue)) { throw new ArgumentException($"'{nameof(nonceValue)}' cannot be null or empty.", nameof(nonceValue)); } var session = await _sessionProvider.CreateSession(nonceValue); return Ok(session); }
AES加密方法
static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV) { // Check arguments. if (plainText == null || plainText.Length <= 0) throw new ArgumentNullException("plainText"); if (Key == null || Key.Length <= 0) throw new ArgumentNullException("Key"); if (IV == null || IV.Length <= 0) throw new ArgumentNullException("IV"); byte[] encrypted; // Create an Aes object // with the specified key and IV. using (Aes aesAlg = Aes.Create()) { aesAlg.Key = Key; aesAlg.IV = IV; // Create an encryptor to perform the stream transform. ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV); // Create the streams used for encryption. using (MemoryStream msEncrypt = new MemoryStream()) { using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) { using (StreamWriter swEncrypt = new StreamWriter(csEncrypt)) { //Write all data to the stream. swEncrypt.Write(plainText); } encrypted = msEncrypt.ToArray(); } } } // Return the encrypted bytes from the memory stream. return encrypted; }
Postman返回结果
{ "sessionKey": "lI+ZRpzqP6E2vErt+wK4dw+nFM0mm0q1Pc2PoAuCssybVI07jUIQ5VWGR2yXCmX5", "isValid": false, "sessionKeyASCI":"???F????6?J???w??&?J?=???\u000b????T?;?B?U?Gl?\ne?", "sessionKeyUTF8":"���F��?�6�J���w��&�J�=͏�\u000b��̛T�;�B�U�Gl�\ne?" }
具体问题
- C#使用了哪种编码将sessionKey转换为返回结果中的字符串?我原以为是ASCII或UTF8,但实际结果与这两种编码的转换结果不同。
- 将sessionKey作为byte[]在POST接口中使用时能正常工作,可成功转回字符串,但我希望将该SessionKey放在请求头中传递,因此引出第三个问题。
- 如何将AES加密结果编码为可用于请求头的字符串,并且后续能转回byte[]?
解答
问题1:sessionKey的编码方式
返回结果中的sessionKey是Base64编码,而非ASCII或UTF8。ASP.NET Core默认序列化byte[]类型时,会自动将其转换为Base64字符串——这就是你看到的lI+ZRpzqP6E2vErt+wK4dw+...这类结果的原因。
AES加密后的字节流是二进制数据,并非合法的ASCII或UTF8字符序列,直接用文本编码转换必然会丢失数据或出现乱码,这也是你手动转换后得到乱码的原因。
问题2:POST接口传递byte[]正常的原因
POST接口中直接传递byte[]时,ASP.NET Core会自动处理二进制数据的序列化与反序列化(通常通过Base64或直接二进制传输)。但请求头的传输规则不同:请求头只能包含可打印的ASCII字符,无法直接传输二进制数据,因此需要专门的编码方案。
问题3:适配请求头的编码与解码方案
要将AES加密后的byte[]转换为可在请求头中安全传输的字符串,同时能还原为原字节数组,推荐两种方案:
方案1:标准Base64编码
标准Base64包含+、/和=字符,这些字符在请求头中可直接使用(符合HTTP规范)。编码和解码代码如下:
// 编码:byte[]转Base64字符串 string headerSafeSessionKey = Convert.ToBase64String(session.SessionKey); // 解码:Base64字符串转回byte[] byte[] originalBytes = Convert.FromBase64String(headerSafeSessionKey);
方案2:URL安全的Base64编码
如果担心+、/和=可能被代理或网关异常处理,可以使用URL安全的Base64变体:将+替换为-,/替换为_,并去掉末尾的=填充字符。解码时再还原为标准Base64格式:
// URL安全编码 string urlSafeBase64 = Convert.ToBase64String(session.SessionKey) .Replace('+', '-') .Replace('/', '_') .TrimEnd('='); // URL安全解码 string standardBase64 = urlSafeBase64 .Replace('-', '+') .Replace('_', '/'); // 补回缺失的=填充 switch (standardBase64.Length % 4) { case 2: standardBase64 += "=="; break; case 3: standardBase64 += "="; break; } byte[] originalBytes = Convert.FromBase64String(standardBase64);
注意事项
- 请求头有长度上限(通常建议不超过4KB),会话密钥类数据一般不会超出此限制;
- 解码时必须使用与编码完全对应的规则,避免数据损坏。
内容的提问来源于stack exchange,提问作者CiucaS
相关产品推荐
相关产品推荐

