Data decryption issue

T

Tom Andrecht

I'm trying to get some encryption/decryption routines going to take care of
my data, and while the encryption is working great, I keep running into the
message "Padding is invalid and cannot be removed" on the decryption piece.
From everything I can see, I am doing things correctly here My code is as
follows:

private const string PassStr = "MyPrivateKey";
private static readonly byte[] PassSalt = new byte[] { Byte Byte
Byte Byte Byte};
private static readonly Enabled en;

static Encryption()
{
en = new Enabled();
en.enabled = true;
}

private static byte[] TransDown(char[] TransString)
{
byte[] ResultStr = new byte[TransString.Length];

for (int i = 0; i < TransString.Length; i++)
ResultStr = Convert.ToByte(TransString);

return ResultStr;
}

private static char[] TransUp(Byte[] TransString)
{
char[] ResultStr = new char[TransString.Length];

for (int i = 0; i < TransString.Length; i++)
ResultStr = Convert.ToChar(TransString);

return ResultStr;
}

private static char[] TransDown(String TransString)
{
char[] ResultStr = new char[TransString.Length];

for (int i = 0; i < TransString.Length; i++)
ResultStr = Convert.ToChar(TransString);

return ResultStr;
}

public static char[] Encrypt(char[] InputString)
{
if (en.enabled)
{
if ((InputString != null) && (InputString.Length > 0))
{
char[] ResultStr = new char[32];
MemoryStream memoryStream;
CryptoStream cryptoStream;
RijndaelManaged rijndael = new RijndaelManaged();
ResultStr = TransDown(PassStr);
rijndael.Key = TransDown(ResultStr);
rijndael.IV = PassSalt;
rijndael.Padding = PaddingMode.PKCS7;
rijndael.Mode = CipherMode.CBC;
memoryStream = new MemoryStream();
cryptoStream = new CryptoStream(memoryStream,
rijndael.CreateEncryptor(), CryptoStreamMode.Write);
cryptoStream.Write(TransDown(InputString), 0,
InputString.Length);
cryptoStream.FlushFinalBlock();
//ResultStr = TransUp(memoryStream.ToArray());
cryptoStream.Close();
return TransUp(memoryStream.ToArray());
}
else
return TransDown("NULL");
}
else
return TransDown("Not Authorized");
}

public static char[] Decrypt(char[] InputString)
{
if (en.enabled)
{
if ((InputString != null) && (InputString.Length > 0))
{
char[] ResultStr = new char[32];
byte[] ResultByte = new byte[InputString.Length];
MemoryStream memoryStream = new
MemoryStream(TransDown(InputString));
memoryStream.Position = 0;
CryptoStream cryptoStream;
RijndaelManaged rijndael = new RijndaelManaged();
ResultStr = TransDown(PassStr);
rijndael.Key = TransDown(ResultStr);
rijndael.IV = PassSalt;
rijndael.Padding = PaddingMode.PKCS7;
rijndael.Mode = CipherMode.CBC;
cryptoStream = new CryptoStream(memoryStream,
rijndael.CreateDecryptor(), CryptoStreamMode.Read);
cryptoStream.Read(ResultByte, 0, InputString.Length);
cryptoStream.Close();
return TransUp(ResultByte);
}
else
return TransDown(" ") ;
}
else
return TransDown("Not Authorized");
}

The message I am getting is:

Msg 6522, Level 16, State 2, Line 1
A .NET Framework error occurred during execution of user defined routine or
aggregate 'Decrypt':
System.Security.Cryptography.CryptographicException: Padding is invalid and
cannot be removed.
System.Security.Cryptography.CryptographicException:
at System.Security.Cryptography.RijndaelManagedTransform.DecryptData(Byte[]
inputBuffer, Int32 inputOffset, Int32 inputCount, Byte[]& outputBuffer,
Int32 outputOffset, PaddingMode paddingMode, Boolean fLast)
at
System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[]
inputBuffer, Int32 inputOffset, Int32 inputCount)
at System.Security.Cryptography.CryptoStream.Read(Byte[] buffer, Int32
offset, Int32 count)
at SQLEncryption.Encryption.Decrypt(Char[] InputString)

Can anyone tell me where I am going wrong? I don't know the cryptography
components well enough to have a clue about what I am doing wrong. Thanks.
 
T

Tom Andrecht

Unfortunately I tried the built-in conversion routines and couldn't get them
to work. Maybe I've just been in Delphi too long to be able to figure this
stuff out again. As far as the Encrypt routine goes, I know it works
because I can successfully decrypt a single record at a time. The problem
comes into play when I'm trying to decrypt more than one record (passed in
from MSSQL). First one or two work great, then i get this blowing up. Is
there something I need to do to remove extra padding? I haven't seen
anything like that so far.

Tom
 
T

Tom Andrecht

Peter,

I do appreciate the advice. I did try the Convert routines again, and am
still running into trouble. Specifically, I have tried the
Convert.FromBase64CharArray and Convert.ToBase64CharArray functions, and am
running into roadblocks since my strings do not fit into the limits of
allowed characters (a..z, A..Z, 1..0, and +/). I have spaces and sometimes
other characters (@, and ' are the most common ones). For that reason, I
was using my own that would convert all. At this point, I don't know how I
could get everything to convert down without the functions I wrote, crude as
they are. Thanks

Tom
 
T

Tom Andrecht

Ok, I have the UTF8Encoding class in place, and it seems to be working fine.
Now I am trying to run the decrypt, and am getting an error that I can't
figure out. The Decrypt function is similar to the posted one, but with the
encoding changes. To use it, I'm running a SQL statement against the
function as "SELECT dbo.Decrypt(Name1) FROM Customers." Now I'm getting an
error as follows from MS SQL Server:

Msg 6522, Level 16, State 2, Line 1
A .NET Framework error occurred during execution of user defined routine or
aggregate 'Decrypt':
System.Security.Cryptography.CryptographicException: Padding is invalid and
cannot be removed.
System.Security.Cryptography.CryptographicException:
at
System.Security.Cryptography.RijndaelManagedTransform.DecryptData(Byte[]
inputBuffer, Int32 inputOffset, Int32 inputCount, Byte[]& outputBuffer,
Int32 outputOffset, PaddingMode paddingMode, Boolean fLast)
at
System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[]
inputBuffer, Int32 inputOffset, Int32 inputCount)
at System.Security.Cryptography.CryptoStream.FlushFinalBlock()
at System.Security.Cryptography.CryptoStream.Dispose(Boolean disposing)
at System.IO.Stream.Close()
at SQLEncryption.Encryption.Decrypt(Char[] InputString)
..

So, I have extra padding in place, but I don't know if the padding mode
matters. I've tried using PKCS7, ISO10126, and no padding modes. On the
PKCS7 and ISO10126, I can encrypt just fine, but the decrypt function
returns the above error, but the encrypt does not work when padding is
specified to be none.
 
T

Tom Andrecht

Ok, the overall problem is this. I have two functions in a C# .DLL as
follows:
public static char[] Encrypt(char[] InputString)
{
if (en.enabled)
{
if ((InputString != null) && (InputString.Length > 0))
{
MemoryStream memoryStream;
CryptoStream cryptoStream;
UTF8Encoding E = new UTF8Encoding();
RijndaelManaged rijndael = new RijndaelManaged();
rijndael.Key = E.GetBytes(PassStr);
rijndael.IV = PassSalt;
rijndael.Padding = PaddingMode.ISO10126;
rijndael.Mode = CipherMode.CBC;
memoryStream = new MemoryStream();
cryptoStream = new CryptoStream(memoryStream,
rijndael.CreateEncryptor(), CryptoStreamMode.Write);
cryptoStream.Write(E.GetBytes(InputString), 0,
InputString.Length);
cryptoStream.FlushFinalBlock();
cryptoStream.Close();
return E.GetChars(memoryStream.ToArray());
}
else
return TransDown("NULL");
}
else
return TransDown("Not Authorized");
}

public static char[] Decrypt(char[] InputString)
{
if (en.enabled)
{
if (InputString.ToString() == "NULL")
{
return TransDown("");
}
if ((InputString != null) && (InputString.Length > 0))
{
MemoryStream memoryStream;
CryptoStream cryptoStream;
UTF8Encoding E = new UTF8Encoding();
byte[] iString;
RijndaelManaged rijndael = new RijndaelManaged();
rijndael.Key = E.GetBytes(PassStr);
rijndael.IV = PassSalt;
rijndael.Padding = PaddingMode.ISO10126;
rijndael.Mode = CipherMode.CBC;
memoryStream = new MemoryStream();
cryptoStream = new CryptoStream(memoryStream,
rijndael.CreateDecryptor(), CryptoStreamMode.Write);
iString = E.GetBytes(InputString);
cryptoStream.Write(iString, 0, iString.Length);
cryptoStream.Close();
return E.GetChars(memoryStream.ToArray());
}
else
return TransDown("NULL");
}
else
return TransDown("Not Authorized");
}

This .DLL gets loaded into a MSSQL database and the functions get loaded as
Scalar-Valued functions. They are then called in SQL with statements such
as "SELECT dbo.DECRYPT(SSN) FROM CUSTOMER" to take the encrypted form of the
SSN and decrypt it for display to authorized users. The problem is, when I
encrypt with no padding, I get an error, but when I decrypt with some form
of padding (the same as used to encrypt), I get an error that the padding is
invalid.

Peter Duniho said:
Ok, I have the UTF8Encoding class in place, and it seems to be working
fine.

Except for the part that doesn't, of course. :)
Now I am trying to run the decrypt, and am getting an error that I can't
figure out. [...]

And you still haven't posted a concise-but-complete code sample.

My best guess, knowing very little about the encryption/decryption stuff
per se, but have some familiarity with this sort of "stream
transformation" stuff more generally, is that you are somehow trying to
pack multiple transformations (encryption/decryption) into a single stream
but without properly delineating each section. If true, that would result
in the transformation of one section incorrectly trying to use data from
another section.

Especially since you say it works fine when you encrypt/decrypt just one
section, this seems like a reasonably likely explanation.

Until you offer more information, I really don't see how anyone could
offer more specific advice.

Pete
 
A

Arne Vajhøj

Tom said:
Ok, the overall problem is this. I have two functions in a C# .DLL as
follows:
public static char[] Encrypt(char[] InputString)
{
if (en.enabled)
{
if ((InputString != null) && (InputString.Length > 0))
{
MemoryStream memoryStream;
CryptoStream cryptoStream;
UTF8Encoding E = new UTF8Encoding();
RijndaelManaged rijndael = new RijndaelManaged();
rijndael.Key = E.GetBytes(PassStr);
rijndael.IV = PassSalt;
rijndael.Padding = PaddingMode.ISO10126;
rijndael.Mode = CipherMode.CBC;
memoryStream = new MemoryStream();
cryptoStream = new CryptoStream(memoryStream,
rijndael.CreateEncryptor(), CryptoStreamMode.Write);
cryptoStream.Write(E.GetBytes(InputString), 0,
InputString.Length);

This is not good. The number of bytes in UTF-8 encoding and
the number of chars does not need to be the same.

cryptoStream.Write(E.GetBytes(InputString), 0,
E.GetByteCount(InputString));
cryptoStream.FlushFinalBlock();
cryptoStream.Close();
return E.GetChars(memoryStream.ToArray());

This is not good.

You should not try and save random bytes (which encrypted data is)
in chars or strings.

Return a byte array of convert to Base64 or Hex.
}
else
return TransDown("NULL");
}
else
return TransDown("Not Authorized");
}

public static char[] Decrypt(char[] InputString)
{
if (en.enabled)
{
if (InputString.ToString() == "NULL")
{
return TransDown("");
}
if ((InputString != null) && (InputString.Length > 0))
{
MemoryStream memoryStream;
CryptoStream cryptoStream;
UTF8Encoding E = new UTF8Encoding();
byte[] iString;
RijndaelManaged rijndael = new RijndaelManaged();
rijndael.Key = E.GetBytes(PassStr);
rijndael.IV = PassSalt;
rijndael.Padding = PaddingMode.ISO10126;
rijndael.Mode = CipherMode.CBC;
memoryStream = new MemoryStream();
cryptoStream = new CryptoStream(memoryStream,
rijndael.CreateDecryptor(), CryptoStreamMode.Write);
iString = E.GetBytes(InputString);
cryptoStream.Write(iString, 0, iString.Length);

Same problem.
cryptoStream.Close();
return E.GetChars(memoryStream.ToArray());
}
else
return TransDown("NULL");
}
else
return TransDown("Not Authorized");
}

Arne
 
A

Arne Vajhøj

Arne said:
Tom said:
Ok, the overall problem is this. I have two functions in a C# .DLL as
follows:
public static char[] Encrypt(char[] InputString)
{
if (en.enabled)
{
if ((InputString != null) && (InputString.Length > 0))
{
MemoryStream memoryStream;
CryptoStream cryptoStream;
UTF8Encoding E = new UTF8Encoding();
RijndaelManaged rijndael = new RijndaelManaged();
rijndael.Key = E.GetBytes(PassStr);
rijndael.IV = PassSalt;
rijndael.Padding = PaddingMode.ISO10126;
rijndael.Mode = CipherMode.CBC;
memoryStream = new MemoryStream();
cryptoStream = new CryptoStream(memoryStream,
rijndael.CreateEncryptor(), CryptoStreamMode.Write);
cryptoStream.Write(E.GetBytes(InputString), 0,
InputString.Length);

This is not good. The number of bytes in UTF-8 encoding and
the number of chars does not need to be the same.

cryptoStream.Write(E.GetBytes(InputString), 0,
E.GetByteCount(InputString));
cryptoStream.FlushFinalBlock();
cryptoStream.Close();
return E.GetChars(memoryStream.ToArray());

This is not good.

You should not try and save random bytes (which encrypted data is)
in chars or strings.

Return a byte array of convert to Base64 or Hex.
}
else
return TransDown("NULL");
}
else
return TransDown("Not Authorized");
}

public static char[] Decrypt(char[] InputString)
{
if (en.enabled)
{
if (InputString.ToString() == "NULL")
{
return TransDown("");
}
if ((InputString != null) && (InputString.Length > 0))
{
MemoryStream memoryStream;
CryptoStream cryptoStream;
UTF8Encoding E = new UTF8Encoding();
byte[] iString;
RijndaelManaged rijndael = new RijndaelManaged();
rijndael.Key = E.GetBytes(PassStr);
rijndael.IV = PassSalt;
rijndael.Padding = PaddingMode.ISO10126;
rijndael.Mode = CipherMode.CBC;
memoryStream = new MemoryStream();
cryptoStream = new CryptoStream(memoryStream,
rijndael.CreateDecryptor(), CryptoStreamMode.Write);
iString = E.GetBytes(InputString);
cryptoStream.Write(iString, 0, iString.Length);

Same problem.
cryptoStream.Close();
return E.GetChars(memoryStream.ToArray());
}
else
return TransDown("NULL");
}
else
return TransDown("Not Authorized");
}

Try:

public static char[] Encrypt(char[] InputString)
{
if (en.enabled)
{
if ((InputString != null) && (InputString.Length > 0))
{
MemoryStream memoryStream;
CryptoStream cryptoStream;
UTF8Encoding E = new UTF8Encoding();
RijndaelManaged rijndael = new RijndaelManaged();
rijndael.Key = E.GetBytes(PassStr);
rijndael.IV = PassSalt;
rijndael.Padding = PaddingMode.ISO10126;
rijndael.Mode = CipherMode.CBC;
memoryStream = new MemoryStream();
cryptoStream = new CryptoStream(memoryStream,
rijndael.CreateEncryptor(), CryptoStreamMode.Write);
cryptoStream.Write(E.GetBytes(InputString), 0,
E.GetByteCount(InputString));
cryptoStream.FlushFinalBlock();
cryptoStream.Close();
return
Convert.ToBase64String(memoryStream.ToArray()).ToCharArray();
}
else
return TransDown("NULL");
}
else
return TransDown("Not Authorized");
}

public static char[] Decrypt(char[] InputString)
{
if (en.enabled)
{
if (InputString.ToString() == "NULL")
{
return TransDown("");
}
if ((InputString != null) && (InputString.Length > 0))
{
MemoryStream memoryStream;
CryptoStream cryptoStream;
UTF8Encoding E = new UTF8Encoding();
byte[] iString;
RijndaelManaged rijndael = new RijndaelManaged();
rijndael.Key = E.GetBytes(PassStr);
rijndael.IV = PassSalt;
rijndael.Padding = PaddingMode.ISO10126;
rijndael.Mode = CipherMode.CBC;
memoryStream = new MemoryStream();
cryptoStream = new CryptoStream(memoryStream,
rijndael.CreateDecryptor(), CryptoStreamMode.Write);
iString = Convert.FromBase64CharArray(InputString,
0, InputString.Length);
cryptoStream.Write(iString, 0, iString.Length);
cryptoStream.Close();
return E.GetChars(memoryStream.ToArray());
}
else
return TransDown("NULL");
}
else
return TransDown("Not Authorized");
}

Arne

PS: And I would prefer string over char[] anyway.
 
T

Tom Andrecht

Arne,

That worked perfectly and solved my problem completely. Thanks for your
advice.

Tom

Arne Vajhøj said:
Arne said:
Tom said:
Ok, the overall problem is this. I have two functions in a C# .DLL as
follows:
public static char[] Encrypt(char[] InputString)
{
if (en.enabled)
{
if ((InputString != null) && (InputString.Length > 0))
{
MemoryStream memoryStream;
CryptoStream cryptoStream;
UTF8Encoding E = new UTF8Encoding();
RijndaelManaged rijndael = new RijndaelManaged();
rijndael.Key = E.GetBytes(PassStr);
rijndael.IV = PassSalt;
rijndael.Padding = PaddingMode.ISO10126;
rijndael.Mode = CipherMode.CBC;
memoryStream = new MemoryStream();
cryptoStream = new CryptoStream(memoryStream,
rijndael.CreateEncryptor(), CryptoStreamMode.Write);
cryptoStream.Write(E.GetBytes(InputString), 0,
InputString.Length);

This is not good. The number of bytes in UTF-8 encoding and
the number of chars does not need to be the same.

cryptoStream.Write(E.GetBytes(InputString), 0,
E.GetByteCount(InputString));
cryptoStream.FlushFinalBlock();
cryptoStream.Close();
return E.GetChars(memoryStream.ToArray());

This is not good.

You should not try and save random bytes (which encrypted data is)
in chars or strings.

Return a byte array of convert to Base64 or Hex.
}
else
return TransDown("NULL");
}
else
return TransDown("Not Authorized");
}

public static char[] Decrypt(char[] InputString)
{
if (en.enabled)
{
if (InputString.ToString() == "NULL")
{
return TransDown("");
}
if ((InputString != null) && (InputString.Length > 0))
{
MemoryStream memoryStream;
CryptoStream cryptoStream;
UTF8Encoding E = new UTF8Encoding();
byte[] iString;
RijndaelManaged rijndael = new RijndaelManaged();
rijndael.Key = E.GetBytes(PassStr);
rijndael.IV = PassSalt;
rijndael.Padding = PaddingMode.ISO10126;
rijndael.Mode = CipherMode.CBC;
memoryStream = new MemoryStream();
cryptoStream = new CryptoStream(memoryStream,
rijndael.CreateDecryptor(), CryptoStreamMode.Write);
iString = E.GetBytes(InputString);
cryptoStream.Write(iString, 0, iString.Length);

Same problem.
cryptoStream.Close();
return E.GetChars(memoryStream.ToArray());
}
else
return TransDown("NULL");
}
else
return TransDown("Not Authorized");
}

Try:

public static char[] Encrypt(char[] InputString)
{
if (en.enabled)
{
if ((InputString != null) && (InputString.Length > 0))
{
MemoryStream memoryStream;
CryptoStream cryptoStream;
UTF8Encoding E = new UTF8Encoding();
RijndaelManaged rijndael = new RijndaelManaged();
rijndael.Key = E.GetBytes(PassStr);
rijndael.IV = PassSalt;
rijndael.Padding = PaddingMode.ISO10126;
rijndael.Mode = CipherMode.CBC;
memoryStream = new MemoryStream();
cryptoStream = new CryptoStream(memoryStream,
rijndael.CreateEncryptor(), CryptoStreamMode.Write);
cryptoStream.Write(E.GetBytes(InputString), 0,
E.GetByteCount(InputString));
cryptoStream.FlushFinalBlock();
cryptoStream.Close();
return
Convert.ToBase64String(memoryStream.ToArray()).ToCharArray();
}
else
return TransDown("NULL");
}
else
return TransDown("Not Authorized");
}

public static char[] Decrypt(char[] InputString)
{
if (en.enabled)
{
if (InputString.ToString() == "NULL")
{
return TransDown("");
}
if ((InputString != null) && (InputString.Length > 0))
{
MemoryStream memoryStream;
CryptoStream cryptoStream;
UTF8Encoding E = new UTF8Encoding();
byte[] iString;
RijndaelManaged rijndael = new RijndaelManaged();
rijndael.Key = E.GetBytes(PassStr);
rijndael.IV = PassSalt;
rijndael.Padding = PaddingMode.ISO10126;
rijndael.Mode = CipherMode.CBC;
memoryStream = new MemoryStream();
cryptoStream = new CryptoStream(memoryStream,
rijndael.CreateDecryptor(), CryptoStreamMode.Write);
iString = Convert.FromBase64CharArray(InputString, 0,
InputString.Length);
cryptoStream.Write(iString, 0, iString.Length);
cryptoStream.Close();
return E.GetChars(memoryStream.ToArray());
}
else
return TransDown("NULL");
}
else
return TransDown("Not Authorized");
}

Arne

PS: And I would prefer string over char[] anyway.
 
J

Joe Kuemerle

Ok, the overall problem is this. I have two functions in a C# .DLL as

....snip code...
This .DLL gets loaded into a MSSQL database and the functions get
loaded as Scalar-Valued functions. They are then called in SQL with
statements such as "SELECT dbo.DECRYPT(SSN) FROM CUSTOMER" to take the
encrypted form of the SSN and decrypt it for display to authorized
users. The problem is, when I encrypt with no padding, I get an
error, but when I decrypt with some form of padding (the same as used
to encrypt), I get an error that the padding is invalid.

Since you are loading this assembly into an MSSQL database I assume the database
is either SQL 2005 or 2008 both of which already have native support for
AES encryption (along with triple DES, RSA and numerous hashing algorithms.
My question is: why not use the existing functions rather than rolling your
own especially since the SQL encryption/decryption functionality takes care
of generating and storing a nonce value for the encryption IV every time
you write to the cell and you can delegate key management to SQL Server.

For more details you can see the slide deck and code from a recent presentation
I gave on encryption in SQL Server here: http://www.bennettadelson.com/downloads/SQLSIG/June2008.zip
.. The last slide in the deck also contains a number of resources that provide
more details on the encryption available.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top