我在C#中有一个三重DES包装器,它由两个静态函数Encrypt
和Decrypt
组成。偶尔,Decrypt
会失败,TransformFinalBlock(..., ...)
会抛出错误"Bad data"。
- 为什么会发生这种情况
- 解决方案是什么
提前谢谢。
public static string Encrypt(string toencrypt, string key, bool usehashing = true)
{
byte[] keyArray;
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toencrypt);
byte[] resultArray;
//If hashing use get hashcode regards to your key
if (usehashing)
{
MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
//Always release the resources and flush data
// of the Cryptographic service provide. Best Practice
hashmd5.Clear();
}
else
keyArray = UTF8Encoding.UTF8.GetBytes(key);
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
//set the secret key for the tripleDES algorithm
tdes.Key = keyArray;
//mode of operation. there are other 4 modes.
//We choose ECB(Electronic code Book)
tdes.Mode = CipherMode.ECB;
//padding mode(if any extra byte added)
tdes.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = tdes.CreateEncryptor();
try
{
//transform the specified region of bytes array to resultArray
resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
}
catch (System.Exception ex)
{
//Release resources held by TripleDes Encryptor
tdes.Clear();
return "";
}
//Release resources held by TripleDes Encryptor
tdes.Clear();
//Return the encrypted data into unreadable string format
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
public static string Decrypt(string todecrypt, string key, bool usehashing = true)
{
byte[] keyArray;
byte[] toEncryptArray;
byte[] resultArray;
//get the byte code of the string
try
{
toEncryptArray = Convert.FromBase64String(todecrypt.Replace(" ", "+"));//The replace happens only when spaces exist in the string (hence not a Base64 string in the first place).
}
catch (System.Exception ex)
{
return "";
}
if (usehashing)
{
//if hashing was used get the hash code with regards to your key
MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
//release any resource held by the MD5CryptoServiceProvider
hashmd5.Clear();
}
else
{
//if hashing was not implemented get the byte code of the key
keyArray = UTF8Encoding.UTF8.GetBytes(key);
}
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
//set the secret key for the tripleDES algorithm
tdes.Key = keyArray;
//mode of operation. there are other 4 modes.
//We choose ECB(Electronic code Book)
tdes.Mode = CipherMode.ECB;
//padding mode(if any extra byte added)
tdes.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = tdes.CreateDecryptor();
try
{
resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
}
catch (System.Exception ex)
{
//Release resources held by TripleDes Encryptor
tdes.Clear();
return "";
}
//Release resources held by TripleDes Encryptor
tdes.Clear();
//return the Clear decrypted TEXT
return UTF8Encoding.UTF8.GetString(resultArray);
}
一个一旦加密就会导致Decrypt
失败的示例字符串是:
AgAAAA*AQAAAA*aAAAAA*jfgGTw*nY+sHZ2PrBmdj6wVnY+sEZ2PrA2dj6wFk4GhCJOHoQqdj6x9nY+seQ*
然而,大多数字符串不会导致它失败。我猜这一定和一些特殊的角色有关。
首先,请提供初始未加密密钥和字符串,该密钥和字符串会生成失败的加密块。然后我们可能有更好的机会弄清楚为什么会出现问题。然而,根据要求,我在您的代码中看到了一些潜在的陷阱,主要与不处理实现IDisposable
的类型有关。这里有一个代码的小重构,它考虑到了这一点(以及其他一些小调整):
public static string Encrypt(string toencrypt, string key, bool usehashing = true)
{
byte[] keyArray;
// If hashing use get hash code regards to your key
if (usehashing)
{
using (var hashmd5 = new MD5CryptoServiceProvider())
{
keyArray = hashmd5.ComputeHash(Encoding.UTF8.GetBytes(key));
}
}
else
{
keyArray = Encoding.UTF8.GetBytes(key);
}
// set the secret key for the tripleDES algorithm
// mode of operation. there are other 4 modes.
// We choose ECB(Electronic code Book)
// padding mode(if any extra byte added)
using (var tdes = new TripleDESCryptoServiceProvider
{
Key = keyArray,
Mode = CipherMode.ECB,
Padding = PaddingMode.PKCS7
})
using (var transform = tdes.CreateEncryptor())
{
try
{
var toEncryptArray = Encoding.UTF8.GetBytes(toencrypt);
// transform the specified region of bytes array to resultArray
var resultArray = transform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
// Return the encrypted data into unreadable string format
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
catch (Exception)
{
return string.Empty;
}
}
}
public static string Decrypt(string todecrypt, string key, bool usehashing = true)
{
byte[] toEncryptArray;
// get the byte code of the string
try
{
toEncryptArray = Convert.FromBase64String(todecrypt.Replace(" ", "+")); // The replace happens only when spaces exist in the string (hence not a Base64 string in the first place).
}
catch (Exception)
{
return string.Empty;
}
byte[] keyArray;
if (usehashing)
{
// if hashing was used get the hash code with regards to your key
using (var hashmd5 = new MD5CryptoServiceProvider())
{
keyArray = hashmd5.ComputeHash(Encoding.UTF8.GetBytes(key));
}
}
else
{
// if hashing was not implemented get the byte code of the key
keyArray = Encoding.UTF8.GetBytes(key);
}
// set the secret key for the tripleDES algorithm
// mode of operation. there are other 4 modes.
// We choose ECB(Electronic code Book)
// padding mode(if any extra byte added)
using (var tdes = new TripleDESCryptoServiceProvider
{
Key = keyArray,
Mode = CipherMode.ECB,
Padding = PaddingMode.PKCS7
})
using (var transform = tdes.CreateDecryptor())
{
try
{
var resultArray = transform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
// return the Clear decrypted TEXT
return Encoding.UTF8.GetString(resultArray);
}
catch (Exception)
{
return string.Empty;
}
}
}