Beginning Crypto question

S

SenseiHitokiri

I have some code that converts a string into base64 for some
encryption.
It was written on the 1.1 framework but I am trying to get it to work
on 2.0. It throws exceptions on the cryptStream.FlushFinalBlock() and
cryptStream.Clear(). Can anyone tell me what is up with this?
Thanks ahead of time for any help you can offer.

public static string EncryptAndBase64( string val )
{
byte[] buf = UnicodeEncoding.Unicode.GetBytes(val);

MemoryStream memStream = new MemoryStream();
CryptoStream cryptStream = new CryptoStream(memStream, enc3des,
CryptoStreamMode.Write);

cryptStream.Write(buf, 0, buf.Length);
cryptStream.FlushFinalBlock();
cryptStream.Clear();
Array.Clear(buf, 0, buf.Length);

buf = memStream.GetBuffer();
val = Convert.ToBase64String(buf, 0, (int)memStream.Length);
Array.Clear(buf, 0, (int)memStream.Length);
return val;
}

public static object DecryptFromBase64( object val )
{
if( val.Equals( DBNull.Value ) )
return DBNull.Value;

return DecryptFromBase64( (string)val );
}

public static string DecryptFromBase64( string base64str )
{
byte[] buf = Convert.FromBase64String(base64str);
MemoryStream memStream = new MemoryStream();
CryptoStream cryptStream = new CryptoStream(memStream, dec3des,
CryptoStreamMode.Write );

cryptStream.Write(buf, 0, buf.Length);
cryptStream.FlushFinalBlock();
cryptStream.Clear();

Array.Clear(buf, 0, buf.Length);
buf = memStream.GetBuffer();

string ret = UnicodeEncoding.Unicode.GetString(buf, 0,
(int)memStream.Length);
Array.Clear(buf, 0, (int)memStream.Length);
memStream.Close();

return ret;
}
 
J

Jon Skeet [C# MVP]

SenseiHitokiri said:
I have some code that converts a string into base64 for some
encryption.
It was written on the 1.1 framework but I am trying to get it to work
on 2.0. It throws exceptions on the cryptStream.FlushFinalBlock() and
cryptStream.Clear(). Can anyone tell me what is up with this?
Thanks ahead of time for any help you can offer.

Could you post a short but complete program which demonstrates the
problem?

See http://www.pobox.com/~skeet/csharp/complete.html for details of
what I mean by that.
 
S

SenseiHitokiri

hmm I swore I posted the code up in here but I don't see it. Well here
it is again. C#

using System;
using System.Security.Cryptography;
using System.Text;

namespace DebugCrypto
{
class DebugCrypto
{
static void Main(string[] args)
{
DebugCrypto x = new DebugCrypto();
Console.Read();
}
void Program()
{
string base64str = "FmcT1N0kYX/IId4m6GuYpg=="; //string to
decrypt
ICryptoTransform dec3des = SetupCrypto();
byte[] buf = Convert.FromBase64String(base64str);

System.IO.MemoryStream memStream = new
System.IO.MemoryStream();
CryptoStream cryptStream = new CryptoStream(memStream,
dec3des, CryptoStreamMode.Write);

cryptStream.Write(buf, 0, buf.Length);
try
{
cryptStream.FlushFinalBlock(); //This is what
errors out
cryptStream.Clear(); // and this
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}

Array.Clear(buf, 0, buf.Length);
buf = memStream.GetBuffer();

Console.WriteLine(UnicodeEncoding.Unicode.GetString(buf,
0, (int)memStream.Length));

Array.Clear(buf, 0, (int)memStream.Length);
memStream.Close();
}

ICryptoTransform SetupCrypto()
{
TripleDESCryptoServiceProvider des3 = new
TripleDESCryptoServiceProvider();

byte[] salt =
System.Text.UTF8Encoding.UTF8.GetBytes("testKey"); //Encryption key
SHA1 hash = new SHA1Managed();
for (int i = 0; i < 200; ++i)
{
salt = hash.ComputeHash(salt, 0, salt.Length);
hash.Initialize();
}
PasswordDeriveBytes pdb = new
PasswordDeriveBytes("testKey", salt, "SHA512", 1000);
Array.Clear(salt, 0, salt.Length);
hash.Clear();

byte[] key3des = pdb.GetBytes(24);
byte[] iv3des = pdb.GetBytes(8);

return( des3.CreateDecryptor(key3des, iv3des) );
}
}
}
 
J

Jon Skeet [C# MVP]

SenseiHitokiri said:
hmm I swore I posted the code up in here but I don't see it. Well here
it is again. C#

<snip>

Well, the exception (after putting in a call to x.Program() - your
program as posted does nothing :) suggests that the data is invalid.
We'll need to see a short but complete program that produces that data
to start with, too.
 
S

SenseiHitokiri

<snip>

Well, the exception (after putting in a call to x.Program() - your
program as posted does nothing :) suggests that the data is invalid.
We'll need to see a short but complete program that produces that data
to start with, too.

Hmm... that may be a little harder. I'm taking over this code from
someone else and at the moment that is in a seperate app that I do not
have access to. I can try to rip out the encrypt code from this
program and throw it up here but that may take me a bit to discern
it. Damn I wish he gave me some documentation lol.
 
S

SenseiHitokiri

Ok give this a whirl. It generates the encrypted string and prints it
to the screen but then gives me a bad data error when trying to
decrypt.

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

namespace DebugCrypto
{
class DebugCrypto
{
ICryptoTransform enc3des, dec3des;
byte[] key3des = null;
byte[] iv3des = null;

static void Main(string[] args)
{
DebugCrypto x = new DebugCrypto();
string read = Console.ReadLine();
while ( read != "exit" )
{
string encrypted = x.EncryptAndBase64(read);

Console.WriteLine("Encrypting: ");
Console.WriteLine(encrypted);
Console.WriteLine("Decrypting: ");
Console.WriteLine(x.DecryptFromBase64(encrypted));
Console.WriteLine("\n");
}
}

public DebugCrypto()
{
string sKey = "testKey";

TripleDESCryptoServiceProvider des3 = new
TripleDESCryptoServiceProvider();

byte[] salt =
System.Text.UTF8Encoding.UTF8.GetBytes(sKey);
SHA1 hash = new SHA1Managed();
for (int i = 0; i < 200; ++i)
{
salt = hash.ComputeHash(salt, 0, salt.Length);
hash.Initialize();
}
PasswordDeriveBytes pdb = new PasswordDeriveBytes(sKey,
salt, "SHA512", 1000);
Array.Clear(salt, 0, salt.Length);
hash.Clear();

key3des = pdb.GetBytes(24);
iv3des = pdb.GetBytes(8);

enc3des = des3.CreateEncryptor(key3des, iv3des);
dec3des = des3.CreateDecryptor(key3des, iv3des);
des3.Clear();
}

public string EncryptAndBase64(string val)
{
byte[] buf = UnicodeEncoding.Unicode.GetBytes(val);

MemoryStream memStream = new MemoryStream();
CryptoStream cryptStream = new CryptoStream(memStream,
enc3des, CryptoStreamMode.Write);

cryptStream.Write(buf, 0, buf.Length);
int memLength = (int)memStream.Length;

cryptStream.FlushFinalBlock();
cryptStream.Clear();
Array.Clear(buf, 0, buf.Length);

buf = memStream.GetBuffer();
val = Convert.ToBase64String(buf, 0, memLength );
Array.Clear(buf, 0, memLength );
return val;
}

public string DecryptFromBase64(string base64str)
{
byte[] buf = Convert.FromBase64String(base64str);
MemoryStream memStream = new MemoryStream();
CryptoStream cryptStream = new CryptoStream(memStream,
dec3des, CryptoStreamMode.Write);

cryptStream.Write(buf, 0, buf.Length);
int memLength = (int)memStream.Length;

cryptStream.FlushFinalBlock();
cryptStream.Clear();
Array.Clear(buf, 0, buf.Length);
buf = memStream.GetBuffer();

string ret = UnicodeEncoding.Unicode.GetString(buf, 0,
memLength);
Array.Clear(buf, 0, memLength );
memStream.Close();
return ret;
}
}
}
 
J

Jon Skeet [C# MVP]

SenseiHitokiri said:
Ok give this a whirl. It generates the encrypted string and prints it
to the screen but then gives me a bad data error when trying to
decrypt.

The encryption is broken:
public string EncryptAndBase64(string val)
{
byte[] buf = UnicodeEncoding.Unicode.GetBytes(val);

MemoryStream memStream = new MemoryStream();
CryptoStream cryptStream = new CryptoStream(memStream,
enc3des, CryptoStreamMode.Write);

cryptStream.Write(buf, 0, buf.Length);
int memLength = (int)memStream.Length;

cryptStream.FlushFinalBlock();
cryptStream.Clear();
Array.Clear(buf, 0, buf.Length);

buf = memStream.GetBuffer();
val = Convert.ToBase64String(buf, 0, memLength );
Array.Clear(buf, 0, memLength );
return val;
}

Note how it works out the length of memStream *before* it flushes the
final block. Just move that line to *after* cryptStream.FlushFinalBlock
(and do the same in the decryption) and it works. However, it's not the
nicest way of doing it. It's simpler to use MemoryStream.ToArray to get
the buffer, rather than asking for the length at all. I would
personally write the decryption code as (the encryption side mirrors
it, of course):

public string DecryptFromBase64(string base64str)
{
byte[] buf = Convert.FromBase64String(base64str);
using (MemoryStream memStream = new MemoryStream())
{
using (CryptoStream cryptStream = new CryptoStream
(memStream, dec3des, CryptoStreamMode.Write))
{
cryptStream.Write(buf, 0, buf.Length);
// I don't think this is necessary in .NET 2.0
// but it is in 1.1 due to a bug in CryptoStream,
// IIRC
cryptStream.FlushFinalBlock();
}

byte[] decrypted = memStream.ToArray();

return Encoding.Unicode.GetString(decrypted);
}
}
 

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