我在创建传递 URL 的加密字符串时遇到问题。解密后我得到的字符不正确或出现错误。 “输入的数据不是一个完整的块”
这是我的课程来加密和解密我的字符串:
public static class StringCipher
{
public static string Encrypt(string s)
{
return AesProvider(s, (aes, raw) =>
{
using var ms = new MemoryStream();
using (var cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(raw, 0, raw.Length);
}
return Encoding.UTF8.GetString(ms.ToArray());
});
}
public static string Decrypt(string s)
{
return AesProvider(s, (aes, raw) =>
{
using var ms = new MemoryStream();
using (var cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(raw, 0, raw.Length);
}
return Encoding.UTF8.GetString(ms.ToArray());
});
}
private static string AesProvider(string s, Func<Aes, byte[], string> fn)
{
var raw = Encoding.UTF8.GetBytes(s);
using var aes = Aes.Create();
aes.Padding = PaddingMode.Zeros;
aes.KeySize = 128; // in bits
aes.Key = new byte[128 / 8]; // 16 bytes for 128 bit encryption
aes.IV = new byte[128 / 8]; // AES needs a 16-byte IV
aes.Mode = CipherMode.CBC;
return fn.Invoke(aes, raw);
}
}
示例用法如下:
var encrypted = StringCipher.Encrypt("my payload");
然后我使用
Base64UrlEncoder
,我知道这是一种 URL 安全的 base64 编码。
var url = $"https://example.com?code={Base64UrlEncoder.Encode(encrypted)}"
当我想解密它时,我正在尝试执行以下操作:
// https://example.com?code=a5e52f...
var decoded = Base64UrlEncoder.Decode(code);
var plainText = StringCipher.Decrypt(decoded); // expect "my payload"
我知道我一定在这里犯了一个愚蠢的错误。
问题:
简而言之:因为并非每个字节序列都是有效的 UTF-8 字符序列,并且由于
Encoding.UTF8
默认情况下只会忽略无效序列,因此当您使用 GetString
将这些字节转换为字符串时,您最终会得到一些数据丢失。
使用 Base64 是正确的方法,但你做错了:你想将字节数组传递给
Base64UrlEncoder.Encode
,而不是字符串。不要做GetString
这一步,直接把ms.ToArray()
的结果传过去即可。 Base64 的全部意义在于将任意二进制数据转换为文本,您不需要中间转换为字符串。
同理,解密的时候,要用
Base64UrlEncoder.DecodeBytes
把那个字符串转成字节,然后再解密这些字节。