Click here to Skip to main content
15,884,975 members
Articles / Programming Languages / Visual Basic

.NET Encryption Simplified

Rate me:
Please Sign up or sign in to vote.
4.90/5 (209 votes)
28 Jan 2007CPOL10 min read 1.8M   23.8K   586   196
A simple, string-oriented class for symmetric encryption, asymmetric encryption, and hashing.

Image 1

Introduction

Microsoft's .NET framework has robust support for encryption in the System.Security.Cryptography namespace. Everything you need to perform encryption is available in that class, but it's difficult to understand unless you have a firm grasp of cryptographic theory. Over the last four months, I've struggled with the concepts and theory behind encrypting and decrypting data. I've wrapped all my derived knowledge into a class I call Encryption. This class is heavily documented, string oriented, and most of all, simple! It's ideal for learning more about encryption.

Background

There are three essential cryptographic concepts represented in the Encryption namespace. It's important that every developer understands these concepts before proceeding any further:

  1. Hashing

    Hashes aren't encryption, per se, but they are fundamental to all other encryption operations. A hash is a data fingerprint - a tiny set of bytes that represents the uniqueness of a much larger block of bytes. Like fingerprints, no two should ever be alike, and a matching fingerprint is conclusive proof of identity. A full discussion of hashes is outside the scope of this article, but I highly recommend Steve Friedl's Illustrated Guide to Cryptographic Hashes for more background.

  2. Symmetric Encryption

    In symmetric encryption, a single key is used for encrypting and decrypting the data. This type of encryption is quite fast, but has a severe problem: in order to share a secret with someone, they have to know your key. This implies a very high level of trust between people sharing secrets; if an unscrupulous person has your key-- or if your key is intercepted by a spy-- they can decrypt all the messages you send using that key!

  3. Asymmetric Encryption

    Asymmetric encryption solves the trust problem inherent in symmetric encryption by using two different keys: a public key for encrypting messages, and a private key for decrypting messages. This makes it possible to communicate in secrecy with people you don't fully trust. If an unscrupulous person has your public key, who cares? The public key is only good for encryption; it's useless for decryption. They can't decrypt any of your messages! However, asymmetric encryption is very slow. It's not recommended for use on more than roughly 1 kilobyte of data.

These three concepts are heavily intertwined and always seen together in modern cryptography. They have different strengths and weaknesses; combining them offers a much higher level of security than can be achieved using a single method alone. For example, when digitally transmitting a check to your bank, all three of these methods are used:

Image 2

Image reprinted from Entrust's Introduction to Cryptography and Digital Signatures PDF.

  • A hash of the check is calculated.
  • The hash is encrypted with our public key using asymmetric encryption.
  • The encrypted hash is appended to the document.
  • The document is encrypted using a unique one-time symmetric encryption key.
  • The one-time symmetric encryption key is encrypted with the recipient's public key using asymmetric encryption.
  • The encrypted key and encrypted document are transmitted to the recipient.

In order to open the check, these steps are simply performed in the reverse order by the recipient. Note that if any of these steps were missing, the transaction would have significant weaknesses that could be exploited!

Encryption.Hash

Let's start with the simplest operation-- Hashing the string "Hash Browns":

VB.NET
Dim h As New Encryption.Hash(Encryption.Hash.Provider.CRC32)
Dim d As New Encryption.Data("Hash Browns")
h.Calculate(d)
Console.WriteLine(".ToHex = '" & h.Value.ToHex & "'")
Console.WriteLine(".ToBase64 = '" & h.Value.ToBase64 & "'")
Console.WriteLine(".ToString = '" & h.Value.ToString & "'")

The unique data fingerprint of the string "Hash Browns" using the CRC32 algorithm is 32 bits or 4 bytes in length. We have a custom data type, Encryption.Data, to aid us in converting those 4 bytes to and from familiar string representations:

VB.NET
.ToHex = 'FDBFBC6D'
.ToBase64 = '/b+8bQ=='
.ToString = 'y¿¼m'

It doesn't make much sense to display an array of raw bytes using the .ToString method; that's shown only for illustrative purposes. You'll want raw byte values displayed either as Hexadecimal or Base64 encoded. If necessary, you can get to the raw byte representation via the Encryption.Data.Bytes array.

The CRC32 hash is not a good choice for security work; it's optimized for speed and detection of machine transmission errors. It would be relatively easy for a knowledgeable human hacker to generate a string that produces the same CRC32 hash. Let's take a look at a slower, but more secure hash: SHA1.

VB.NET
Dim h As New Encryption.Hash(Encryption.Hash.Provider.SHA1)
Dim d As New Encryption.Data("Hash Browns")
Dim salt As New Encryption.Data("NaCl")
h.Calculate(d, salt)
Console.WriteLine(h.Value.ToHex)
Console.WriteLine(h.Value.ToBase64)

SHA1 produces a much longer and more tamper-resistant 160-bit hash code.

VB.NET
.ToHex = '95CF26B3BB0.F377347B6D414951456A16DD0CF5F'
.ToBase64 = 'lc8ms7sPN3NHttQUlRRWoW3Qz18='

Notice the salt I added? Hashes are commonly used to avoid plain-text storage of passwords in a database. You calculate the hash of the password and store the hash instead of the actual password. When the user types in their password, hash it, then compare it against the stored hash in the database. It's clever, but there is a vulnerability: you can still mount a dictionary attack by hashing the English dictionary and matching it against the hashes stored in the database. We can prevent this by adding a salt-- a unique string-- to every password before hashing it. You'd typically salt with some arbitrary value from the same record, such as the record ID, user's birthday, or a GUID. It doesn't really matter what your salt is, as long as it makes the values unique. By adding the salt as shown above, we are effectively hashing the string "NaClHash Browns" instead of "Hash Browns". Good luck finding "NaClHash" in a dictionary!

Also note that string representations aren't particularly efficient; it takes 40 characters to represent the 160 bit (20 byte) hash in string using Hexadecimal, and 28 characters to represent that same hash using Base64 encoding. If you don't need to display your data in semi-human readable format, stick to binary formats. But the textual representations sure are convenient for use in XML or .config files!

We're not limited to Encryption.Data byte arrays of fixed length. We can also calculate the hash of an IO.Stream of any arbitrary size:

VB.NET
Dim sr As New IO.StreamReader("c:\test.txt")
Dim h As New Encryption.Hash(Encryption.Hash.Provider.MD5)
Console.WriteLine(".ToHex = '" & h.Calculate(sr.BaseStream).ToHex & "'")
sr.Close()

So the file test.txt has an MD5 hash of:

VB.NET
.ToHex = '92C7C0F251D98DEA2ACC49B21CF08070'

Let's see what happens if we add a single space character to test.txt, and hash it again:

VB.NET
.ToHex = 'FADECF02C2ABDC7B65EBF2382E8AC756'

One of the defining properties of a hash is that small changes in the source bytes produce big differences in the resulting hash bytes.

All hashes have the same purpose: to digitally fingerprint code. However, there are different speed and security tradeoffs for each Hash.Provider:

Provider Length (bits) Security Speed
Hash.Provider.CRC32 32 low fast
Hash.Provider.SHA1 160 moderate medium
Hash.Provider.SHA256 256 high slow
Hash.Provider.SHA384 384 high slow
Hash.Provider.SHA512 512 extreme slow
Hash.Provider.MD5 128 moderate medium

Encryption.Symmetric

Symmetric encryption is the most familiar kind of encryption; you have a single secret key which is used to both encrypt and decrypt:

VB.NET
Dim sym As New Encryption.Symmetric(Encryption.Symmetric.Provider.Rijndael)
Dim key As New Encryption.Data("My Password")
Dim encryptedData As Encryption.Data
encryptedData = sym.Encrypt(New Encryption.Data("Secret Sauce"), key)
Dim base64EncryptedString as String = encryptedData.ToBase64

We now have some Rijndael encrypted bytes, expressed as a Base64 string. Let's decrypt them:

VB.NET
Dim sym As New Encryption.Symmetric(Encryption.Symmetric.Provider.Rijndael)
Dim key As New Encryption.Data("My Password")
Dim encryptedData As New Encryption.Data
encryptedData.Base64 = base64EncryptedString
Dim decryptedData As Encryption.Data
decryptedData = sym.Decrypt(encryptedData, key)
Console.WriteLine(decryptedData.ToString)

Like the Encryption.Hash class, this also works for any arbitrarily-sized IO.Stream as well as the fixed size Encryption.Data:

VB
Dim sym As New Encryption.Symmetric(Encryption.Symmetric.Provider.TripleDES)
Dim key As New Encryption.Data("My Password")
Dim fs As New IO.FileStream("c:\test.txt", IO.FileMode.Open, 
                            IO.FileAccess.Read)
Dim br As New IO.BinaryReader(fs)
Dim encryptedData As Encryption.Data
encryptedData = sym.Encrypt(br.BaseStream, key)
br.Close()
Dim sym2 As New Encryption.Symmetric(Encryption.Symmetric.Provider.TripleDES)
Dim decryptedData As Encryption.Data
decryptedData = sym2.Decrypt(encryptedData, key)

There are a few things to remember when using the Encryption.Symmetric class:

  • All symmetric encryption is currently performed in memory. Be careful when encrypting extremely large files!
  • .NET always chooses the largest available key size by default. If you want to manually specify a smaller key size, use the .KeySizeBytes or .KeySizeBits properties.
  • The key is optional in the .Encrypt method. If you don't provide a key, a key of appropriate length will be auto generated for you and it can be retrieved via the .Key property. It won't be fun to pronounce, because it'll be a randomly generated array of bytes, but it'll sure be hard to guess!
  • The .InitializationVector property is completely optional. The symmetric algorithms are block-oriented and seed the next block with the results from the previous block. This means the very first block has no seed, so that's where the IV comes in. It's annoying to have to remember both a password and an initialization vector to decrypt your data, and I don't think this is a serious weakness, so I recommend accepting the default initialization vector.

.NET provides four different Symmetric.Provider algorithms; I would avoid the ones with shorter keys and known weaknesses:

Provider Length (bits) Known Vulnerabilities
Symmetric.Provider.DES 64 yes
Symmetric.Provider.RC2 40-128 yes
Symmetric.Provider.Rijndael 128, 192, 256 no
Symmetric.Provider.TripleDES 128, 192 no

Encryption.Asymmetric

Asymmetric encryption requires the use of two keys: one public, one private, together known as a "keyset". Let's generate a new keyset and encrypt some data:

VB.NET
Dim asym As New Encryption.Asymmetric
Dim pubkey As New Encryption.Asymmetric.PublicKey
Dim privkey As New Encryption.Asymmetric.PrivateKey
asym.GenerateNewKeyset(pubkey, privkey)
Dim secret As String = "ancient chinese"
Dim encryptedData As Encryption.Data
encryptedData = asym.Encrypt(New Encryption.Data(secret), pubkey)
Dim decryptedData As Encryption.Data
Dim asym2 As New Encryption.Asymmetric
decryptedData = asym2.Decrypt(encryptedData, privkey)

Note that we used the public key to encrypt, and the private key to decrypt.

Although you can certainly generate as many new public/private keysets as you want, you'll typically load an existing keyset. To facilitate loading and saving of keys, the Encryption.Asymmetric.PublicKey and Encryption.Asymmetric.PrivateKey classes support XML serialization via the .ToXml and .FromXml methods. They also support exporting to config file format via the .ToConfigSection method, which returns a string suitable for cutting and pasting into the <appSettings> section of your *.config file:

XML
<appSettings>
  <add key="PublicKey.Modulus" 
    value="3uWxbWSnlL2ntr/gcJ0NQeiWRfzj/72zIDuBW/TmegeodMdPUvI5vXur0fKp
    6RbSU112oPf9o7hoAF8bdR9YOiJg6axZYKh+BxEH6pUPLbrtn1dPCUgTxlMeo0IhKvi
    h1Q90Bz+ZxCp/V8Hcf86p+4LPeb1o9EOa01zd0yUwvkE=" />
  <add key="PublicKey.Exponent" 
    value="AQAB" />
  <add key="PrivateKey.P" 
    value="76iHZusdN1TYrTqf1gExNMMWbiHS7zSB/bi/xeUR0F3fjvnvsayn6s5ShM0jx
    YHVVkRyVoH16PwLW6Tt2gpdYw==" />
  <add key="PrivateKey.Q" 
    value="7hiVRmx0z1KERw+Zy86MmlvuODUsn2kuM06kLsSHbznSkYl5lekH9RFxFemNk
    GGMBg8OT5+EVtWAOdto8KTJCw==" />
  <add key="PrivateKey.DP" 
    value="ksvo/EqBn9XRzvH826npSQdCYv1G5gyEnzQeC4qPidEmUb6Yan12cWYlt4CsK
    5umYGwWmRSL20Ufc+gnZQo6Pw==" />
  <add key="PrivateKey.DQ" 
    value="QliLUCJsslDWF08blhUqTOENEpCOrKUMgLOLQJT3AGFmcbOTM9jJpNqFXovEL
    NVhxVZwsHNM1z2LC5Q+O8BPXQ==" />
  <add key="PrivateKey.InverseQ" 
    value="pjEtLwYB4yeDpdORNFxhFVXWZCqoky86bmAnrrG4+FvwkH/2dNe65Wmp62JvZ
    7dwgPBIA+uA/LF+C1LXcXe9Aw==" />
  <add key="PrivateKey.D" 
    value="EmuZBhlTYA9sVMX2nlfcSJ4YDSChFvluXDOOtTK/+UW4vi3aeFhcPTSDNo5/T
    Cv+pbULoLHd3DHZJm61rjAw8jV5n09Trufg/Z3ybzUrAOzT3iTR2rvg7mNS2IBmaTyJg     
    emNKQDeFW81UOELVszUXNjhVex+k67Ma4omR6iTHSE=" />
</appSettings>

The private key is a superset of the public key; it can be used for both encryption and decryption, whereas the public key can only be used for encryption. Once a key is placed in the <appSettings> section of your .config file, it will be used automatically; you no longer have to specify a private key in the .Decrypt method:

VB.NET
Dim encryptedData As Encryption.Data
Dim decryptedData As Encryption.Data
Dim asym As New Encryption.Asymmetric
Dim asym2 As New Encryption.Asymmetric
Dim secret As String = "Michael Bolton"
encryptedData = asym.Encrypt(New Encryption.Data(secret))
decryptedData = asym2.Decrypt(encryptedData)
Console.WriteLine(decryptedData.ToString)

Note that we didn't specify any keys here; everything was automatically absorbed from the <appSettings> section of the config file.

There are a few caveats when using Encryption.Asymmetric:

  • Microsoft's implementation of asymmetric encryption offers no choice of providers: you'll get RSA and you'll like it! You do get a choice of key sizes, though-- anywhere from 384 bits to 16,384 bits in steps of 8 bits. If you don't specify a size in the constructor, you'll get 1,024 bits by default. That should be more than enough for most uses.
  • Asymmetric encryption is designed for small inputs. This is partly because asymmetric encryption is brutally slow, but it's also by design: depending on the key size you choose, you'll get an exception if you try to encrypt something too big! There are workarounds, but I don't recommend them. Follow best practices as defined at the top of this article; use asymmetric encryption to protect short stuff, like symmetric passwords or hashes.

The Annoying File Dependency in Encryption.Asymmetric

Unfortunately, Microsoft chose to provide some System.Security.Cryptography functionality through the existing COM-based CryptoAPI. Typically this is no big deal; lots of things in .NET are delivered via COM interfaces. However, there is one destructive side effect in this case: asymmetric encryption, which in my opinion should be an entirely in-memory operation, has a filesystem "key container" dependency:

Image 3

Even worse, this weird little "key container" file usually goes to the current user's folder! I have specified a machine folder as documented in this Microsoft knowledge base article. Every time we perform an asymmetric encryption operation, a file is created and then destroyed in the C:\Documents and Settings\All Users\Application Data\Microsoft\Crypto\RSA\MachineKeys folder. It is simply unavoidable, which you can see for yourself by opening this folder and watching what happens to it when you make asymmetric encryption calls. Make sure whatever account .NET is running as (ASP.NET, etc.) has permission to this folder!

Conclusion

Encryption is a deep, complicated subject. I hope this article and the accompanying classes made it at least a little more approachable.

Please don't hesitate to provide feedback, good or bad! If you enjoyed this article, you may also like my other articles as well.

History

  • Tuesday, April 19th, 2005
    • Published.
  • Sunday, May 1st, 2005
    • Minor bugfixes to article code.
    • Corrected issue with byte array nulls and Encoding.GetString in C#.
  • Monday, January 29th, 2007
    • Straight port to .NET 2.0 and Visual Studio 2005.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United States United States
My name is Jeff Atwood. I live in Berkeley, CA with my wife, two cats, and far more computers than I care to mention. My first computer was the Texas Instruments TI-99/4a. I've been a Microsoft Windows developer since 1992; primarily in VB. I am particularly interested in best practices and human factors in software development, as represented in my recommended developer reading list. I also have a coding and human factors related blog at www.codinghorror.com.

Comments and Discussions

 
GeneralDefault KeyContainerName Pin
William.Wong6-Aug-07 22:38
William.Wong6-Aug-07 22:38 
QuestionPadding of decrypted data? Pin
slolife11-Jul-07 22:17
slolife11-Jul-07 22:17 
QuestionVisual Web Developer 2005.? Pin
3d-codeaholic14-Jun-07 6:30
3d-codeaholic14-Jun-07 6:30 
AnswerRe: Visual Web Developer 2005.? Pin
3d-codeaholic14-Jun-07 10:00
3d-codeaholic14-Jun-07 10:00 
GeneralThis is a fantastic library Pin
snkscore5-May-07 11:19
snkscore5-May-07 11:19 
QuestionHave it in C#? Pin
Mike Prather25-Apr-07 5:02
Mike Prather25-Apr-07 5:02 
QuestionRe: Have it in C#? Pin
Braim8023-Jul-07 20:45
Braim8023-Jul-07 20:45 
AnswerRe: Have it in C#? Pin
kalyankrishna12-Aug-07 0:07
kalyankrishna12-Aug-07 0:07 
I hope I got this right

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

// A simple, string-oriented wrapper class for encryption functions, including
// Hashing, Symmetric Encryption, and Asymmetric Encryption.
//
// Jeff Atwood
// http://www.codinghorror.com/
namespace Encryption
{

#region " Hash"

///
/// Hash functions are fundamental to modern cryptography. These functions map binary
/// strings of an arbitrary length to small binary strings of a fixed length, known as
/// hash values. A cryptographic hash function has the property that it is computationally
/// infeasible to find two distinct inputs that hash to the same value. Hash functions
/// are commonly used with digital signatures and for data integrity.
///

public class Hash
{

///
/// Type of hash; some are security oriented, others are fast and simple
///

public enum Provider
{
///
/// Cyclic Redundancy Check provider, 32-bit
///

CRC32,
///
/// Secure Hashing Algorithm provider, SHA-1 variant, 160-bit
///

SHA1,
///
/// Secure Hashing Algorithm provider, SHA-2 variant, 256-bit
///

SHA256,
///
/// Secure Hashing Algorithm provider, SHA-2 variant, 384-bit
///

SHA384,
///
/// Secure Hashing Algorithm provider, SHA-2 variant, 512-bit
///

SHA512,
///
/// Message Digest algorithm 5, 128-bit
///

MD5
}

private HashAlgorithm _Hash;
private Data _HashValue = new Data();

private Hash()
{
}

///
/// Instantiate a new hash of the specified type
///

public Hash(Provider p)
{
switch (p)
{
case Provider.CRC32:
_Hash = new CRC32();
break;
case Provider.MD5:
_Hash = new MD5CryptoServiceProvider();
break;
case Provider.SHA1:
_Hash = new SHA1Managed();
break;
case Provider.SHA256:
_Hash = new SHA256Managed();
break;
case Provider.SHA384:
_Hash = new SHA384Managed();
break;
case Provider.SHA512:
_Hash = new SHA512Managed();
break;
}
}

///
/// Returns the previously calculated hash
///

public Data Value
{
get { return _HashValue; }
}

///
/// Calculates hash on a stream of arbitrary length
///

public Data Calculate(ref System.IO.Stream s)
{
_HashValue.Bytes = _Hash.ComputeHash(s);
return _HashValue;
}

///
/// Calculates hash for fixed length <see cref="Data">
///

public Data Calculate(Data d)
{
return CalculatePrivate(d.Bytes);
}

///
/// Calculates hash for a string with a prefixed salt value.
/// A "salt" is random data prefixed to every hashed value to prevent
/// common dictionary attacks.
///

public Data Calculate(Data d, Data salt)
{
byte[] nb = new byte[d.Bytes.Length + salt.Bytes.Length];
salt.Bytes.CopyTo(nb, 0);
d.Bytes.CopyTo(nb, salt.Bytes.Length);
return CalculatePrivate(nb);
}

///
/// Calculates hash for an array of bytes
///

private Data CalculatePrivate(byte[] b)
{
_HashValue.Bytes = _Hash.ComputeHash(b);
return _HashValue;
}

#region " CRC32 HashAlgorithm"

private class CRC32 : HashAlgorithm
{

private int result = -1;

protected override void HashCore(byte[] array, int ibStart, int cbSize)
{
int lookup;
for (int i = ibStart; i <= cbSize - 1; i++)
{
lookup = (result & 255) ^ array[i];
result = ((result & -256) / 256) & 16777215;
result = result ^ crcLookup[lookup];
}
}

protected override byte[] HashFinal()
{
byte[] b = BitConverter.GetBytes(~this.result);
Array.Reverse(b);
return b;
}

public override void Initialize()
{
result = -1;
}

private int[] crcLookup = {0, 1996959894, -301047508, -1727442502, 124634137, 1886057615, -379345611, -1637575261, 249268274, 2044508324,
-522852066, -1747789432, 162941995, 2125561021, -407360249, -1866523247, 498536548, 1789927666, -205950648, -2067906082,
450548861, 1843258603, -187386543, -2083289657, 325883990, 1684777152, -43845254, -1973040660, 335633487, 1661365465,
-99664541, -1928851979, 997073096, 1281953886, -715111964, -1570279054, 1006888145, 1258607687, -770865667, -1526024853,
901097722, 1119000684, -608450090, -1396901568, 853044451, 1172266101, -589951537, -1412350631, 651767980, 1373503546,
-925412992, -1076862698, 565507253, 1454621731, -809855591, -1195530993, 671266974, 1594198024, -972236366, -1324619484,
795835527, 1483230225, -1050600021, -1234817731, 1994146192, 31158534, -1731059524, -271249366, 1907459465, 112637215,
-1614814043, -390540237, 2013776290, 251722036, -1777751922, -519137256, 2137656763, 141376813, -1855689577, -429695999,
1802195444, 476864866, -2056965928, -228458418, 1812370925, 453092731, -2113342271, -183516073, 1706088902, 314042704,
-1950435094, -54949764, 1658658271, 366619977, -1932296973, -69972891, 1303535960, 984961486, -1547960204, -725929758,
1256170817, 1037604311, -1529756563, -740887301, 1131014506, 879679996, -1385723834, -631195440, 1141124467, 855842277,
-1442165665, -586318647, 1342533948, 654459306, -1106571248, -921952122, 1466479909, 544179635, -1184443383, -832445281,
1591671054, 702138776, -1328506846, -942167884, 1504918807, 783551873, -1212326853, -1061524307, -306674912, -1698712650,
62317068, 1957810842, -355121351, -1647151185, 81470997, 1943803523, -480048366, -1805370492, 225274430, 2053790376,
-468791541, -1828061283, 167816743, 2097651377, -267414716, -2029476910, 503444072, 1762050814, -144550051, -2140837941,
426522225, 1852507879, -19653770, -1982649376, 282753626, 1742555852, -105259153, -1900089351, 397917763, 1622183637,
-690576408, -1580100738, 953729732, 1340076626, -776247311, -1497606297, 1068828381, 1219638859, -670225446, -1358292148,
906185462, 1090812512, -547295293, -1469587627, 829329135, 1181335161, -882789492, -1134132454, 628085408, 1382605366,
-871598187, -1156888829, 570562233, 1426400815, -977650754, -1296233688, 733239954, 1555261956, -1026031705, -1244606671,
752459403, 1541320221, -1687895376, -328994266, 1969922972, 40735498, -1677130071, -351390145, 1913087877, 83908371,
-1782625662, -491226604, 2075208622, 213261112, -1831694693, -438977011, 2094854071, 198958881, -2032938284, -237706686,
1759359992, 534414190, -2118248755, -155638181, 1873836001, 414664567, -2012718362, -15766928, 1711684554, 285281116,
-1889165569, -127750551, 1634467795, 376229701, -1609899400, -686959890, 1308918612, 956543938, -1486412191, -799009033,
1231636301, 1047427035, -1362007478, -640263460, 1088359270, 936918000, -1447252397, -558129467, 1202900863, 817233897,
-1111625188, -893730166, 1404277552, 615818150, -1160759803, -841546093, 1423857449, 601450431, -1285129682, -1000256840,
1567103746, 711928724, -1274298825, -1022587231, 1510334235, 755167117};

public override byte[] Hash
{
get
{
byte[] b = BitConverter.GetBytes(~this.result);
Array.Reverse(b);
return b;
}
}
}

#endregion

}
#endregion

#region " Symmetric"

///
/// Symmetric encryption uses a single key to encrypt and decrypt.
/// Both parties (encryptor and decryptor) must share the same secret key.
///

public class Symmetric
{

private const string _DefaultIntializationVector = "%1Az=-@qT";
private const int _BufferSize = 2048;

public enum Provider
{
///
/// The Data Encryption Standard provider supports a 64 bit key only
///

DES,
///
/// The Rivest Cipher 2 provider supports keys ranging from 40 to 128 bits, default is 128 bits
///

RC2,
///
/// The Rijndael (also known as AES) provider supports keys of 128, 192, or 256 bits with a default of 256 bits
///

Rijndael,
///
/// The TripleDES provider (also known as 3DES) supports keys of 128 or 192 bits with a default of 192 bits
///

TripleDES
}

private Data _data;
private Data _key;
private Data _iv;
private SymmetricAlgorithm _crypto;
private byte[] _EncryptedBytes;
private bool _UseDefaultInitializationVector;

private Symmetric()
{
}

///
/// Instantiates a new symmetric encryption object using the specified provider.
///

public Symmetric(Provider provider, bool useDefaultInitializationVector)
{
switch (provider)
{
case Provider.DES:
_crypto = new DESCryptoServiceProvider();
break;
case Provider.RC2:
_crypto = new RC2CryptoServiceProvider();
break;
case Provider.Rijndael:
_crypto = new RijndaelManaged();
break;
case Provider.TripleDES:
_crypto = new TripleDESCryptoServiceProvider();
break;
}

//-- make sure key and IV are always set, no matter what
this.Key = RandomKey();
if (useDefaultInitializationVector)
{
this.IntializationVector = new Data(_DefaultIntializationVector);
}
else
{
this.IntializationVector = RandomInitializationVector();
}
}

///
/// Key size in bytes. We use the default key size for any given provider; if you
/// want to force a specific key size, set this property
///

public int KeySizeBytes
{
get { return _crypto.KeySize / 8; }
set
{
_crypto.KeySize = value * 8;
_key.MaxBytes = value;
}
}

///
/// Key size in bits. We use the default key size for any given provider; if you
/// want to force a specific key size, set this property
///

public int KeySizeBits
{
get { return _crypto.KeySize; }
set
{
_crypto.KeySize = value;
_key.MaxBits = value;
}
}

///
/// The key used to encrypt/decrypt data
///

public Data Key
{
get { return _key; }
set
{
_key = value;
_key.MaxBytes = _crypto.LegalKeySizes[0].MaxSize / 8;
_key.MinBytes = _crypto.LegalKeySizes[0].MinSize / 8;
_key.StepBytes = _crypto.LegalKeySizes[0].SkipSize / 8;
}
}

///
/// Using the default Cipher Block Chaining (CBC) mode, all data blocks are processed using
/// the value derived from the previous block; the first data block has no previous data block
/// to use, so it needs an InitializationVector to feed the first block
///

public Data IntializationVector
{
get { return _iv; }
set
{
_iv = value;
_iv.MaxBytes = _crypto.BlockSize / 8;
_iv.MinBytes = _crypto.BlockSize / 8;
}
}

///
/// generates a random Initialization Vector, if one was not provided
///

public Data RandomInitializationVector()
{
_crypto.GenerateIV();
Data d = new Data(_crypto.IV);
return d;
}

///
/// generates a random Key, if one was not provided
///

public Data RandomKey()
{
_crypto.GenerateKey();
Data d = new Data(_crypto.Key);
return d;
}

///
/// Ensures that _crypto object has valid Key and IV
/// prior to any attempt to encrypt/decrypt anything
///

private void ValidateKeyAndIv(bool isEncrypting)
{
if (_key.IsEmpty)
{
if (isEncrypting)
{
_key = RandomKey();
}
else
{
throw new CryptographicException("No key was provided for the decryption operation!");
}
}

if (_iv.IsEmpty)
{
if (isEncrypting)
{
_iv = RandomInitializationVector();
}
else
{
throw new CryptographicException("No initialization vector was provided for the decryption operation!");
}
}
_crypto.Key = _key.Bytes;
_crypto.IV = _iv.Bytes;
}

///
/// Encrypts the specified Data using provided key
///

public Data Encrypt(Data d, Data key)
{
this.Key = key;
return Encrypt(d);
}

///
/// Encrypts the specified Data using preset key and preset initialization vector
///

public Data Encrypt(Data d)
{
System.IO.MemoryStream ms = new System.IO.MemoryStream();

ValidateKeyAndIv(true);

CryptoStream cs = new CryptoStream(ms, _crypto.CreateEncryptor(), CryptoStreamMode.Write);
cs.Write(d.Bytes, 0, d.Bytes.Length);
cs.Close();
ms.Close();

return new Data(ms.ToArray());
}

///
/// Encrypts the stream to memory using provided key and provided initialization vector
///

public Data Encrypt(Stream s, Data key, Data iv)
{
this.IntializationVector = iv;
this.Key = key;
return Encrypt(s);
}

///
/// Encrypts the stream to memory using specified key
///

public Data Encrypt(Stream s, Data key)
{
this.Key = key;
return Encrypt(s);
}

///
/// Encrypts the specified stream to memory using preset key and preset initialization vector
///

public Data Encrypt(Stream s)
{
System.IO.MemoryStream ms = new System.IO.MemoryStream();
byte[] b = new byte[_BufferSize + 1];
int i;

ValidateKeyAndIv(true);

CryptoStream cs = new CryptoStream(ms, _crypto.CreateEncryptor(), CryptoStreamMode.Write);
i = s.Read(b, 0, _BufferSize);
while (i > 0)
{
cs.Write(b, 0, i);
i = s.Read(b, 0, _BufferSize);
}

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

return new Data(ms.ToArray());
}

///
/// Decrypts the specified data using provided key and preset initialization vector
///

public Data Decrypt(Data encryptedData, Data key)
{
this.Key = key;
return Decrypt(encryptedData);
}

///
/// Decrypts the specified stream using provided key and preset initialization vector
///

public Data Decrypt(Stream encryptedStream, Data key)
{
this.Key = key;
return Decrypt(encryptedStream);
}

///
/// Decrypts the specified stream using preset key and preset initialization vector
///

public Data Decrypt(Stream encryptedStream)
{
System.IO.MemoryStream ms = new System.IO.MemoryStream();
byte[] b = new byte[_BufferSize + 1];

ValidateKeyAndIv(false);
CryptoStream cs = new CryptoStream(encryptedStream, _crypto.CreateDecryptor(), CryptoStreamMode.Read);

int i;
i = cs.Read(b, 0, _BufferSize);

while (i > 0)
{
ms.Write(b, 0, i);
i = cs.Read(b, 0, _BufferSize);
}
cs.Close();
ms.Close();

return new Data(ms.ToArray());
}

///
/// Decrypts the specified data using preset key and preset initialization vector
///

public Data Decrypt(Data encryptedData)
{
System.IO.MemoryStream ms = new System.IO.MemoryStream(encryptedData.Bytes, 0, encryptedData.Bytes.Length);
byte[] b = new byte[encryptedData.Bytes.Length];

ValidateKeyAndIv(false);
CryptoStream cs = new CryptoStream(ms, _crypto.CreateDecryptor(), CryptoStreamMode.Read);

try
{
cs.Read(b, 0, encryptedData.Bytes.Length - 1);
}
catch (CryptographicException ex)
{
throw new CryptographicException("Unable to decrypt data. The provided key may be invalid.", ex);
}
finally
{
cs.Close();
}
return new Data(b);
}

}

#endregion

#region " Asymmetric"

///
/// Asymmetric encryption uses a pair of keys to encrypt and decrypt.
/// There is a "public" key which is used to encrypt. Decrypting, on the other hand,
/// requires both the "public" key and an additional "private" key. The advantage is
/// that people can send you encrypted messages without being able to decrypt them.
///

/// <remarks>
/// The only provider supported is the <see cref="RSACryptoServiceProvider">
///
public class Asymmetric
{

private RSACryptoServiceProvider _rsa;
private string _KeyContainerName = "Encryption.AsymmetricEncryption.DefaultContainerName";
private bool _UseMachineKeystore = true;
private int _KeySize = 1024;

private const string _ElementParent = "RSAKeyValue";
private const string _ElementModulus = "Modulus";
private const string _ElementExponent = "Exponent";
private const string _ElementPrimeP = "P";
private const string _ElementPrimeQ = "Q";
private const string _ElementPrimeExponentP = "DP";
private const string _ElementPrimeExponentQ = "DQ";
private const string _ElementCoefficient = "InverseQ";
private const string _ElementPrivateExponent = "D";

//-- http://forum.java.sun.com/thread.jsp?forum=9&thread=552022&tstart=0&trange=15
private const string _KeyModulus = "PublicKey.Modulus";
private const string _KeyExponent = "PublicKey.Exponent";
private const string _KeyPrimeP = "PrivateKey.P";
private const string _KeyPrimeQ = "PrivateKey.Q";
private const string _KeyPrimeExponentP = "PrivateKey.DP";
private const string _KeyPrimeExponentQ = "PrivateKey.DQ";
private const string _KeyCoefficient = "PrivateKey.InverseQ";
private const string _KeyPrivateExponent = "PrivateKey.D";

#region " PublicKey Class"

///
/// Represents a public encryption key. Intended to be shared, it
/// contains only the Modulus and Exponent.
///

public class PublicKey
{
public string Modulus;
public string Exponent;

public PublicKey()
{
}

public PublicKey(string KeyXml)
{
LoadFromXml(KeyXml);
}

///
/// Load public key from App.config or Web.config file
///

public void LoadFromConfig()
{
this.Modulus = Utils.GetConfigString(_KeyModulus);
this.Exponent = Utils.GetConfigString(_KeyExponent);
}

///
/// Returns *.config file XML section representing this public key
///

public string ToConfigSection()
{
StringBuilder sb = new StringBuilder();
{
sb.Append(Utils.WriteConfigKey(_KeyModulus, this.Modulus));
sb.Append(Utils.WriteConfigKey(_KeyExponent, this.Exponent));
}
return sb.ToString();
}

///
/// Writes the *.config file representation of this public key to a file
///

public void ExportToConfigFile(string filePath)
{
StreamWriter sw = new StreamWriter(filePath, false);
sw.Write(this.ToConfigSection());
sw.Close();
}

///
/// Loads the public key from its XML string
///

public void LoadFromXml(string keyXml)
{
this.Modulus = Utils.GetXmlElement(keyXml, "Modulus");
this.Exponent = Utils.GetXmlElement(keyXml, "Exponent");
}

///
/// Converts this public key to an RSAParameters object
///

public RSAParameters ToParameters()
{
RSAParameters r = new RSAParameters();
r.Modulus = Convert.FromBase64String(this.Modulus);
r.Exponent = Convert.FromBase64String(this.Exponent);
return r;
}

///
/// Converts this public key to its XML string representation
///

public string ToXml()
{
StringBuilder sb = new StringBuilder();
{
sb.Append(Utils.WriteXmlNode(_ElementParent));
sb.Append(Utils.WriteXmlElement(_ElementModulus, this.Modulus));
sb.Append(Utils.WriteXmlElement(_ElementExponent, this.Exponent));
sb.Append(Utils.WriteXmlNode(_ElementParent, true));
}
return sb.ToString();
}

///
/// Writes the Xml representation of this public key to a file
///

public void ExportToXmlFile(string filePath)
{
StreamWriter sw = new StreamWriter(filePath, false);
sw.Write(this.ToXml());
sw.Close();
}

}
#endregion

#region " PrivateKey Class"

///
/// Represents a private encryption key. Not intended to be shared, as it
/// contains all the elements that make up the key.
///

public class PrivateKey
{
public string Modulus;
public string Exponent;
public string PrimeP;
public string PrimeQ;
public string PrimeExponentP;
public string PrimeExponentQ;
public string Coefficient;
public string PrivateExponent;

public PrivateKey()
{
}

public PrivateKey(string keyXml)
{
LoadFromXml(keyXml);
}

///
/// Load private key from App.config or Web.config file
///

public void LoadFromConfig()
{
this.Modulus = Utils.GetConfigString(_KeyModulus);
this.Exponent = Utils.GetConfigString(_KeyExponent);
this.PrimeP = Utils.GetConfigString(_KeyPrimeP);
this.PrimeQ = Utils.GetConfigString(_KeyPrimeQ);
this.PrimeExponentP = Utils.GetConfigString(_KeyPrimeExponentP);
this.PrimeExponentQ = Utils.GetConfigString(_KeyPrimeExponentQ);
this.Coefficient = Utils.GetConfigString(_KeyCoefficient);
this.PrivateExponent = Utils.GetConfigString(_KeyPrivateExponent);
}

///
/// Converts this private key to an RSAParameters object
///

public RSAParameters ToParameters()
{
RSAParameters r = new RSAParameters();
r.Modulus = Convert.FromBase64String(this.Modulus);
r.Exponent = Convert.FromBase64String(this.Exponent);
r.P = Convert.FromBase64String(this.PrimeP);
r.Q = Convert.FromBase64String(this.PrimeQ);
r.DP = Convert.FromBase64String(this.PrimeExponentP);
r.DQ = Convert.FromBase64String(this.PrimeExponentQ);
r.InverseQ = Convert.FromBase64String(this.Coefficient);
r.D = Convert.FromBase64String(this.PrivateExponent);
return r;
}

///
/// Returns *.config file XML section representing this private key
///

public string ToConfigSection()
{
StringBuilder sb = new StringBuilder();
{
sb.Append(Utils.WriteConfigKey(_KeyModulus, this.Modulus));
sb.Append(Utils.WriteConfigKey(_KeyExponent, this.Exponent));
sb.Append(Utils.WriteConfigKey(_KeyPrimeP, this.PrimeP));
sb.Append(Utils.WriteConfigKey(_KeyPrimeQ, this.PrimeQ));
sb.Append(Utils.WriteConfigKey(_KeyPrimeExponentP, this.PrimeExponentP));
sb.Append(Utils.WriteConfigKey(_KeyPrimeExponentQ, this.PrimeExponentQ));
sb.Append(Utils.WriteConfigKey(_KeyCoefficient, this.Coefficient));
sb.Append(Utils.WriteConfigKey(_KeyPrivateExponent, this.PrivateExponent));
}
return sb.ToString();
}

///
/// Writes the *.config file representation of this private key to a file
///

public void ExportToConfigFile(string strFilePath)
{
StreamWriter sw = new StreamWriter(strFilePath, false);
sw.Write(this.ToConfigSection());
sw.Close();
}

///
/// Loads the private key from its XML string
///

public void LoadFromXml(string keyXml)
{
this.Modulus = Utils.GetXmlElement(keyXml, "Modulus");
this.Exponent = Utils.GetXmlElement(keyXml, "Exponent");
this.PrimeP = Utils.GetXmlElement(keyXml, "P");
this.PrimeQ = Utils.GetXmlElement(keyXml, "Q");
this.PrimeExponentP = Utils.GetXmlElement(keyXml, "DP");
this.PrimeExponentQ = Utils.GetXmlElement(keyXml, "DQ");
this.Coefficient = Utils.GetXmlElement(keyXml, "InverseQ");
this.PrivateExponent = Utils.GetXmlElement(keyXml, "D");
}

///
/// Converts this private key to its XML string representation
///

public string ToXml()
{
StringBuilder sb = new StringBuilder();
{
sb.Append(Utils.WriteXmlNode(_ElementParent));
sb.Append(Utils.WriteXmlElement(_ElementModulus, this.Modulus));
sb.Append(Utils.WriteXmlElement(_ElementExponent, this.Exponent));
sb.Append(Utils.WriteXmlElement(_ElementPrimeP, this.PrimeP));
sb.Append(Utils.WriteXmlElement(_ElementPrimeQ, this.PrimeQ));
sb.Append(Utils.WriteXmlElement(_ElementPrimeExponentP, this.PrimeExponentP));
sb.Append(Utils.WriteXmlElement(_ElementPrimeExponentQ, this.PrimeExponentQ));
sb.Append(Utils.WriteXmlElement(_ElementCoefficient, this.Coefficient));
sb.Append(Utils.WriteXmlElement(_ElementPrivateExponent, this.PrivateExponent));
sb.Append(Utils.WriteXmlNode(_ElementParent, true));
}
return sb.ToString();
}

///
/// Writes the Xml representation of this private key to a file
///

public void ExportToXmlFile(string filePath)
{
StreamWriter sw = new StreamWriter(filePath, false);
sw.Write(this.ToXml());
sw.Close();
}
}

#endregion

///
/// Instantiates a new asymmetric encryption session using the default key size;
/// this is usally 1024 bits
///

public Asymmetric()
{
_rsa = GetRSAProvider();
}

///
/// Instantiates a new asymmetric encryption session using a specific key size
///

public Asymmetric(int keySize)
{
_KeySize = keySize;
_rsa = GetRSAProvider();
}

///
/// Sets the name of the key container used to store this key on disk; this is an
/// unavoidable side effect of the underlying Microsoft CryptoAPI.
///

/// <remarks>
/// http://support.microsoft.com/default.aspx?scid=http://support.microsoft.com:80/support/kb/articles/q322/3/71.asp&NoWebContent=1
///
public string KeyContainerName
{
get { return _KeyContainerName; }
set { _KeyContainerName = value; }
}

///
/// Returns the current key size, in bits
///

public int KeySizeBits
{
get { return _rsa.KeySize; }
}

///
/// Returns the maximum supported key size, in bits
///

public int KeySizeMaxBits
{
get { return _rsa.LegalKeySizes[0].MaxSize; }
}

///
/// Returns the minimum supported key size, in bits
///

public int KeySizeMinBits
{
get { return _rsa.LegalKeySizes[0].MinSize; }
}

///
/// Returns valid key step sizes, in bits
///

public int KeySizeStepBits
{
get { return _rsa.LegalKeySizes[0].SkipSize; }
}

///
/// Returns the default public key as stored in the *.config file
///

public PublicKey DefaultPublicKey
{
get
{
PublicKey pubkey = new PublicKey();
pubkey.LoadFromConfig();
return pubkey;
}
}

///
/// Returns the default private key as stored in the *.config file
///

public PrivateKey DefaultPrivateKey
{
get
{
PrivateKey privkey = new PrivateKey();
privkey.LoadFromConfig();
return privkey;
}
}

///
/// Generates a new public/private key pair as objects
///

public void GenerateNewKeyset(ref PublicKey publicKey, ref PrivateKey privateKey)
{
string PublicKeyXML = null;
string PrivateKeyXML = null;
GenerateNewKeyset(ref PublicKeyXML, ref PrivateKeyXML);
publicKey = new PublicKey(PublicKeyXML);
privateKey = new PrivateKey(PrivateKeyXML);
}

///
/// Generates a new public/private key pair as XML strings
///

public void GenerateNewKeyset(ref string publicKeyXML, ref string privateKeyXML)
{
RSA rsa = RSACryptoServiceProvider.Create();
publicKeyXML = rsa.ToXmlString(false);
privateKeyXML = rsa.ToXmlString(true);
}

///
/// Encrypts data using the default public key
///

public Data Encrypt(Data d)
{
PublicKey PublicKey = DefaultPublicKey;
return Encrypt(d, PublicKey);
}

///
/// Encrypts data using the provided public key
///

public Data Encrypt(Data d, PublicKey publicKey)
{
_rsa.ImportParameters(publicKey.ToParameters());
return EncryptPrivate(d);
}

///
/// Encrypts data using the provided public key as XML
///

public Data Encrypt(Data d, string publicKeyXML)
{
LoadKeyXml(publicKeyXML, false);
return EncryptPrivate(d);
}

private Data EncryptPrivate(Data d)
{
try
{
return new Data(_rsa.Encrypt(d.Bytes, false));
}
catch (CryptographicException ex)
{
if (ex.Message.ToLower().IndexOf("bad length") > -1)
{
throw new CryptographicException("Your data is too large; RSA encryption is designed to encrypt relatively small amounts of data. The exact byte limit depends on the key size. To encrypt more data, use symmetric encryption and then encrypt that symmetric key with asymmetric RSA encryption.", ex);
}
else
{
throw;
}
}
}

///
/// Decrypts data using the default private key
///

public Data Decrypt(Data encryptedData)
{
PrivateKey PrivateKey = new PrivateKey();
PrivateKey.LoadFromConfig();
return Decrypt(encryptedData, PrivateKey);
}

///
/// Decrypts data using the provided private key
///

public Data Decrypt(Data encryptedData, PrivateKey PrivateKey)
{
_rsa.ImportParameters(PrivateKey.ToParameters());
return DecryptPrivate(encryptedData);
}

///
/// Decrypts data using the provided private key as XML
///

public Data Decrypt(Data encryptedData, string PrivateKeyXML)
{
LoadKeyXml(PrivateKeyXML, true);
return DecryptPrivate(encryptedData);
}

private void LoadKeyXml(string keyXml, bool isPrivate)
{
try
{
_rsa.FromXmlString(keyXml);
}
catch (System.Security.XmlSyntaxException ex)
{
string s;
if (isPrivate)
{
s = "private";
}
else
{
s = "public";
}
throw new System.Security.XmlSyntaxException(string.Format("The provided {0} encryption key XML does not appear to be valid.", s), ex);
}
}

private Data DecryptPrivate(Data encryptedData)
{
return new Data(_rsa.Decrypt(encryptedData.Bytes, false));
}

///
/// gets the default RSA provider using the specified key size;
/// note that Microsoft's CryptoAPI has an underlying file system dependency that is unavoidable
///

/// <remarks>
/// http://support.microsoft.com/default.aspx?scid=http://support.microsoft.com:80/support/kb/articles/q322/3/71.asp&NoWebContent=1
///
private RSACryptoServiceProvider GetRSAProvider()
{
RSACryptoServiceProvider rsa = null;
CspParameters csp = null;
try
{
csp = new CspParameters();
csp.KeyContainerName = _KeyContainerName;
rsa = new RSACryptoServiceProvider(_KeySize, csp);
rsa.PersistKeyInCsp = false;
RSACryptoServiceProvider.UseMachineKeyStore = true;
return rsa;
}
catch (System.Security.Cryptography.CryptographicException ex)
{
if (ex.Message.ToLower().IndexOf("csp for this implementation could not be acquired") > -1)
{
throw new Exception("Unable to obtain Cryptographic Service Provider. " + "Either the permissions are incorrect on the " + "'C:\\Documents and Settings\\All Users\\Application Data\\Microsoft\\Crypto\\RSA\\MachineKeys' " + "folder, or the current security context '" + System.Security.Principal.WindowsIdentity.GetCurrent().Name + "'" + " does not have access to this folder.", ex);
}
else
{
throw;
}
}
finally
{
if ((rsa != null))
{
rsa = null;
}
if ((csp != null))
{
csp = null;
}
}
}

}

#endregion

#region " Data"

///
/// represents Hex, Byte, Base64, or String data to encrypt/decrypt;
/// use the .Text property to set/get a string representation
/// use the .Hex property to set/get a string-based Hexadecimal representation
/// use the .Base64 to set/get a string-based Base64 representation
///

public class Data
{
private byte[] _b;
private int _MaxBytes = 0;
private int _MinBytes = 0;
private int _StepBytes = 0;

///
/// Determines the default text encoding across ALL Data instances
///

public static System.Text.Encoding DefaultEncoding = System.Text.Encoding.GetEncoding("Windows-1252");

///
/// Determines the default text encoding for this Data instance
///

public System.Text.Encoding Encoding = DefaultEncoding;

///
/// Creates new, empty encryption data
///

public Data()
{
}

///
/// Creates new encryption data with the specified byte array
///

public Data(byte[] b)
{
_b = b;
}

///
/// Creates new encryption data with the specified string;
/// will be converted to byte array using default encoding
///

public Data(string s)
{
this.Text = s;
}

///
/// Creates new encryption data using the specified string and the
/// specified encoding to convert the string to a byte array.
///

public Data(string s, System.Text.Encoding encoding)
{
this.Encoding = encoding;
this.Text = s;
}

///
/// returns true if no data is present
///

public bool IsEmpty
{
get
{
if (_b == null)
{
return true;
}

if (_b.Length == 0)
{
return true;
}
return false;
}
}

///
/// allowed step interval, in bytes, for this data; if 0, no limit
///

public int StepBytes
{
get { return _StepBytes; }
set { _StepBytes = value; }
}

///
/// allowed step interval, in bits, for this data; if 0, no limit
///

public int StepBits
{
get { return _StepBytes * 8; }
set { _StepBytes = value / 8; }
}

///
/// minimum number of bytes allowed for this data; if 0, no limit
///

public int MinBytes
{
get { return _MinBytes; }
set { _MinBytes = value; }
}

///
/// minimum number of bits allowed for this data; if 0, no limit
///

public int MinBits
{
get { return _MinBytes * 8; }
set { _MinBytes = value / 8; }
}

///
/// maximum number of bytes allowed for this data; if 0, no limit
///

public int MaxBytes
{
get { return _MaxBytes; }
set { _MaxBytes = value; }
}

///
/// maximum number of bits allowed for this data; if 0, no limit
///

public int MaxBits
{
get { return _MaxBytes * 8; }
set { _MaxBytes = value / 8; }
}

///
/// Returns the byte representation of the data;
/// This will be padded to MinBytes and trimmed to MaxBytes as necessary!
///

public byte[] Bytes
{
get
{
if (_MaxBytes > 0)
{
if (_b.Length > _MaxBytes)
{
byte[] b = new byte[_MaxBytes];
Array.Copy(_b, b, b.Length);
_b = b;
}
}

if (_MinBytes > 0)
{
if (_b.Length < _MinBytes)
{
byte[] b = new byte[_MinBytes];
Array.Copy(_b, b, _b.Length);
_b = b;
}
}
return _b;
}
set { _b = value; }
}

///
/// Sets or returns text representation of bytes using the default text encoding
///

public string Text
{
get
{
if (_b == null)
{
return "";
}
else
{
//-- need to handle nulls here; oddly, C# will happily convert
//-- nulls into the string whereas VB stops converting at the
//-- first null!
int i = Array.IndexOf(_b, (byte)0);
if (i >= 0)
{
return this.Encoding.GetString(_b, 0, i);
}
else
{
return this.Encoding.GetString(_b);
}
}
}
set { _b = this.Encoding.GetBytes(value); }
}

///
/// Sets or returns Hex string representation of this data
///

public string Hex
{
get { return Utils.ToHex(_b); }
set { _b = Utils.FromHex(value); }
}

///
/// Sets or returns Base64 string representation of this data
///

public string Base64
{
get { return Utils.ToBase64(_b); }
set { _b = Utils.FromBase64(value); }
}

///
/// Returns text representation of bytes using the default text encoding
///

public new string ToString()
{
return this.Text;
}

///
/// returns Base64 string representation of this data
///

public string ToBase64()
{
return this.Base64;
}

///
/// returns Hex string representation of this data
///

public string ToHex()
{
return this.Hex;
}

}

#endregion

#region " Utils"

///
/// Friend class for shared utility methods used by multiple Encryption classes
///

internal class Utils
{

///
/// converts an array of bytes to a string Hex representation
///

static internal string ToHex(byte[] ba)
{
if (ba == null || ba.Length == 0)
{
return "";
}
const string HexFormat = "{0:X2}";
StringBuilder sb = new StringBuilder();
foreach (byte b in ba)
{
sb.Append(string.Format(HexFormat, b));
}
return sb.ToString();
}

///
/// converts from a string Hex representation to an array of bytes
///

static internal byte[] FromHex(string hexEncoded)
{
if (hexEncoded == null || hexEncoded.Length == 0)
{
return null;
}
try
{
int l = Convert.ToInt32(hexEncoded.Length / 2);
byte[] b = new byte[l];
for (int i = 0; i <= l - 1; i++)
{
b[i] = Convert.ToByte(hexEncoded.Substring(i * 2, 2), 16);
}
return b;
}
catch (Exception ex)
{
throw new System.FormatException("The provided string does not appear to be Hex encoded:" + Environment.NewLine + hexEncoded + Environment.NewLine, ex);
}
}

///
/// converts from a string Base64 representation to an array of bytes
///

static internal byte[] FromBase64(string base64Encoded)
{
if (base64Encoded == null || base64Encoded.Length == 0)
{
return null;
}
try
{
return Convert.FromBase64String(base64Encoded);
}
catch (System.FormatException ex)
{
throw new System.FormatException("The provided string does not appear to be Base64 encoded:" + Environment.NewLine + base64Encoded + Environment.NewLine, ex);
}
}

///
/// converts from an array of bytes to a string Base64 representation
///

static internal string ToBase64(byte[] b)
{
if (b == null || b.Length == 0)
{
return "";
}
return Convert.ToBase64String(b);
}

///
/// retrieve an element from an XML string
///

static internal string GetXmlElement(string xml, string element)
{
Match m;
m = Regex.Match(xml, "<" + element + ">(?<element>[^>]*)", RegexOptions.IgnoreCase);
if (m == null)
{
throw new Exception("Could not find <" + element + "> in provided Public Key XML.");
}
return m.Groups["Element"].ToString();
}

///
/// Returns the specified string value from the application .config file
///

static internal string GetConfigString(string key)
{
return GetConfigString(key, true);
}

///
/// Returns the specified string value from the application .config file
///

static internal string GetConfigString(string key, bool isRequired)
{

string s = (string)ConfigurationManager.AppSettings.Get(key);
if (s == null)
{
if (isRequired)
{
throw new ConfigurationErrorsException("key <" + key + "> is missing from .config file");
}
else
{
return "";
}
}
else
{
return s;
}
}

static internal string WriteConfigKey(string key, string value)
{
string s = "<add key="\"{0}\"" value="\"{1}\"">" + Environment.NewLine;
return string.Format(s, key, value);
}

static internal string WriteXmlElement(string element, string value)
{
string s = "<{0}>{1}" + Environment.NewLine;
return string.Format(s, element, value);
}

static internal string WriteXmlNode(string element)
{
return WriteXmlNode(element, false);
}

static internal string WriteXmlNode(string element, bool isClosing)
{
string s;
if (isClosing)
{
s = "" + Environment.NewLine;
}
else
{
s = "<{0}>" + Environment.NewLine;
}
return string.Format(s, element);
}

}
}

#endregion

Regards,
Kalyan Krishna

GeneralRe: Have it in C#? Pin
Fenasi Kerim6-Sep-07 16:43
Fenasi Kerim6-Sep-07 16:43 
GeneralRe: Have it in C#? Pin
smimon18-Oct-07 23:34
smimon18-Oct-07 23:34 
GeneralRe: Have it in C#? [modified] Pin
Alex Talazar11-Jun-08 6:44
professionalAlex Talazar11-Jun-08 6:44 
GeneralRe: Have it in C#? Pin
Rob Harlow27-Jun-08 2:55
Rob Harlow27-Jun-08 2:55 
AnswerRe: Have it in C#? (untested vb to c# conversion) Pin
_Groker30-Dec-08 5:02
_Groker30-Dec-08 5:02 
AnswerRe: Have it in C#? Pin
Mr President19-Feb-09 16:17
Mr President19-Feb-09 16:17 
GeneralGood read Pin
swan3931-Mar-07 13:13
swan3931-Mar-07 13:13 
GeneralNice one Pin
terryhutt1959@hotmail.com21-Mar-07 11:50
terryhutt1959@hotmail.com21-Mar-07 11:50 
GeneralError in the article Pin
Trinetra20-Feb-07 19:18
Trinetra20-Feb-07 19:18 
QuestionWon't compile Pin
Pong God2-Feb-07 18:02
Pong God2-Feb-07 18:02 
AnswerRe: Won't compile Pin
beaule.p14-Mar-07 18:28
beaule.p14-Mar-07 18:28 
QuestionGeneral Security Questions Pin
dotNugga31-Jan-07 17:33
dotNugga31-Jan-07 17:33 
GeneralGreat! Pin
elygirang29-Jan-07 19:07
elygirang29-Jan-07 19:07 
GeneralMissing Pin
Jan Seda29-Jan-07 1:38
professionalJan Seda29-Jan-07 1:38 
GeneralThis was just great Pin
defwebserver17-Dec-06 3:59
defwebserver17-Dec-06 3:59 
GeneralGood one Pin
Pradeep C26-Oct-06 10:37
Pradeep C26-Oct-06 10:37 
QuestionUrgent, Cannot Sign the Hash with Priv Key Pin
doggy37-Sep-06 3:29
doggy37-Sep-06 3:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.