2

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.

10
  • 2
    It's broken beyond repair. You can't change the output of the CryptoStream (with the Replace on the hexOutput variable) and expect to be able to decrypt the result. Commented Jul 5, 2013 at 7:23
  • That was my initially thought. However the encryption algorithm was copied from a Delphi implementation. In Delphi it was possible to decrypt this value which made me think it should somehow be possible in .net too. Commented Jul 5, 2013 at 7:32
  • It may work for some data, but probably only if the result of BitConvert result doesn't contain any hyphens... Commented Jul 5, 2013 at 7:37
  • The input has validation rules so won't contain hyphens. Commented Jul 5, 2013 at 7:53
  • BitConverter yields things like: 0A-34-F3-EE-00 The problem with the Replace method isn't a problem. However, the next line assumes each char is two bytes, which is a faulty assumption for UTF8. Commented Jul 5, 2013 at 8:39

2 Answers 2

4

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; } 
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for taking the time to reply. Unfortunately I cannot change the Encrypt method. It's actually used in another system that I've no control over. There are already values stored in the database based on that encryption algorithm. All I can change is the Decrypt method. This is the root of my problem.
@keitn - Updated to honour the Encrypt. Happy byte mangling :)
Thanks Wolfwyrd. I was doing something really stupid in hindsight I was calling my helper method BuildRigndaelCommon but wasn't assigning the output RijndaelManaged to a variable. Then further down I had "using (var symmetricKey = new RijndaelManaged())". I was changing the padding settings in the helper method but obviously that had no affect. Thanks again.
0

It looks like your encryption method outputs a space separated hex string, representing a byte array: "OA FE 82 3B ...". It also makes assumptions about the plaintext and chops off any padding.

Your first step it to convert the hex string back into a byte array, which is pretty easy.

To deal with the lost padding just set decryption to NoPadding, as @Wolfwyrd suggests. You may have to check that your data is correctly terminated if the padding length was off.

If the assumptions about plaintext characters were wrong, then it is likely you will have to recover things by hand. If the plaintext is strict ASCII (7 bit characters only) then this should not be a problem. Anything outside that, such as accented letters: á, é etc. will break the assumption.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.