URL 安全 C# AES 加密

问题描述 投票:0回答:1

我在创建传递 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"

我知道我一定在这里犯了一个愚蠢的错误。

问题:

  1. 为什么这个实现不能正常工作?
  2. 有没有更好的方法来实现这个目标?
c# .net-core encryption aes
1个回答
0
投票

简而言之:因为并非每个字节序列都是有效的 UTF-8 字符序列,并且由于

Encoding.UTF8
默认情况下只会忽略无效序列,因此当您使用
GetString
将这些字节转换为字符串时,您最终会得到一些数据丢失。

使用 Base64 是正确的方法,但你做错了:你想将字节数组传递给

Base64UrlEncoder.Encode
,而不是字符串。不要做
GetString
这一步,直接把
ms.ToArray()
的结果传过去即可。 Base64 的全部意义在于将任意二进制数据转换为文本,您不需要中间转换为字符串。

同理,解密的时候,要用

Base64UrlEncoder.DecodeBytes
把那个字符串转成字节,然后再解密这些字节。

© www.soinside.com 2019 - 2024. All rights reserved.