【问题标题】:How to apply padding for Base64如何为 Base64 应用填充
【发布时间】:2013-02-03 20:13:12
【问题描述】:

当我使用四个字母的单词作为输入时,我有以下代码可以正常工作,例如“测试”。当输入不是 4 的倍数时,它会失败,例如“我的测试”。

异常:Base-64 字符数组的长度无效。

问题

  1. 是否保证加密的结果将始终与 Unicode 字符串兼容(没有任何损失)。如果是,我可以使用 UTF 编码而不是 Base64 吗? What's the difference between UTF8/UTF16 and Base64 in terms of encoding
  2. 即使输入不是 4 的倍数,如何添加填充以便我们得到正确的结果(解密后)?

主要程序

class Program
{
    static void Main(string[] args)
    {
        string valid128BitString = "AAECAwQFBgcICQoLDA0ODw==";
        string inputValue = "MyTest";
        string keyValue = valid128BitString;


        byte[] byteValForString = Convert.FromBase64String(inputValue);
        EncryptResult result = Aes128Utility.EncryptData(byteValForString, keyValue);
        EncryptResult encyptedValue = new EncryptResult();
        string resultingIV = "4uy34C9sqOC9rbV4GD8jrA==";
        if (String.Equals(resultingIV,result.IV))
        {
            int x = 0;
        }

        encyptedValue.IV = resultingIV;
        encyptedValue.EncryptedMsg = result.EncryptedMsg;

        string finalResult = Convert.ToBase64String(Aes128Utility.DecryptData(encyptedValue, keyValue));
        Console.WriteLine(finalResult);

        if (String.Equals(inputValue, finalResult))
        {
            Console.WriteLine("Match");
        }
        else
        {
            Console.WriteLine("Differ");
        }

        Console.ReadLine();
    }
}

AES 加密实用程序

public static class Aes128Utility
{
    private static byte[] key;

    public static EncryptResult EncryptData(byte[] rawData, string strKey)
    {
        EncryptResult result = null;
        if (key == null)
        {
            if (!String.IsNullOrEmpty(strKey))
            {
                key = Convert.FromBase64String((strKey));
                result = Encrypt(rawData);
            }
        }
        else
        {
            result = Encrypt(rawData);
        }

        return result; 

    }

    public static byte[] DecryptData(EncryptResult encryptResult, string strKey)
    {
        byte[] origData = null;
        if (key == null)
        {
            if (!String.IsNullOrEmpty(strKey))
            {
                key = Convert.FromBase64String(strKey);
                origData = Decrypt(Convert.FromBase64String(encryptResult.EncryptedMsg), Convert.FromBase64String(encryptResult.IV));
            }
        }
        else
        {
            origData = Decrypt(Convert.FromBase64String(encryptResult.EncryptedMsg), Convert.FromBase64String(encryptResult.IV));
        }

        return origData; 
    }

    private static EncryptResult Encrypt(byte[] rawData)
    {
        using (AesCryptoServiceProvider aesProvider = new AesCryptoServiceProvider())
        {
            aesProvider.Key = key;
            aesProvider.Mode = CipherMode.CBC;
            aesProvider.Padding = PaddingMode.PKCS7;
            aesProvider.IV = Convert.FromBase64String("4uy34C9sqOC9rbV4GD8jrA==");
            using (MemoryStream memStream = new MemoryStream())
            {
                CryptoStream encStream = new CryptoStream(memStream, aesProvider.CreateEncryptor(), CryptoStreamMode.Write);
                encStream.Write(rawData, 0, rawData.Length);
                encStream.FlushFinalBlock();
                EncryptResult encResult = new EncryptResult();
                encResult.EncryptedMsg = Convert.ToBase64String(memStream.ToArray());
                encResult.IV = Convert.ToBase64String(aesProvider.IV);
                return encResult;
            }
        }
    }

    private static byte[] Decrypt(byte[] encryptedMsg, byte[] iv)
    {
        using (AesCryptoServiceProvider aesProvider = new AesCryptoServiceProvider())
        {
            aesProvider.Key = key;
            aesProvider.IV = iv;
            aesProvider.Mode = CipherMode.CBC;
            aesProvider.Padding = PaddingMode.PKCS7;
            using (MemoryStream memStream = new MemoryStream())
            {
                CryptoStream decStream = new CryptoStream(memStream, aesProvider.CreateDecryptor(), CryptoStreamMode.Write);
                decStream.Write(encryptedMsg, 0, encryptedMsg.Length);
                decStream.FlushFinalBlock();
                return memStream.ToArray();
            }
        }
    }

 }

DTO

public class EncryptResult
{
    public string EncryptedMsg { get; set; }
    public string IV { get; set; }
}

参考文献

  1. How to create byte[] with length 16 using FromBase64String
  2. Getting incorrect decryption value using AesCryptoServiceProvider

【问题讨论】:

  • 为什么是你的 DTO 的字符串,有什么原因你不能将它们作为字节数组传输吗?

标签: c# .net encryption cryptography


【解决方案1】:

Base64 是一种将二进制值表示为文本的方式,这样您就不会与常见的控制代码冲突,例如用于换行符的\x0A 或用于字符串终止符的\0。将键入的文本转换为二进制是

以下是您应该如何将文本传入和取回。您可以将UTF8 替换为您想要的任何编码,但您需要确保Encoding.Whatever.GetBytesEncoding.Whatever.GetString 的编码相同

class Program
{
    static void Main(string[] args)
    {
        string valid128BitString = "AAECAwQFBgcICQoLDA0ODw==";
        string inputValue = "MyTest";
        string keyValue = valid128BitString;

        //Turns our text in to binary data
        byte[] byteValForString = Encoding.UTF8.GetBytes(inputValue);

        EncryptResult result = Aes128Utility.EncryptData(byteValForString, keyValue);
        EncryptResult encyptedValue = new EncryptResult();

        //(Snip)

        encyptedValue.IV = resultingIV;
        encyptedValue.EncryptedMsg = result.EncryptedMsg;

        string finalResult = Encoding.UTF8.GetString(Aes128Utility.DecryptData(encyptedValue, keyValue));
        Console.WriteLine(finalResult);

        if (String.Equals(inputValue, finalResult))
        {
            Console.WriteLine("Match");
        }
        else
        {
            Console.WriteLine("Differ");
        }

        Console.ReadLine();
    }
}

【讨论】:

  • 当我将加密的字节数组转换为字符串时,它会以长度为 24 的字符串形式出现。这很好。但是数字 24 背后的基本原理是什么?
  • 因为编码一个字节需要 1 + 1/3 个字母来编码。因此,如果您在完成后有 1/3 或 2/3 的余数,则需要用一个特殊符号填充它,意思是“没有数据,只是试图四舍五入到下一个整数”。该符号通常是=。请参阅Wikipedia page on Base64 了解更多信息。
【解决方案2】:

如果你正在加密,那么对我来说编码 Base64 并不会增加任何有用的东西,反而会带来你面临的问题。

至于填充,我看到的一个解决方案是创建一个确实是 4 的倍数的新 byte[],并将源 byte[] 复制到该新 byte[]。

所以,是这样的:

 if (rawdata.Length % 16 !=0)
 {
      newSource = new byte[source.Length + 16 - source.Length % 16];
      Array.Copy(source, newSource, source.Length);
 }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-18
    • 1970-01-01
    • 2021-06-28
    • 1970-01-01
    • 1970-01-01
    • 2018-10-10
    相关资源
    最近更新 更多