我正在尝试加密和解密文本,有时,特别是对于较大的文本,随机字符会出现在解密文本中。我在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[=�
Padding.Zeros
似乎是最好的。我也无法使用Padding.None
,因为它会抛出NotSupportedException: bad data length
。Mode
更改为CBC(并非如此重要)。WebUtility.HtmlDecode()
来解码标题,但它并没有影响它。以下加密使用AES加密,如您所见。我想指出key
和IV
是加密和解密方法在同一类中的两个全局字符串。我这样做的原因是乱用不同的编码和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;
}
为了防止重要,我使用它来获取网页的标题,但正如我所提到的,使用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;
答案 0 :(得分:3)
感谢Hans Passant,我找到了解决方案。问题是我在加密和解密时使用Encoding.GetString()
或Encoding.GetBytes()
,当我应该使用Convert.ToBase64String()
或Convert.FromBase64String()
时。
答案 1 :(得分:-1)
我有同样的额外输出问题。对我来说这不是编码问题,因为我在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;
在解密结束时,我会修剪输出。