• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 4127
  • Last Modified:

Specified key is not a valid size for this algorithm

I have the following Encryption algorithm and I am getting the Specified key is not a valid size for this algorithm error.

        public string Encrypt(string toEncrypt, bool useHashing, string key)
        {
            // If string is null or whitespace, return toEncrypt
            if (String.IsNullOrEmpty(toEncrypt) || String.IsNullOrWhiteSpace(toEncrypt) || toEncrypt.Equals(DBNull.Value))
                return toEncrypt;

            // Strip blanks from end of string
            toEncrypt = toEncrypt.Trim();
     
            byte[] keyArray;
            byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);

            System.Configuration.AppSettingsReader settingsReader = new AppSettingsReader();
            if (String.IsNullOrEmpty(key))
                // Get the key from config file
                key = (string)settingsReader.GetValue("SecurityKey", typeof(String));
            //System.Windows.Forms.MessageBox.Show(key);
            if (useHashing)
            {
                //MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
                SHA512CryptoServiceProvider hashmd5 = new SHA512CryptoServiceProvider();
                keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
                hashmd5.Clear();
            }
            else
                keyArray = UTF8Encoding.UTF8.GetBytes(key);

            TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
            tdes.Key = keyArray;
            tdes.Mode = CipherMode.ECB;
            tdes.Padding = PaddingMode.PKCS7;

            ICryptoTransform cTransform = tdes.CreateEncryptor();
            byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
            tdes.Clear();
            return Convert.ToBase64String(resultArray, 0, resultArray.Length);
        }

Open in new window

The above code is in a DLL that is registered on the server.

Here is the code that I am using to test the DLL.

<%@LANGUAGE="VBSCRIPT"%>
<%
Set Encrypt = Server.CreateObject("EnCryptDecrypt.CryptorEngine")

tmpStr = Encrypt.Encrypt("12345", true, "abcdefghijklmnop")
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
</head>

<body>
<p>Encryption Test</p>
<% Response.Write tmpStr %>
</body>
</html>

Open in new window


I can't figure out why the error is occurring since the key being used is 16 characters which should be 128 bits.  The SHA512 supports 128 bit, 192 bit and 256 bit keys.

Any help would be great!
0
dyarosh
Asked:
dyarosh
  • 17
  • 13
  • 3
1 Solution
 
rharland2009Commented:
SHA512 uses hexadecimal digits. Hexadecimal digits are 4 bits per. I think you need 32.
0
 
dyaroshAuthor Commented:
Does my key have to be in HEX?  I tried the following key and got the same error message:

tmpStr = Encrypt.Encrypt("12345", true, "abcdefghijklmnopqrstuvwxyz123456")
0
 
rharland2009Commented:
No, it should not need to be in hex.
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
dyaroshAuthor Commented:
I still get the error using this as the key: abcdefghijklmnopqrstuvwxyz123456

Any thoughts?
0
 
rharland2009Commented:
Each of those characters is a byte, not a bit.
I think you need to shorten it to match the keylength you're after.
0
 
arnoldCommented:
Wy are you using UTF8 for encoding?can you as part of your test output what the key length is and the string that is being passed to the encrypt function.
0
 
dyaroshAuthor Commented:
I modified my the Encryption Program to return the KeyHashSize and I modified my calling program to tell me how many bytes are in my key.  Here are the results:

String to encrypt: 12345
Key: abcdefghijklmnopqrstuvwxyz123456
Results: Encryption Key: 256     Key in Bytes: 32

I'm still getting the invalid key size error.  I should say that I modified my original post to use SHA256CryptoServiceProvider hashmd5 = new SHA256CryptoServiceProvider();

As to why I'm using UTF8 for encoding:  I copied this algorithm from a post that I found on the web.

Any other thoughts?
0
 
arnoldCommented:
Which .net framework are you working with?
http://msdn.microsoft.com/en-us/library/system.security.cryptography.sha512cryptoserviceprovider.aspx

You have several from triple des, des, and sha512 within the DLL.
0
 
dyaroshAuthor Commented:
.Net Framework 4
0
 
arnoldCommented:
The computeHASH method requires three parameters.
Or it takes a stream of data

Your key is effectively an integer representing the number of bytes in the string you passed.
http://msdn.microsoft.com/en-us/library/xsy6z64h%28v=vs.100%29.aspx

http://msdn.microsoft.com/en-us/library/system.security.cryptography.sha512%28v=vs.100%29.aspx
0
 
dyaroshAuthor Commented:
I don't see where it requires 3 parameters:

HashAlgorithm.ComputeHash Method (Byte[])

I am passing it a byte array by calling UTF8Encoding.UTF8.GetBytes(key).
0
 
arnoldCommented:
GetBytes reports the bytes as int.

The link http://msdn.microsoft.com/en-us/library/system.security.cryptography.sha512%28v=vs.100%29.aspx 
ref ComputeHash there are three options.

The link dealing with the GetBytes method of the UTF-8 returns an INT and not a string array.
0
 
dyaroshAuthor Commented:
I see your point about GetBytes but here is a test that I've done and the attached file shows the results.

namespace CVL
{
    public partial class test : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }
        protected void EncryptBtn_Click(object sender, EventArgs e)
        {
            string key = KeyValue.Text;
            byte[] keyArray;
            keyArray = UTF8Encoding.UTF8.GetBytes(key);
            string tmpStr = keyArray.Count().ToString() + "<br />";
            
            foreach (byte k in keyArray)
            {
                tmpStr = tmpStr + k + "<br />";
            }
            StatusMsg.Text = tmpStr;
            //CryptorEngine encrypt = new CryptorEngine();
            //StatusMsg.Text = encrypt.Encrypt(EncryptValue.Text, true, key);
            //StatusMsg.Text = StatusMsg.Text + "   Key in Bytes: " + tmpStr;
        }
    }
}

Open in new window


So from what I can tell I am returning a byte array that has 32 elements which is the key size.
UTF8.GetBytes.bmp
0
 
arnoldCommented:
I am not sure what the output is.
0
 
dyaroshAuthor Commented:
32 is the number of bytes in the array.  The values after represent the bytes of the key.  I'm showing that my key is 32 bytes and this line

keyArray = UTF8Encoding.UTF8.GetBytes(key);

is returning a byte array.
0
 
dyaroshAuthor Commented:
I have narrowed down the error to coming from the 3DES code but still don't know why.  This screen shot shows the key I'm using (16 characters), number of bytes in byte array and the values in the byte array.
3DESerror.bmp
0
 
dyaroshAuthor Commented:
Found the problem.  The ComputeHash is returning a 32 byte array regardless of how few characters are in the key.  The 3DES needs a key that is 16 or 24 bytes.

Since I can't use 3DES, do you have any suggestions for finishing the encryption?  I need it to be FIPs compliant.
0
 
arnoldCommented:
I think 3des has to use a hex key 0-9 and a-f
http://www.cryptosys.net/3des.html
0
 
dyaroshAuthor Commented:
I installed the app on 3 other servers and don't have the problem on them so I've narrowed the problem down to something specific on the production server.  One of the things I discovered is the production server doesn't seem to be referencing the corrrect algorithm (see screen shot).  The error indicates that it is using the RijindaelManaged which is not FIPs compliant.  In my code I am using Rijindael as shown below.

        public string Encrypt(string PlainText, string key, string Salt="21stIn", 
            string HashAlgorithm = "SHA1", int PasswordIterations = 2,
            string InitialVector = "OFRna73m*aze01xY", int KeySize = 256)
        {
            // If string is null or whitespace, return toEncrypt
            if (String.IsNullOrEmpty(PlainText) || String.IsNullOrWhiteSpace(PlainText) || PlainText.Equals(DBNull.Value))
                return "";

            // Strip blanks from end of string
            PlainText = PlainText.Trim();

            System.Configuration.AppSettingsReader settingsReader = new AppSettingsReader();
            if (String.IsNullOrEmpty(key))
                // Get the key from config file
                key = (string)settingsReader.GetValue("SecurityKey", typeof(String));
            
            byte[] InitialVectorBytes = Encoding.ASCII.GetBytes(InitialVector);
            byte[] SaltValueBytes = Encoding.ASCII.GetBytes(Salt);
            byte[] PlainTextBytes = Encoding.UTF8.GetBytes(PlainText);
            PasswordDeriveBytes DerivedPassword = new PasswordDeriveBytes(key, SaltValueBytes, HashAlgorithm, PasswordIterations);  
            byte[] KeyBytes = DerivedPassword.GetBytes(KeySize / 8);
            [b]Rijndael SymmetricKey = Rijndael.Create();[/b]            SymmetricKey.Mode = CipherMode.CBC;
            byte[] CipherTextBytes = null;
            using (ICryptoTransform Encryptor = SymmetricKey.CreateEncryptor(KeyBytes, InitialVectorBytes))
            {
                using (MemoryStream MemStream = new MemoryStream())
                {
                    using (CryptoStream CryptoStream = new CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write))
                    {
                        CryptoStream.Write(PlainTextBytes, 0, PlainTextBytes.Length);
                        CryptoStream.FlushFinalBlock();
                        CipherTextBytes = MemStream.ToArray();
                        MemStream.Close();
                        CryptoStream.Close();
                    }
                }
            }
            SymmetricKey.Clear();
            return Convert.ToBase64String(CipherTextBytes);
        }

Open in new window


So my question is, how do I find out why the production server is using the Managed version while the other servers are not?  I've compared the IIS settings between the servers and I don't see a difference.
FIPs-Error.bmp
0
 
arnoldCommented:
.net version for the site? Double check the steps you follow when setting this up from scratch, versus the setup on the production server. Is the DLL have to be part f authorized components on the production system?
0
 
dyaroshAuthor Commented:
I haven't setup any of the servers.  I have access to the servers.  How do I check if DLL has to be part of authorized components?  How do I authorize it?  Production server is running Windows Server 2003.
0
 
arnoldCommented:
In IIS 6 you need to check web service extensions to see if the one you need is added and approved.
0
 
dyaroshAuthor Commented:
I checked Web Service Extensions and both machines have ASP.NET v4.0.30319.  I checked the aspnet_isapii.dll on both machines and they are the same size.  The only difference I see is that the machine that the DLL works on has Windows SharePoint Services v3 allowed under Web Extensions where the machine where the DLL is not working does not.  I am not using SharePoint Services that I am aware of.
0
 
arnoldCommented:
Is the DLL that includes these functions registered on both systems?
i.e. when you setting up your software on a new system, what process do you go through?
Was the same process followed for the production system?
0
 
dyaroshAuthor Commented:
That I can't answer because my group does not set up the systems.
0
 
arnoldCommented:
You have a custom DLL that includes your encryption functions. Does that DLL get added to the production environment or is your encrypt.encrypt method in the code uses a system DLL function rather than your own.
0
 
dyaroshAuthor Commented:
I use the following to register my custom DLL:

%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\regasm EncryptDecrypt.dll /codebase /tlb:EnCryptDecrypt.tlb

I run this from the folder where my DLL is.
0
 
arnoldCommented:
Based on your issue, the DLL does not seem to register or you have a misconfiguration where the code you think is being executed is not being run on the production server while running everywhere else.

The only thing that I can suggest is that you confirm that the code that exists on the production server is the code you are running on the development and other systems where it was setup.  One way is to add to your code an output line that is a comment in html
<!-- Version of your page code -->

This way view source on the production output will tell you whether the issue is with the server/code or it still has an incorrect version.

You can use the comment options as a means to debug as well. i.e. check if debug variable is set within your code, and output data points of interest within comments or write debug data into a database.


The code you posted does use FIPS as the test.
What is the process within your firm that gets your code onto the production system?


When you say you run the code to register the DLL, do you first unregister the old ones you had?
regasm /u EncryptDecrypt.dll?

This might be what the difference is.
Try it first on a test system where this code currently does not exist. Register an older version of your DLL.
See what happens. then try to update the setup with a newer version. Does the issue remain or does the setup start functioning?
0
 
dyaroshAuthor Commented:
I did as you suggested and still have the same problem.  At this point I think the problem has to be on the Production server and not with my code.  I am able to run on a different production server ok so at this point I am going to have to install my application on that server.  I appreciate all your help.
0
 
arnoldCommented:
You mean you added the comment identifier and it reflects the correct response but still getting the same error? Double check the calling page to make sure it is not the one with the wrong crypto selector.
0
 
dyaroshAuthor Commented:
I would like to close this question without a result.  The problem still exists on the Production Server and we used a different server that didn't have the problem.
0
 
arnoldCommented:
Did this exchange help you at all?  I.e. comments helped to lead you to move this application to a new server, pick and assign whatever point value you want and close the question, alternatively you can ask to delete this question.
0
 
dyaroshAuthor Commented:
My problem still exists but your help enabled me to narrow down the problem to a specific server.  Since we are putting a plan in place to migrate our applications from that server to another one where the DLL works I am not going to pursue this any longer.  Thank you for your time and help on this.
0

Featured Post

Upgrade your Question Security!

Your question, your audience. Choose who sees your identity—and your question—with question security.

  • 17
  • 13
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now