所以我使用了一些我在网上看到的 AES 加密/解密方法,我做了一些修改。方法写在下面。
public void EncryptStringAES(Object threadContext)
{
if (string.IsNullOrEmpty(inputData))
{
outputData = string.Empty;
doneEventProperty.Set();
return;
}
if (string.IsNullOrEmpty(sharedSecretData))
throw new ArgumentNullException("sharedSecret");
string outStr = null;
RijndaelManaged aesAlg = null;
try
{
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(sharedSecretData, saltData);
aesAlg = new RijndaelManaged();
aesAlg.Padding = PaddingMode.PKCS7;
aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
using (MemoryStream msEncrypt = new MemoryStream())
{
msEncrypt.Write(BitConverter.GetBytes(aesAlg.IV.Length), 0, sizeof(int));
msEncrypt.Write(aesAlg.IV, 0, aesAlg.IV.Length);
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(inputData);
}
}
outStr = Convert.ToBase64String(msEncrypt.ToArray());
}
}
finally
{
if (aesAlg != null)
aesAlg.Clear();
}
outputData = outStr;
doneEventProperty.Set();
}
public void DecryptStringAES(Object threadContext)
{
if (string.IsNullOrEmpty(inputData))
{
outputData = string.Empty;
doneEventProperty.Set();
return;
}
if (string.IsNullOrEmpty(sharedSecretData))
throw new ArgumentNullException("sharedSecret");
RijndaelManaged aesAlg = null;
string plaintext = null;
try
{
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(sharedSecretData, saltData);
byte[] bytes = Convert.FromBase64String(inputData.ToString());
using (MemoryStream msDecrypt = new MemoryStream(bytes))
{
aesAlg = new RijndaelManaged();
aesAlg.Padding = PaddingMode.PKCS7;
aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);
aesAlg.IV = ReadByteArray(msDecrypt);
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
finally
{
if (aesAlg != null)
aesAlg.Clear();
}
outputData = plaintext;
doneEventProperty.Set();
}
我对其进行了修改,以便使用这些代码的对象可以在线程池中排队,并希望使整个加密/解密过程更快。在我修改线程代码之前,它可以工作。但是我添加线程功能后,总是遇到这个错误:
输入不是有效的 Base-64 字符串,因为它包含非 base 64 字符、两个以上的填充字符或填充字符中的非法字符。
当我解密我加密的字符串时,总是会发生这种情况。以下是我加密的数据示例。
EAAAALlZu0F1HmtQ0pNO/xPoOBgr4zRJvhIyr43van78dDED
EAAAAIvlxL+vtqhAf3HCFpRc6xeb76KFqhfe6Tbu1SN7LZH1
我已经检查了 Base64 字符串的要求,这些几乎符合要求。我还尝试了我在 stackoverflow 中看到的所有可能的答案,但仍然无济于事。更糟糕的是,有时有效,有时无效。我在这里没有选择,所以有人可以帮助我吗?
更新:
下面是一些使用上述方法的代码。
class AESHandler
{
private string outputDataProperty;
private string inputDataProperty;
private byte[] saltDataProperty;
private string sharedSecretDataProperty;
private ManualResetEvent doneEventProperty;
private Guid signatureDataProperty;
public string outputData
{
get
{
return outputDataProperty;
}
private set
{
outputDataProperty = value;
}
}
private string inputData
{
get
{
return inputDataProperty;
}
set
{
inputDataProperty = value;
}
}
private byte[] saltData
{
get
{
return saltDataProperty;
}
set
{
saltDataProperty = value;
}
}
private string sharedSecretData
{
get
{
return sharedSecretDataProperty;
}
set
{
sharedSecretDataProperty = value;
}
}
public ManualResetEvent doneEvent
{
get
{
return doneEventProperty;
}
}
public Guid signatureData
{
get
{
return signatureDataProperty;
}
private set
{
signatureDataProperty = value;
}
}
private byte[] ReadByteArray(Stream s)
{
byte[] rawLength = new byte[sizeof(int)];
if (s.Read(rawLength, 0, rawLength.Length) != rawLength.Length)
{
throw new SystemException("Stream did not contain properly formatted byte array");
}
byte[] buffer = new byte[BitConverter.ToInt32(rawLength, 0)];
if (s.Read(buffer, 0, buffer.Length) != buffer.Length)
{
throw new SystemException("Did not read byte array properly");
}
return buffer;
}
public void EncryptStringAES(Object threadContext)
{
if (string.IsNullOrEmpty(inputData))
{
outputData = string.Empty;
doneEventProperty.Set();
return;
}
if (string.IsNullOrEmpty(sharedSecretData))
throw new ArgumentNullException("sharedSecret");
string outStr = null;
RijndaelManaged aesAlg = null;
try
{
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(sharedSecretData, saltData);
aesAlg = new RijndaelManaged();
aesAlg.Padding = PaddingMode.PKCS7;
aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
using (MemoryStream msEncrypt = new MemoryStream())
{
msEncrypt.Write(BitConverter.GetBytes(aesAlg.IV.Length), 0, sizeof(int));
msEncrypt.Write(aesAlg.IV, 0, aesAlg.IV.Length);
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(inputData);
}
}
outStr = Convert.ToBase64String(msEncrypt.ToArray());
}
}
finally
{
if (aesAlg != null)
aesAlg.Clear();
}
outputData = outStr;
doneEventProperty.Set();
}
public void DecryptStringAES(Object threadContext)
{
if (string.IsNullOrEmpty(inputData))
{
outputData = string.Empty;
doneEventProperty.Set();
return;
}
if (string.IsNullOrEmpty(sharedSecretData))
throw new ArgumentNullException("sharedSecret");
RijndaelManaged aesAlg = null;
string plaintext = null;
try
{
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(sharedSecretData, saltData);
byte[] bytes = Convert.FromBase64String(inputData.ToString());
using (MemoryStream msDecrypt = new MemoryStream(bytes))
{
aesAlg = new RijndaelManaged();
aesAlg.Padding = PaddingMode.PKCS7;
aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);
aesAlg.IV = ReadByteArray(msDecrypt);
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
finally
{
if (aesAlg != null)
aesAlg.Clear();
}
outputData = plaintext;
doneEventProperty.Set();
}
public AESHandler(string input, string sharedSecret, Guid signature, byte[] salt)
{
if (!string.IsNullOrEmpty(input))
{
inputData = input;
}
else
{
inputData = string.Empty;
}
sharedSecretData = sharedSecret;
signatureData = signature;
saltData = salt;
doneEventProperty = new ManualResetEvent(false);
}
}
那是处理加密/解密过程的实际代码。下面的代码创建了上面类的一个实例,并在线程池中排队。
public sealed partial class AESCore
{
private static List<AESHandler> encryptThreadList = new List<AESHandler>();
public static Guid AESQueueEncrypt(string input, string sharedSecret)
{
return AESQueueEncrypt(input, sharedSecret, EncryptionCore._salt);
}
public static Guid AESQueueEncrypt(string input, string sharedSecret, byte[] salt)
{
Guid queueID = Guid.NewGuid();
AESHandler handle = new AESHandler(input, sharedSecret, queueID, EncryptionCore._salt);
ThreadPool.QueueUserWorkItem(handle.EncryptStringAES);
encryptThreadList.Add(handle);
return queueID;
}
public static Guid AESQueueDecrypt(string input, string sharedSecret)
{
return AESQueueDecrypt(input, sharedSecret, EncryptionCore._salt);
}
public static Guid AESQueueDecrypt(string input, string sharedSecret, byte[] salt)
{
Guid queueID = Guid.NewGuid();
AESHandler handle = new AESHandler(input, sharedSecret, queueID, EncryptionCore._salt);
ThreadPool.QueueUserWorkItem(handle.DecryptStringAES);
encryptThreadList.Add(handle);
return queueID;
}
public static string AESFetchData(Guid signature)
{
var data = encryptThreadList.Where(s => s.signatureData == signature).FirstOrDefault();
string output = data.outputData;
encryptThreadList.Remove(data);
return output;
}
public static void AESProcessWait()
{
foreach (var d in encryptThreadList)
{
d.doneEvent.WaitOne();
}
}
}
用法是这样的:
加密
Guid strnNameLast = Encryption.AESCore.AESQueueEncrypt(user.strnNameLast, publicKeyToken);
Guid strnNameFirst = Encryption.AESCore.AESQueueEncrypt(user.strnNameFirst, publicKeyToken);
Encryption.AESCore.AESProcessWait();
string strnNameLastEncrypted = Encryption.AESCore.AESFetchData(strnNameLast);
string strnNameFirstEncrypted = Encryption.AESCore.AESFetchData(strnNameFirst);
解密:
Guid strnNameLast = Encryption.AESCore.AESQueueDecrypt(user.strnNameLast, publicKeyToken);
Guid strnNameFirst = Encryption.AESCore.AESQueueDecrypt(user.strnNameFirst, publicKeyToken);
Encryption.AESCore.AESProcessWait();
string strnNameLastDecrypted = Convert.ToString(Encryption.AESCore.AESFetchData(strnNameLast));
string strnNameFirstDecrypted = Convert.ToString(Encryption.AESCore.AESFetchData(strnNameFirst));