为什么在我的解密文本中出现随机字符

本文关键字:随机 字符 文本 我的 解密 为什么 | 更新日期: 2023-09-27 17:54:11

简介

我正在尝试加密和解密文本,有时,尤其是对于较大的文本,解密后的文本中会出现随机字符。我在System.Security.Cryptography命名空间中使用AES加密,目前我试图加密的文本将是一个URL和一些信息,例如页面标题。我在下面提供了一个例子,以及我所做的尝试。我还编写了两种加密和解密方法,减去了输出到调试窗口的任何行。使用的Key和IV应该不是问题,因为目前,它们将是恒定的。

我认为我应该指出,正如预期的那样,它在单独的事件中加密和解密18/01/2013;18/01/2013

示例

说我想解密这个文本:

Barnabe Googes Information & Homepage | Search and Research on BarnabeGooge.com;18/01/2013;18/01/2013;;http://www.googe.com

默认情况下,它使用UTF-8,并将加密为:

뤟౏羜ڮ胂淺弊놛荧ꠃ錺槝ヸ蘜ầᄼꕒヘ⍩㗪潺뱂施㒞ꨛ殳硪픴ی뿨춃�燲ᯁﱪ뙊힓琲鯖嶑⨹갂Ѭ쳀鿜�྄䋖⭫ퟂ㪏�荾ꆺשּ붹梾麦膛

并解密回:

Barnabe Googes Information & Homepage | Search and Research on B���Ax2�!��f�M]18/01/20�;18/01[�;>َ�l?����m��*-��+��^A[=�

我所尝试的

  • 我曾尝试更改为其他编码,但UTF-8似乎对解密文本的影响最小
  • 更改为不同类型的填充,但Padding.Zeros似乎是最好的。我也不能使用Padding.None,因为它抛出了一个NotSupportedException: bad data length
  • Mode更改为CBC(这并不重要(
  • 刷新/关闭CryptoStream,这样它就可以刷新最后一个块,或者其他什么
  • 为了防止问题出在标题上,我用WebUtility.HtmlDecode()对标题进行了解码,但这并没有影响它

加密方法

如您所见,下面的加密使用AES加密。我想指出的是,keyIV与加密和解密方法是同一类中的两个全局字符串。我这样做的原因是为了处理不同的编码和CryptographyServiceProviders,如果偶然发生随机变化的话。请忽略这些,因为它们是恒定的,不会影响最终的加密/解密。

public static byte[] EncryptStringToBytes(string plainText, Encoding Enc)
{
    if (plainText == null || plainText.Length <= 0)
            throw new ArgumentNullException("plainText");
    byte[] encrypted;
    using (AesCryptoServiceProvider tdsAlg = new AesCryptoServiceProvider())
    {
         tdsAlg.Key = (byte[])Enc.GetBytes(key).Take(tdsAlg.Key.Length).ToArray();
         tdsAlg.IV = (byte[])Enc.GetBytes(IV).Take(tdsAlg.IV.Length).ToArray();
         tdsAlg.Padding = PaddingMode.Zeros;
         tdsAlg.Mode = CipherMode.CBC;
         ICryptoTransform encryptor = tdsAlg.CreateEncryptor(tdsAlg.Key, tdsAlg.IV);
         using (MemoryStream msEncrypt = new MemoryStream())
         {
             using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
             {
                 using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                 {
                     swEncrypt.Write(plainText);
                 }
                 encrypted = msEncrypt.ToArray();
                 csEncrypt.Close();
             }
         }
    }
    return encrypted;
}

解密方法

public static string DecryptStringFromBytes(byte[] cipherText,Encoding Enc)
{
    if (cipherText == null || cipherText.Length <= 0)
        throw new ArgumentNullException("cipherText");
    string plaintext = null;
    using (AesCryptoServiceProvider tdsAlg = new AesCryptoServiceProvider())
    {
        tdsAlg.Key = (byte[])Enc.GetBytes(key).Take(tdsAlg.Key.Length).ToArray();
        tdsAlg.IV = (byte[])Enc.GetBytes(IV).Take(tdsAlg.IV.Length).ToArray() ;
        tdsAlg.Padding = PaddingMode.Zeros;
        tdsAlg.Mode = CipherMode.CBC;
        ICryptoTransform decryptor = tdsAlg.CreateDecryptor();
        using (MemoryStream msDecrypt = new MemoryStream(cipherText))
        {
            using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
            {
                using (StreamReader srDecrypt = new StreamReader(csDecrypt,true))
                {
                    plaintext = srDecrypt.ReadToEnd().Replace("'0","");
                    csDecrypt.Close();
                    return plaintext.Replace("'0",string.Empty);
                }
            }
        }
   }    
   return plaintext;    
}

Bootnote

为了以防万一,我用这个来获取网页的标题,但正如我提到的,使用HtmlDecode不会影响它。

WebClient x = new WebClient();
string source = x.DownloadString(Url);
x.Dispose();
string title= Regex.Match(source, @"'<title'b[^>]*'>'s*(?<Title>['s'S]*?)'</title'>", RegexOptions.IgnoreCase).Groups["Title"].Value;
title = title.Replace(";", " ");
return title;

为什么在我的解密文本中出现随机字符

感谢Hans Passant,我找到了解决方案。问题是,当我加密和解密时,我使用的是Encoding.GetString()Encoding.GetBytes(),而我本应该使用Convert.ToBase64String()Convert.FromBase64String()

我也遇到了额外输出的问题。对我来说,这不是编码问题,因为我把它作为BCrypt库中的字节数组传递。由于它是纯文本,我会在加密前使用空格字符作为填充,在解密后使用修剪。

int padding = BLOCK_SIZE - (input_len+1)%BLOCK_SIZE;
if(padding && (input_len+padding) <= buf_size)
{
   memset(buf+input_len, ' ', padding);
   input_len += padding;
}

对于128比特加密,块大小为16。注意,buf_size应该是block-size的倍数,以使其始终工作。由于我们已经填充了输入,所以在解密时不需要填充算法。

tdsAlg.Padding = PaddingMode.None;

在解密结束时,我会修剪输出。