CryptoStream returns bad data only on some machines

51 views
Skip to first unread message

dxterra

unread,
Feb 26, 2009, 11:09:31 AM2/26/09
to DotNetDevelopment, VB.NET, C# .NET, ADO.NET, ASP.NET, XML, XML Web Services,.NET Remoting
I have an application that uses CryptoStream to encrypt and decrypt
strings and stores and retrieves these values from a SQLServer
database.

When I run the application on my machine I can decrypt all the strings
in the database. When I run from a server I get "Bad Data" errors when
I try to close my CryptoStream.

Here is a sample application that I threw together:

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

namespace myTest
{
class Program
{
private static byte[] byteToken;

static void Main( string[] args )
{
Console.WriteLine( "Decoding sample string:" );

string testtoken = "mGAETZOUuW5tjFR4ihp80D23JQg4Uhtfdq
+UjZlBOE9XIRVvi+FtKg3R7TygdTEOjG+Qj6SLXl24fng+vuubLzK1vX1igECVQV
+9KKDjWpSG82S
+GTVOMsButxrae1bN83XdcFV0TN82iBW3Er4fKFfYSgAwyNEDCtrKO1hbbInLD0Z5ktzNB
+pfU4JVOVKAUbSPjIt4/8Na8HJimxleF6q/0SmRL0EOiyJRMT1xrKSHBK2VY/
rJnMicl053U+J1ZDGcHbUBPY1Z+
+dd0cfgKD79t6N0QJLzyPeuRVjmobT6lxznalAxgp5g0IXQugsMHuWeBR/zl/yey/
+h5dHPoK5XRGs56F+P";

Console.WriteLine( DecryptDES( testtoken ) );

Console.WriteLine( "Creating new string:" );

string tmpToken = EncryptDES( RandomString( 64, 64 ) );

Console.WriteLine( tmpToken );

Console.WriteLine( "Decoding new string:" );

Console.WriteLine( DecryptDES( tmpToken ) );
}


#region Encryption Methods
private static string RandomToken()
{
byte[] randombytes = new byte[128];

RNGCryptoServiceProvider Gen = new RNGCryptoServiceProvider
();
Gen.GetBytes( randombytes );
byteToken = randombytes;

return Encoding.Unicode.GetString( randombytes );
}

public static string RandomString( int minLength, int
maxLength )
{

string PASSWORD_CHARS_LCASE = "abcdefgijkmnopqrstwxyz";
string PASSWORD_CHARS_UCASE = "ABCDEFGHJKLMNPQRSTWXYZ";
string PASSWORD_CHARS_NUMERIC = "123456789";
string PASSWORD_CHARS_SPECIAL = "*$-+?_&=!{}";

// Create a local array containing supported password
characters
// grouped by types. You can remove character groups from
this
// array, but doing so will weaken the password strength.
char[][] charGroups = new char[][]
{
PASSWORD_CHARS_LCASE.ToCharArray(),
PASSWORD_CHARS_UCASE.ToCharArray(),
PASSWORD_CHARS_NUMERIC.ToCharArray(),
PASSWORD_CHARS_SPECIAL.ToCharArray()
};

// Use this array to track the number of unused characters
in each
// character group.
int[] charsLeftInGroup = new int[charGroups.Length];

// Initially, all characters in each group are not used.
for( int i = 0; i < charsLeftInGroup.Length; i++ )
charsLeftInGroup[i] = charGroups[i].Length;

// Use this array to track (iterate through) unused
character groups.
int[] leftGroupsOrder = new int[charGroups.Length];

// Initially, all character groups are not used.
for( int i = 0; i < leftGroupsOrder.Length; i++ )
leftGroupsOrder[i] = i;

// Because we cannot use the default randomizer, which is
based on the
// current time (it will produce the same "random" number
within a
// second), we will use a random number generator to seed
the
// randomizer.

// Use a 4-byte array to fill it with random bytes and
convert it then
// to an integer value.
byte[] randomBytes = new byte[4];

// Generate 4 random bytes.
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider
();
rng.GetBytes( randomBytes );

// Convert 4 bytes into a 32-bit integer value.
int seed = ( randomBytes[0] & 0x7f ) << 24 |
randomBytes[1] << 16 |
randomBytes[2] << 8 |
randomBytes[3];

// Now, this is real randomization.
Random random = new Random( seed );
// This array will hold password characters.
char[] password = null;
// Allocate appropriate memory for the password.
if( minLength < maxLength )
password = new char[random.Next( minLength, maxLength
+ 1 )];
else
password = new char[minLength];

// Index of the next character to be added to password.
int nextCharIdx;
// Index of the next character group to be processed.
int nextGroupIdx;
// Index which will be used to track not processed
character groups.
int nextLeftGroupsOrderIdx;
// Index of the last non-processed character in a group.
int lastCharIdx;
// Index of the last non-processed group.
int lastLeftGroupsOrderIdx = leftGroupsOrder.Length - 1;

// Generate password characters one at a time.
for( int i = 0; i < password.Length; i++ )
{
// If only one character group remained unprocessed,
process it;
// otherwise, pick a random character group from the
unprocessed
// group list. To allow a special character to appear
in the
// first position, increment the second parameter of
the Next
// function call by one, i.e. lastLeftGroupsOrderIdx +
1.
if( lastLeftGroupsOrderIdx == 0 )
nextLeftGroupsOrderIdx = 0;
else
nextLeftGroupsOrderIdx = random.Next( 0,
lastLeftGroupsOrderIdx );

// Get the actual index of the character group, from
which we will
// pick the next character.
nextGroupIdx = leftGroupsOrder
[nextLeftGroupsOrderIdx];
// Get the index of the last unprocessed characters in
this group.
lastCharIdx = charsLeftInGroup[nextGroupIdx] - 1;
// If only one unprocessed character is left, pick it;
otherwise,
// get a random character from the unused character
list.
if( lastCharIdx == 0 )
nextCharIdx = 0;
else
nextCharIdx = random.Next( 0, lastCharIdx + 1 );

// Add this character to the password.
password[i] = charGroups[nextGroupIdx][nextCharIdx];

// If we processed the last character in this group,
start over.
if( lastCharIdx == 0 )
charsLeftInGroup[nextGroupIdx] = charGroups
[nextGroupIdx].Length;
// There are more unprocessed characters left.
else
{
// Swap processed character with the last
unprocessed character
// so that we don't pick it until we process all
characters in
// this group.
if( lastCharIdx != nextCharIdx )
{
char temp = charGroups[nextGroupIdx]
[lastCharIdx];
charGroups[nextGroupIdx][lastCharIdx] =
charGroups[nextGroupIdx][nextCharIdx];
charGroups[nextGroupIdx][nextCharIdx] = temp;
}
// Decrement the number of unprocessed characters
in
// this group.
charsLeftInGroup[nextGroupIdx]--;
}

// If we processed the last group, start all over.
if( lastLeftGroupsOrderIdx == 0 )
lastLeftGroupsOrderIdx = leftGroupsOrder.Length -
1;
// There are more unprocessed groups left.
else
{
// Swap processed group with the last unprocessed
group
// so that we don't pick it until we process all
groups.
if( lastLeftGroupsOrderIdx !=
nextLeftGroupsOrderIdx )
{
int temp = leftGroupsOrder
[lastLeftGroupsOrderIdx];
leftGroupsOrder[lastLeftGroupsOrderIdx] =
leftGroupsOrder[nextLeftGroupsOrderIdx];
leftGroupsOrder[nextLeftGroupsOrderIdx] =
temp;
}
// Decrement the number of unprocessed groups.
lastLeftGroupsOrderIdx--;
}
}
// Convert password characters into a string and return
the result.
return new string( password );

}

public static byte[] EncryptDES( byte[] clearData, byte[] Key,
byte[] IV )
{

MemoryStream ms = new MemoryStream();

TripleDES tripDES = TripleDES.Create();

tripDES.Key = Key;
tripDES.IV = IV;

CryptoStream cs = new CryptoStream( ms,
tripDES.CreateEncryptor(), CryptoStreamMode.Write );

cs.Write( clearData, 0, clearData.Length );

cs.Close();
ms.Close();

byte[] encryptedData = ms.ToArray();

byte[] testbyte = new byte[byteToken.Length +
encryptedData.Length];
byteToken.CopyTo( testbyte, 0 );
encryptedData.CopyTo( testbyte, byteToken.Length );


return testbyte;
}

public static string EncryptDES( string clearText )
{

byte[] clearBytes = Encoding.Unicode.GetBytes
( clearText );

Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes
( RandomToken(),
new byte[] { 0xe3, 0xe4, 0xed, 0x43, 0x6e, 0x74, 0x72,
0x61, 0x2e, 0x6d, 0x65, 0x6c,
0x4c, 0x6f, 0x6e, 0x62, 0x41, 0x4e,
0x6b, 0x2e, 0x43,
0x6f, 0x6d, 0x5c, 0x52, 0x50, 0x4e,
0x73, 0x53, 0xe3, 0xe4, 0xed} );

byte[] encryptedData = EncryptDES( clearBytes, pdb.GetBytes
( 24 ), pdb.GetBytes( 8 ) );

return Convert.ToBase64String( encryptedData );
}
#endregion


#region Decryption Methods

private static byte[] DecryptDES( byte[] cipherData, byte[]
Key, byte[] IV )
{
MemoryStream ms = new MemoryStream();

TripleDES tripDES = TripleDES.Create();

tripDES.Key = Key;
tripDES.IV = IV;

CryptoStream cs = new CryptoStream( ms,
tripDES.CreateDecryptor(), CryptoStreamMode.Write );
cs.Write( cipherData, 0, cipherData.Length );
cs.FlushFinalBlock();
cs.Close();
ms.Flush();
ms.Close();

byte[] decryptedData = ms.ToArray();
return decryptedData;
}

public static string DecryptDES( string cipherText )
{
//string ErrorText = "Error: ";
byte[] cipherBytes;
try
{
try
{
cipherBytes = Convert.FromBase64String
( cipherText );
}
catch
{
throw new FormatException();
}
byte[] rmk = new byte[128];
byte[] cipher = new byte[cipherBytes.Length - 128];

int i = 0;
for( i = 0; i < 128; i++ )
{
rmk[i] = cipherBytes[i];
}

int j = 0;
for( i = 0; i < ( cipherBytes.Length - 128 ); i++ )
{
cipher[j] = cipherBytes[i + 128];
j++;
}

Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes
( System.Text.Encoding.Unicode.GetString( rmk ),
new byte[] { 0xe3, 0xe4, 0xed, 0x43, 0x6e, 0x74,
0x72, 0x61, 0x2e, 0x6d, 0x65, 0x6c,
0x4c, 0x6f, 0x6e, 0x62, 0x41, 0x4e,
0x6b, 0x2e, 0x43,
0x6f, 0x6d, 0x5c, 0x52, 0x50, 0x4e,
0x73, 0x53, 0xe3, 0xe4, 0xed} );

byte[] decryptedData = DecryptDES( cipher, pdb.GetBytes
( 24 ), pdb.GetBytes( 8 ) );

return Encoding.Unicode.GetString( decryptedData );
}
catch( Exception e )
{
throw new Exception( e.ToString() );
}
}
#endregion

}
}



Any help would be appreciated. Thanks.

dxterra

unread,
Feb 26, 2009, 11:11:27 AM2/26/09
to DotNetDevelopment, VB.NET, C# .NET, ADO.NET, ASP.NET, XML, XML Web Services,.NET Remoting
Reply all
Reply to author
Forward
0 new messages