Solved

URGENT Plzzz... Decrypted string is not same as original string.

Posted on 2006-11-19
8
1,193 Views
Last Modified: 2012-05-05
Hello Friends,

Can you please help me fix the problem with the following code, I am using for encryption and decryption of free text?
After the string is encrypted, I am storing the encrypted string in the database, but when I am sending this information back to the user after the decryption, the decrypted string is not same as original text.

Example: I encrypted the original string "yagya" and stored the encrypted string in the database. But when I retrieve the string from the database and decrypt the string, the result comes to be "yag??". Which is not the original string (yagya). I am using the following code to do this..You may use your own password key to test the code.

Please let me know where exactly this is the problem. I am expecting a fully functional code to encrypt the string of any length.

Thanks for the assistance!
Run2004


using System;
using System.IO;
using System.Text;
using System.Security;
using System.Security.Cryptography;
using System.Web.Services;

namespace FE_SymmetricNamespace
{
public class FE_Symmetric
{
      static private Byte[] m_Key = new Byte[8];
      static private Byte[] m_IV = new Byte[8];
      
      //////////////////////////
      //Function to encrypt data
      public string EncryptData(String strKey, String strData)
      {
            string strResult;            //Return Result

            //1. String Length cannot exceed 90Kb. Otherwise, buffer will overflow. See point 3 for reasons
            if (strData.Length > 92160)
            {
                  strResult="Error. Data String too large. Keep within 90Kb.";
                  return strResult;
            }
      
            //2. Generate the Keys
            if (!InitKey(strKey))
            {
                  strResult="Error. Fail to generate key for encryption";
                  return strResult;
            }

            //3. Prepare the String
            //      The first 5 character of the string is formatted to store the actual length of the data.
            //      This is the simplest way to remember to original length of the data, without resorting to complicated computations.
            //      If anyone figure a good way to 'remember' the original length to facilite the decryption without having to use additional function parameters, pls let me know.
            strData = String.Format("{0,5:00000}"+strData, strData.Length);


            //4. Encrypt the Data
            byte[] rbData = new byte[strData.Length];
            ASCIIEncoding aEnc = new ASCIIEncoding();
            aEnc.GetBytes(strData, 0, strData.Length, rbData, 0);
            
            DESCryptoServiceProvider descsp = new DESCryptoServiceProvider();
            
            ICryptoTransform desEncrypt = descsp.CreateEncryptor(m_Key, m_IV);


            //5. Perpare the streams:
            //      mOut is the output stream.
            //      mStream is the input stream.
            //      cs is the transformation stream.
            MemoryStream mStream = new MemoryStream(rbData);
            CryptoStream cs = new CryptoStream(mStream, desEncrypt, CryptoStreamMode.Read);        
            MemoryStream mOut = new MemoryStream();
            
            //6. Start performing the encryption
            int bytesRead;
            byte[] output = new byte[1024];
            do
            {
                  bytesRead = cs.Read(output,0,1024);
                  if (bytesRead != 0)
                        mOut.Write(output,0,bytesRead);
            } while (bytesRead > 0);
            
            //7. Returns the encrypted result after it is base64 encoded
            //      In this case, the actual result is converted to base64 so that it can be transported over the HTTP protocol without deformation.
            if (mOut.Length == 0)            
                  strResult = "";
            else
                  strResult = Convert.ToBase64String(mOut.GetBuffer(), 0, (int)mOut.Length);
      
            return strResult;
      }

      //////////////////////////
      //Function to decrypt data
      public string DecryptData(String strKey, String strData)
      {
            string strResult;

            //1. Generate the Key used for decrypting
            if (!InitKey(strKey))
            {
                  strResult="Error. Fail to generate key for decryption";
                  return strResult;
            }

            //2. Initialize the service provider
            int nReturn = 0;
            DESCryptoServiceProvider descsp = new DESCryptoServiceProvider();
            ICryptoTransform desDecrypt = descsp.CreateDecryptor(m_Key, m_IV);
            
            //3. Prepare the streams:
            //      mOut is the output stream.
            //      cs is the transformation stream.
            MemoryStream mOut = new MemoryStream();
            CryptoStream cs = new CryptoStream(mOut, desDecrypt, CryptoStreamMode.Write);        
            
            //4. Remember to revert the base64 encoding into a byte array to restore the original encrypted data stream
            byte[] bPlain = new byte[strData.Length];
            try
            {
                  bPlain = Convert.FromBase64CharArray(strData.ToCharArray(), 0, strData.Length);
            }
            catch (Exception)
            {
                  strResult = "Error. Input Data is not base64 encoded.";
                  return strResult;
            }
            
            long lRead = 0;
            long lTotal = strData.Length;
            
            try
            {
                  //5. Perform the actual decryption
                  while (lTotal >= lRead)
                  {
                      cs.Write(bPlain,0,(int)bPlain.Length);
                      //descsp.BlockSize=64
                      lRead = mOut.Length + Convert.ToUInt32(((bPlain.Length / descsp.BlockSize) * descsp.BlockSize));
                  };
                  
                  ASCIIEncoding aEnc = new ASCIIEncoding();
                  strResult = aEnc.GetString(mOut.GetBuffer(), 0, (int)mOut.Length);
                  
                  //6. Trim the string to return only the meaningful data
                  //      Remember that in the encrypt function, the first 5 character holds the length of the actual data
                  //      This is the simplest way to remember to original length of the data, without resorting to complicated computations.
                  String strLen = strResult.Substring(0,5);
                  int nLen = Convert.ToInt32(strLen);
                  strResult = strResult.Substring(5, nLen);
                  nReturn = (int)mOut.Length;
                  
                  return strResult;
            }
            catch (Exception)
            {
                  strResult = "Error. Decryption Failed. Possibly due to incorrect Key or corrputed data";
                  return strResult;
            }
      }

      /////////////////////////////////////////////////////////////
      //Private function to generate the keys into member variables
      static private bool InitKey(String strKey)
      {
            try
            {
                  // Convert Key to byte array
                  byte[] bp = new byte[strKey.Length];
                  ASCIIEncoding aEnc = new ASCIIEncoding();
                  aEnc.GetBytes(strKey, 0, strKey.Length, bp, 0);
                  
                  //Hash the key using SHA1
                  SHA1CryptoServiceProvider sha = new SHA1CryptoServiceProvider();
                  byte[] bpHash = sha.ComputeHash(bp);
                  
                  int i;
                  // use the low 64-bits for the key value
                  for (i=0; i<8; i++)
                        m_Key[i] = bpHash[i];
                        
                  for (i=8; i<16; i++)
                        m_IV[i-8] = bpHash[i];
                  
                  return true;
            }
            catch (Exception)
            {
                  //Error Performing Operations
                  return false;
            }
      }
}
}

0
Comment
Question by:run2004
8 Comments
 
LVL 20

Assisted Solution

by:Daniel Van Der Werken
Daniel Van Der Werken earned 150 total points
ID: 17975564
I tested your encryption as follows and it works.  If you're missing the last two characters of the decrypted text, maybe it's not coming back from the database correctly?

Make sure the cyphertext you send to the dB is the same that comes out.

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Security;
using System.Security.Cryptography;
using System.Web;

namespace ConsoleApplication1
{
    class Cypher
    {
        public Byte[] m_Key = new Byte[8];
        public Byte[] m_IV = new Byte[8];

        public string EncryptData(String strKey, String strData)
        {
            string strResult;          //Return Result

            //1. String Length cannot exceed 90Kb. Otherwise, buffer will overflow. See point 3 for reasons
            if (strData.Length > 92160)
            {
                strResult = "Error. Data String too large. Keep within 90Kb.";
                return strResult;
            }

            //2. Generate the Keys
            if (!InitKey(strKey))
            {
                strResult = "Error. Fail to generate key for encryption";
                return strResult;
            }

            //3. Prepare the String
            //     The first 5 character of the string is formatted to store the actual length of the data.
            //     This is the simplest way to remember to original length of the data, without resorting to complicated computations.
            //     If anyone figure a good way to 'remember' the original length to facilite the decryption without having to use additional function parameters, pls let me know.
            strData = String.Format("{0,5:00000}" + strData, strData.Length);


            //4. Encrypt the Data
            byte[] rbData = new byte[strData.Length];
            ASCIIEncoding aEnc = new ASCIIEncoding();
            aEnc.GetBytes(strData, 0, strData.Length, rbData, 0);

            DESCryptoServiceProvider descsp = new DESCryptoServiceProvider();

            ICryptoTransform desEncrypt = descsp.CreateEncryptor(m_Key, m_IV);


            //5. Perpare the streams:
            //     mOut is the output stream.
            //     mStream is the input stream.
            //     cs is the transformation stream.
            MemoryStream mStream = new MemoryStream(rbData);
            CryptoStream cs = new CryptoStream(mStream, desEncrypt, CryptoStreamMode.Read);
            MemoryStream mOut = new MemoryStream();

            //6. Start performing the encryption
            int bytesRead;
            byte[] output = new byte[1024];
            do
            {
                bytesRead = cs.Read(output, 0, 1024);
                if (bytesRead != 0)
                    mOut.Write(output, 0, bytesRead);
            } while (bytesRead > 0);

            //7. Returns the encrypted result after it is base64 encoded
            //     In this case, the actual result is converted to base64 so that it can be transported over the HTTP protocol without deformation.
            if (mOut.Length == 0)
                strResult = "";
            else
                strResult = Convert.ToBase64String(mOut.GetBuffer(), 0, (int)mOut.Length);

            return strResult;
        }

        public string DecryptData(String strKey, String strData)
        {
            string strResult;

            //1. Generate the Key used for decrypting
            if (!InitKey(strKey))
            {
                strResult = "Error. Fail to generate key for decryption";
                return strResult;
            }

            //2. Initialize the service provider
            int nReturn = 0;
            DESCryptoServiceProvider descsp = new DESCryptoServiceProvider();
            ICryptoTransform desDecrypt = descsp.CreateDecryptor(m_Key, m_IV);

            //3. Prepare the streams:
            //     mOut is the output stream.
            //     cs is the transformation stream.
            MemoryStream mOut = new MemoryStream();
            CryptoStream cs = new CryptoStream(mOut, desDecrypt, CryptoStreamMode.Write);

            //4. Remember to revert the base64 encoding into a byte array to restore the original encrypted data stream
            byte[] bPlain = new byte[strData.Length];
            try
            {
                bPlain = Convert.FromBase64CharArray(strData.ToCharArray(), 0, strData.Length);
            }
            catch (Exception)
            {
                strResult = "Error. Input Data is not base64 encoded.";
                return strResult;
            }

            long lRead = 0;
            long lTotal = strData.Length;

            try
            {
                //5. Perform the actual decryption
                while (lTotal >= lRead)
                {
                    cs.Write(bPlain, 0, (int)bPlain.Length);
                    //descsp.BlockSize=64
                    lRead = mOut.Length + Convert.ToUInt32(((bPlain.Length / descsp.BlockSize) * descsp.BlockSize));
                };

                ASCIIEncoding aEnc = new ASCIIEncoding();
                strResult = aEnc.GetString(mOut.GetBuffer(), 0, (int)mOut.Length);

                //6. Trim the string to return only the meaningful data
                //     Remember that in the encrypt function, the first 5 character holds the length of the actual data
                //     This is the simplest way to remember to original length of the data, without resorting to complicated computations.
                String strLen = strResult.Substring(0, 5);
                int nLen = Convert.ToInt32(strLen);
                strResult = strResult.Substring(5, nLen);
                nReturn = (int)mOut.Length;

                return strResult;
            }
            catch (Exception)
            {
                strResult = "Error. Decryption Failed. Possibly due to incorrect Key or corrputed data";
                return strResult;
            }
        }

        private bool InitKey(String strKey)
        {
            try
            {
                // Convert Key to byte array
                byte[] bp = new byte[strKey.Length];
                ASCIIEncoding aEnc = new ASCIIEncoding();
                aEnc.GetBytes(strKey, 0, strKey.Length, bp, 0);

                //Hash the key using SHA1
                SHA1CryptoServiceProvider sha = new SHA1CryptoServiceProvider();
                byte[] bpHash = sha.ComputeHash(bp);

                int i;
                // use the low 64-bits for the key value
                for (i = 0; i < 8; i++)
                    m_Key[i] = bpHash[i];

                for (i = 8; i < 16; i++)
                    m_IV[i - 8] = bpHash[i];

                return true;
            }
            catch (Exception)
            {
                //Error Performing Operations
                return false;
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Cypher c = new Cypher();
            string TextString = "yagya";
            string ClearText = String.Empty;
            string CypherText = String.Empty;
            string key = "ABC";

            CypherText = c.EncryptData(key, TextString);
            ClearText = c.DecryptData(key, CypherText);

            Console.Write("Hello There\n");
        }
    }
}
0
 
LVL 15

Assisted Solution

by:ozymandias
ozymandias earned 300 total points
ID: 17975572
Your code works fine for me.

FE_Symmetric f = new FE_Symmetric();
string key = "keystring";
string text = "mary had a little lamb";
string s1 = f.EncryptData(key, text);
string s2 = f.DecryptData(key, s1);
Console.WriteLine(text);
Console.WriteLine(s1);
Console.WriteLine(s2);
Console.ReadLine();

produces this output :

mary had a little lamb
07OSXsP/ES0FNsZwDqTu/QZ+gJojItd6IThmZksUp/Q=
mary had a little lamb

So the encryption and decryption work fine.
It maybe that when you store the encrypted string in the database and then retrieve it something happens to it.
0
 
LVL 29

Expert Comment

by:Nightman
ID: 17975878
What database engine - I am assuming SQL.
What is the datatype in the database?
What length is the datatype in the database? (e.g. if varchar, is it varchar(20), etc).
What collation is the column in the database?
0
Courses: Start Training Online With Pros, Today

Brush up on the basics or master the advanced techniques required to earn essential industry certifications, with Courses. Enroll in a course and start learning today. Training topics range from Android App Dev to the Xen Virtualization Platform.

 
LVL 1

Author Comment

by:run2004
ID: 17982890
Nightman,

The database is SQL Server 2005. The field length is verchar(100). So this is my understanding that inserting the record should not be a problem.

I did observe one thing that the encrypted string ends with ==. So does this mean anything to SQL server(Equality).

I am blank on this. Let me know if you have any clue on this.

Thanks!
Run2004
0
 
LVL 1

Author Comment

by:run2004
ID: 17982930
Forgot to add one more thing. When I am inserting the record in the database, the last four characters are being lost. Now I see why I am not getting the original string after the decryption.

Thanks ozymandias  and Dan7el for pointing this out.
0
 
LVL 29

Accepted Solution

by:
Nightman earned 50 total points
ID: 17982993
Try changing the column datatype to nvarchar(100)
0
 
LVL 1

Author Comment

by:run2004
ID: 17983241
I tried this by changing the field to nvarchar(100). The problem is still there.
0
 
LVL 1

Author Comment

by:run2004
ID: 17992231
I found out the cause of the problem. My code was referring the old assembly that had parameter defined for 20 characters.

It's working fine now.

Thanks for all your support.
0

Featured Post

Gigs: Get Your Project Delivered by an Expert

Select from freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely and get projects done right.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction Although it is an old technology, serial ports are still being used by many hardware manufacturers. If you develop applications in C#, Microsoft .NET framework has SerialPort class to communicate with the serial ports.  I needed to…
We all know that functional code is the leg that any good program stands on when it comes right down to it, however, if your program lacks a good user interface your product may not have the appeal needed to keep your customers happy. This issue can…
This tutorial gives a high-level tour of the interface of Marketo (a marketing automation tool to help businesses track and engage prospective customers and drive them to purchase). You will see the main areas including Marketing Activities, Design …
Email security requires an ever evolving service that stays up to date with counter-evolving threats. The Email Laundry perform Research and Development to ensure their email security service evolves faster than cyber criminals. We apply our Threat…

786 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question