c# tripleDESCrypto saved and retrieved from sql not working

562 views Asked by At

hey there, so in a msSQL database that i'm saving and retrieving from using stored procedures. i'm trying to encrypt some data in the c# windows form before being placed, and then of course decrypting it when i pull it back. all the encryption is being handled on the c# side. i'm using the sample code for encryption and decryption verbatim from microsoft's tripleDESCryptoService Class (the memory version, 2nd example). The values get encrypted and sent to the database, but when retrieving it i get a "bad data" error. a sample of the encryption call is...

TripleDESCryptoServiceProvider tDESalg = new TripleDESCryptoServiceProvider();
byte[] tempByte = new byte[100];
tempByte = encrypt(txt_Last_Name.Text, tDESalg.Key, tDESalg.IV);
txt_Last_Name.Text = System.Text.ASCIIEncoding.ASCII.GetString(tempByte);

the txt_Last_Name is then sent to the database, and i can see that there is something in the database. in the database, last name is of type varchar(20)

sample of the decryption call is...

TripleDESCryptoServiceProvider tDESalg = new TripleDESCryptoServiceProvider();
string lastName = dr.GetString(dr.GetOrdinal("Last Name"));
if (isEncrypted)
{
     byte[] toDecrypt = new ASCIIEncoding().GetBytes(lastName);
     lastName = decrypt(toDecrypt, tDESalg.Key, tDESalg.IV);                    
}
txt_Last_Name.Text = lastName;

it bombs in the decryption function at: "csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length);" and i don't understand why. i'm not sure if it's not getting stored in the database correctly, or my conversions aren't right.

if it means anything, the "Data" coming into the decrypt function is of size 16 and contains non-zero values, but the "byte[] fromEncrypt" is an array of size 16 containing all zeros.

thanks for any help!

3

There are 3 answers

15
Jon Skeet On BEST ANSWER

EDIT: Okay, we've got to the bottom of it... although the ASCII issue would have bitten too.

Every time you create a new TripleDESCryptoServiceProvider and ask it for a key/IV, it will generate a new one. You need to store that securely somewhere, as it's required to decrypt the data. Otherwise you don't have any "secret" so it's not really encryption...


This is a terrible idea:

txt_Last_Name.Text = System.Text.ASCIIEncoding.ASCII.GetString(tempByte);

You've got arbitrary binary data in tempByte. Don't assume it's valid ASCII text. That's almost certainly where you're losing data.

Use Convert.ToBase64String and Convert.FromBase64String to safely encode opaque binary data as text.

Additionally, this is a bad idea:

byte[] tempByte = new byte[100];
tempByte = encrypt(txt_Last_Name.Text, tDESalg.Key, tDESalg.IV);

What's the point of creating a byte array if you're then going to ignore it? Use

byte[] tempByte = encrypt(txt_Last_Name.Text, tDESalg.Key, tDESalg.IV);

instead. Oh, and try to follow .NET naming conventions :)

Having said all of this, if your encryption is always returning a byte array of 16 zeroes, that's a pretty sure sign that your encrypt method is broken. We can't really help there until you post the code for that method.

Finally, if your column is of type varchar(20) you should be aware that that may very well not hold all the data you need it to... particularly if you're going to include a salt. Base64 will increase the size of the data somewhat, and encryption may do so too. As mentioned in another answer, storing this as binary in the database would be more sensible in many ways.

(Note: even if you did want to use that code, I'd write it as txt_Last_Name.Text = Encoding.ASCII.GetString(tempByte);. Using directives are your friend, and ASCII is a property of Encoding, not ASCIIEncoding.)

2
pascal On

Just reading the doc... you should convert your byte[] to a String using Convert.ToBase64String().

1
Joe Enos On

Either Convert.ToBase64String(), as pascal recommended above, or store the data as binary in your database instead of text (the preferred solution, since it would use less space). In SQL Server, there is a VARBINARY(MAX) data type for this very purpose.