Solved

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

Posted on 2006-11-19
8
1,181 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 19

Assisted Solution

by:Daniel Van Der Werken
Daniel Van Der Werken earned 150 total points
Comment Utility
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
Comment Utility
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
Comment Utility
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
 
LVL 1

Author Comment

by:run2004
Comment Utility
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
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 1

Author Comment

by:run2004
Comment Utility
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
Comment Utility
Try changing the column datatype to nvarchar(100)
0
 
LVL 1

Author Comment

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

Author Comment

by:run2004
Comment Utility
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

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Launch Process with NOT as Administrator 15 64
Pass through dll 2 33
Get String split 5 30
c# if statement weird reaction 3 27
Article by: Ivo
Anonymous Types in C# by Ivo Stoykov Anonymous Types are useful when  we do not need to follow usual work-flow -- creating object of some type, assign some read-only values and then doing something with them. Instead we can encapsulate this read…
Real-time is more about the business, not the technology. In day-to-day life, to make real-time decisions like buying or investing, business needs the latest information(e.g. Gold Rate/Stock Rate). Unlike traditional days, you need not wait for a fe…
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…

763 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

Need Help in Real-Time?

Connect with top rated Experts

7 Experts available now in Live!

Get 1:1 Help Now