I have the following encryption method. I am not able to decrypt it. I have inherited the encryption algorithm so it cannot be changed.
public static string Encrypt(string plaintext)
{
byte[] rgbIV;
byte[] key;
RijndaelManaged rijndael = BuildRigndaelCommon(out rgbIV, out key);
//convert plaintext into a byte array
byte[] plaintextBytes = Encoding.UTF8.GetBytes(plaintext);
int BlockSize;
BlockSize = 16 * (1 + (plaintext.Length / 16));
Array.Resize(ref plaintextBytes, BlockSize);
// fill the remaining space with 0
for (int i = plaintext.Length; i < BlockSize; i++)
{
plaintextBytes[i] = 0;
}
byte[] cipherTextBytes = null;
//create uninitialized Rijndael encryption obj
using (RijndaelManaged symmetricKey = new RijndaelManaged())
{
//Call SymmetricAlgorithm.CreateEncryptor to create the Encryptor obj
var transform = rijndael.CreateEncryptor();
//Chaining mode
symmetricKey.Mode = CipherMode.CFB;
//create encryptor from the key and the IV value
ICryptoTransform encryptor = symmetricKey.CreateEncryptor(key, rgbIV);
//define memory stream to hold encrypted data
using (MemoryStream ms = new MemoryStream())
{
//define cryptographic stream - contains the transformation key to be used and the mode
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
//encrypt contents of cryptostream
cs.Write(plaintextBytes, 0, BlockSize);
cs.FlushFinalBlock();
//convert encrypted data from a memory stream into a byte array
cipherTextBytes = ms.ToArray();
}
}
}
//store result as a hex value
string hexOutput = BitConverter.ToString(cipherTextBytes).Replace("-", "");
hexOutput = hexOutput.Substring(0, plaintext.Length * 2);
//finially return encrypted string
return hexOutput;
}
As you can see it's pretty standard except at the end it's converted to hex and substring is performed. I'm having great difficulty doing the opposite.
My decrypt method is like:
public static string Decrypt(string disguisedtext)
{
byte[] rgbIV;
byte[] key;
BuildRigndaelCommon(out rgbIV, out key);
byte[] disguishedtextBytes = FromHexString(disguisedtext);
string visiabletext = "";
//create uninitialized Rijndael encryption obj
using (var symmetricKey = new RijndaelManaged())
{
//Call SymmetricAlgorithm.CreateEncryptor to create the Encryptor obj
symmetricKey.Mode = CipherMode.CFB;
//create encryptor from the key and the IV value
// ICryptoTransform encryptor = symmetricKey.CreateEncryptor(key, rgbIV);
ICryptoTransform decryptor = symmetricKey.CreateDecryptor(key, rgbIV);
//define memory stream to hold encrypted data
using (MemoryStream ms = new MemoryStream(disguishedtextBytes))
{
//define cryptographic stream - contains the transformation to be used and the mode
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write))
{
byte[] plaintextBytes = new Byte[disguishedtextBytes.Length];
cs.Write(disguishedtextBytes, 0, disguishedtextBytes.Length);
cs.FlushFinalBlock();
//convert decrypted data from a memory stream into a byte array
byte[] visiabletextBytes = ms.ToArray();
visiabletext = Encoding.UTF8.GetString(visiabletextBytes);
}
}
}
return visiabletext;
}
Helper Methods:
private static RijndaelManaged BuildRigndaelCommon(out byte[] rgbIV, out byte[] key)
{
rgbIV = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x5, 0x6, 0x7, 0x8, 0xA, 0xB, 0xC, 0xD, 0xF, 0x10, 0x11, 0x12 };
key = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x5, 0x6, 0x7, 0x8, 0xA, 0xB, 0xC, 0xD, 0xF, 0x10, 0x11, 0x12 };
//Specify the algorithms key & IV
RijndaelManaged rijndael = new RijndaelManaged{BlockSize = 128, IV = rgbIV, KeySize = 128, Key = key, Padding = PaddingMode.None};
return rijndael;
}
public static byte[] FromHexString(string hexString)
{
if (hexString == null)
{
return new byte[0];
}
var numberChars = hexString.Length;
var bytes = new byte[numberChars / 2];
for (var i = 0; i < numberChars; i += 2)
{
bytes[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16);
}
return bytes;
}
I'm getting various errors regarding the length of the string and that the padding is invalid. Has anybody any ideas to get the decryption working. I've tried padding out the input string back to 32 bytes but no avail.
Your problem is a subtle error in your Encrypt method. You are losing data from your returned ciphertext by messing with the the hexOutput string. Instead of:
//store result as a hex value
string hexOutput = BitConverter.ToString(cipherTextBytes).Replace("-", "");
hexOutput = hexOutput.Substring(0, plaintext.Length * 2);
//finially return encrypted string
return hexOutput;
You should just return the output:
return BitConverter.ToString(cipherTextBytes).Replace("-", "");
You will also need to change the padding mode in your Decrypt method to None. Though this will now correctly decrypt it will also include the manual padding characters that you add in your encrypt method. As you don't know your plain text you have no GOOD way of removing them. You could always add a method to remove all bytes in your array that dont match your padding value of zero:
int endMarker = decryptedData.Length;
do { endMarker--; } while (decryptedData[endMarker] == 0);
Array.Resize(ref decryptedData, endMarker + 1);
However this isn't really a good idea as you're possibly discarding otherwise valid data. A better solution would be to update your encrypt and decrypt methods to let the cipher handle the padding. Putting it all together we get (showing only what i've changed):
private static RijndaelManaged BuildRigndaelCommon(out byte[] rgbIV, out byte[] key)
{
rgbIV = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x5, 0x6, 0x7, 0x8, 0xA, 0xB, 0xC, 0xD, 0xF, 0x10, 0x11, 0x12 };
key = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x5, 0x6, 0x7, 0x8, 0xA, 0xB, 0xC, 0xD, 0xF, 0x10, 0x11, 0x12 };
//Specify the algorithms key & IV
RijndaelManaged rijndael = new RijndaelManaged{BlockSize = 128, IV = rgbIV, KeySize = 128, Key = key, Padding = PaddingMode.PKCS7 };
return rijndael;
}
public static string Encrypt(string plaintext)
{
byte[] rgbIV;
byte[] key;
RijndaelManaged rijndael = BuildRigndaelCommon(out rgbIV, out key);
//convert plaintext into a byte array
byte[] plaintextBytes = Encoding.UTF8.GetBytes(plaintext);
byte[] cipherTextBytes = null;
//create uninitialized Rijndael encryption obj
using (RijndaelManaged symmetricKey = new RijndaelManaged())
{
//Call SymmetricAlgorithm.CreateEncryptor to create the Encryptor obj
var transform = rijndael.CreateEncryptor();
//Chaining mode
symmetricKey.Mode = CipherMode.CFB;
//create encryptor from the key and the IV value
ICryptoTransform encryptor = symmetricKey.CreateEncryptor(key, rgbIV);
//define memory stream to hold encrypted data
using (MemoryStream ms = new MemoryStream())
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
//encrypt contents of cryptostream
cs.Write(plaintextBytes, 0, plaintextBytes.Length);
cs.Flush();
cs.FlushFinalBlock();
//convert encrypted data from a memory stream into a byte array
ms.Position = 0;
cipherTextBytes = ms.ToArray();
ms.Close();
cs.Close();
}
}
//store result as a hex value
return BitConverter.ToString(cipherTextBytes).Replace("-", "");
}
public static string Decrypt(string disguisedtext)
{
byte[] disguishedtextBytes = FromHexString(disguisedtext);
byte[] rgbIV;
byte[] key;
BuildRigndaelCommon(out rgbIV, out key);
string visiabletext = "";
//create uninitialized Rijndael encryption obj
using (var symmetricKey = new RijndaelManaged())
{
//Call SymmetricAlgorithm.CreateEncryptor to create the Encryptor obj
symmetricKey.Mode = CipherMode.CFB;
symmetricKey.BlockSize = 128;
//create encryptor from the key and the IV value
// ICryptoTransform encryptor = symmetricKey.CreateEncryptor(key, rgbIV);
ICryptoTransform decryptor = symmetricKey.CreateDecryptor(key, rgbIV);
//define memory stream to hold encrypted data
using (MemoryStream ms = new MemoryStream(disguishedtextBytes))
{
//define cryptographic stream - contains the transformation to be used and the mode
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
{
byte[] decryptedData = new byte[disguishedtextBytes.Length];
int stringSize = cs.Read(decryptedData, 0, disguishedtextBytes.Length);
cs.Close();
//Trim the excess empty elements from the array and convert back to a string
byte[] trimmedData = new byte[stringSize];
Array.Copy(decryptedData, trimmedData, stringSize);
visiabletext = Encoding.UTF8.GetString(trimmedData);
}
}
}
return visiabletext;
}
Hope this helps point you on your way. As an aside I maintain a set of encryption utilities on Snipt that may be of use to you, particularly the SymmetricEncrypt and SymmetricDecrypt methods.
------ EDIT ------
As noted in the comment below, we are not allowed to alter the Encrypt method. I do like a good challenge! With appropriate byte mangling applied, here's a decrypt that honours the return coming form the Encrypt method:
public static string Decrypt(string disguisedtext)
{
byte[] disguishedtextBytes = FromHexString(disguisedtext);
var originalLength = disguishedtextBytes.Length;
int BlockSize;
BlockSize = 16 * (1 + (originalLength / 16));
Array.Resize(ref disguishedtextBytes, BlockSize);
// fill the remaining space with 0
for (int i = originalLength; i < BlockSize; i++)
{
disguishedtextBytes[i] = 0;
}
byte[] rgbIV;
byte[] key;
BuildRigndaelCommon(out rgbIV, out key);
string visiabletext = "";
//create uninitialized Rijndael encryption obj
using (var symmetricKey = new RijndaelManaged())
{
//Call SymmetricAlgorithm.CreateEncryptor to create the Encryptor obj
symmetricKey.Mode = CipherMode.CFB;
symmetricKey.BlockSize = 128;
symmetricKey.Padding = PaddingMode.None;
// ICryptoTransform encryptor = symmetricKey.CreateEncryptor(key, rgbIV);
ICryptoTransform decryptor = symmetricKey.CreateDecryptor(key, rgbIV);
//define memory stream to hold encrypted data
using (MemoryStream ms = new MemoryStream(disguishedtextBytes))
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
{
byte[] decryptedData = new byte[disguishedtextBytes.Length];
int stringSize = cs.Read(decryptedData, 0, disguishedtextBytes.Length);
cs.Close();
//Trim the excess empty elements from the array and convert back to a string
byte[] trimmedData = new byte[stringSize];
Array.Copy(decryptedData, trimmedData, originalLength);
Array.Resize(ref trimmedData, originalLength);
visiabletext = Encoding.UTF8.GetString(trimmedData);
}
}
return visiabletext;
}