I develop a WinForms solution which uses encryption.
One of the problems I have is dealing with empty passwords (e.g. no password set).
Obviously, empty string causes Cryptographic Exception, so I tried to prevent encrypting/decrypting string if it's empty and set its value to empty string.
However, I get exception:
CryptoGraphic Exception (Bad Data).
Here is the stack trace:
at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr)
at System.Security.Cryptography.Utils._DecryptData(SafeKeyHandle hKey, Byte[] data, Int32 ib, Int32 cb, Byte[]& outputBuffer, Int32 outputOffset, PaddingMode PaddingMode, Boolean fDone)
at System.Security.Cryptography.CryptoAPITransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
at xxx.Security.Cryptography.Decrypt(String cipherString, Boolean useHashing) in C:\xxxx\xxxx\xxxx\xxxx\xxxx\xxxx\Cryptography.cs:line 82
Here is the source code of the class:
using System;
using System.Security.Cryptography;
using System.Text;
namespace xxx
{
public class Cryptography
{
private const string key = "xxxx";
public static string Encrypt(string toEncrypt, bool useHashing)
{
if (toEncrypt == "")
{
string result = System.Convert.ToBase64String(Encoding.UTF8.GetBytes(toEncrypt));
return result;
}
else
{
try
{
byte[] keyArray;
byte[] toEncryptArray = Encoding.UTF8.GetBytes(toEncrypt);
//If hashing use get hashcode regards to your key
if (useHashing)
{
MD5CryptoServiceProvider md5CryptoServiceProvider = new MD5CryptoServiceProvider();
keyArray = md5CryptoServiceProvider.ComputeHash(Encoding.UTF8.GetBytes(key));
md5CryptoServiceProvider.Clear();
}
else
keyArray = Encoding.UTF8.GetBytes(key);
TripleDESCryptoServiceProvider tripleDesCryptoServiceProvider = new TripleDESCryptoServiceProvider();
//set the secret key for the tripleDES algorithm
tripleDesCryptoServiceProvider.Key = keyArray;
//mode of operation. there are other 4 modes.
//We choose ECB(Electronic code Book)
tripleDesCryptoServiceProvider.Mode = CipherMode.ECB;
//padding mode(if any extra byte added)
tripleDesCryptoServiceProvider.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = tripleDesCryptoServiceProvider.CreateEncryptor();
//transform the specified region of bytes array to resultArray
byte[] resultArray =
cTransform.TransformFinalBlock(toEncryptArray, 0,
toEncryptArray.Length);
//Release resources held by TripleDes Encryptor
tripleDesCryptoServiceProvider.Clear();
//Return the encrypted data into unreadable string format
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
catch (Exception)
{
string result = System.Convert.ToBase64String(Encoding.UTF8.GetBytes(toEncrypt));
return result;
}
}
}
public static string Decrypt(string cipherString, bool useHashing)
{
if (cipherString == "")
{
UTF8Encoding utf8 = new UTF8Encoding();
return Encoding.UTF8.GetString(utf8.GetBytes(""));
}
else
{
try
{
byte[] keyArray;
//get the byte code of the string
byte[] toEncryptArray = Convert.FromBase64String(cipherString);
if (useHashing)
{
//if hashing was used get the hash code with regards to your key
MD5CryptoServiceProvider md5CryptoServiceProvider = new MD5CryptoServiceProvider();
keyArray = md5CryptoServiceProvider.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
//release any resource held by the MD5CryptoServiceProvider
md5CryptoServiceProvider.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();
byte[] resultArray = cTransform.TransformFinalBlock(
toEncryptArray, 0, toEncryptArray.Length);
//Release resources held by TripleDes Encryptor
tdes.Clear();
//return the Clear decrypted TEXT
return Encoding.UTF8.GetString(resultArray);
}
catch (Exception)
{
UTF8Encoding utf8 = new UTF8Encoding();
return Encoding.UTF8.GetString(utf8.GetBytes(""));
}
}
}
}
}
So the problem is in Decrypt method. Any clues please?
P.S. Yes, I know the code is not ideal. This class wasn't written by me, I'm just trying to use it. Thank you for improvement suggestions, I will definitely concider them.
Best Answer
If you really want to allow empty passwords, make sure you special-case null as well as empty strings.
So change
to
and return null if
toEncrypt
is null or empty.Also change
to
and return an empty string if 'cipherString' is null or whitespace.
NB - the comment from CodesInChaos above is quite right. This code has a certain smell about it. He gives good advice.