Click here to Skip to main content
Click here to Skip to main content

.NET Encryption Simplified

By , 28 Jan 2007
 

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 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":

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:

.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.

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.

.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:

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:

.ToHex = '92C7C0F251D98DEA2ACC49B21CF08070'

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

.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:

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:

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:

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:

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:

<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:

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:

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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

wumpus1
Web Developer
United States United States
Member
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.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionWhy on earth did you do this in VB?membermsdevtech29 Jan '13 - 2:21 
Why?
AnswerRe: Why on earth did you do this in VB?memberreeselmiller218 Mar '13 - 7:13 
Why Not? Learn about code converters "VB to C#".
AnswerRe: Why on earth did you do this in VB?memberLambert Antonio24 Mar '13 - 20:35 
there's not much of a difference if you do this in VB.Net or C#, you're in .Net, it's the same library
QuestionThank you!memberdfowler19654 Dec '12 - 12:34 
Awesome article! Very informative and plenty of examples to get me going.
QuestionDeHash a Hashmember3d-codeaholic16 Nov '12 - 12:20 
Is there a way to take a value that has been Hashed and to "DE" Hash it. I like to timestamp the Hash. So I would not only like to match the hatch but investigate inside and make sure the time stamp is plus or minus say 15 mins. old. That way the Hash has a life on it.
YoYoYo.

AnswerRe: DeHash a Hash [modified]memberMember 94592307 May '13 - 16:32 
You can't de-hash a hash. That's why it's used the way it is, as a one-way encryption. But to solve your issue, why not just create a compact string representation of a date time and insert it into the beginning or end of your hash. Later, when evaluating the hash in code, you can evaluate the date then strip it out and process the rest of the hash. For example, May 7, 2013 at 7:24pm could be condensed to 1305071924 (represents 2013/05/07 at 19:24 hours or 7:24pm). Just be sure to use leading zeros (i.e. May 7 as 0507 instead of 57). This will ensure your datetime string is always the same length and easy to parse. When encoding dates this way I always put the year first so that if the dates are sorted alphabetically they will also be sorted chronologically. Thumbs Up | :thumbsup:
Fan-freakin'-tastic.


modified 7 May '13 - 22:41.

QuestionGreat article !memberDieter Vander Donckt26 Sep '12 - 4:37 
Thank you for this great article. 5 stars !
.NET encryption explained in a simple way.
GeneralThis is very good article.memberJayesh Sorathia29 Aug '12 - 22:35 
This is very good article.
To learn more on Password Encryption in .Net with C# Examples and VB.Net Examples
In this Example we use MD5 algorithm. Means Encrypt password using MD5 algorithm.
Visit this link. Link.
QuestionDifferent results when compared to equivalent encryption toolsmemberMarkRBaxter20 Aug '12 - 2:37 
Hi,
 
I appreciate that this is an old article and I may not receive a reply - however fingers crossed Smile | :)
 
All of my searches relating to encryption seem to come back to this article and I've been Googling and looking for information for days. I'm just looking for a reliable, standard method for symmetric encryption and finally have settled on this one (thank you!) - however - when I compare encrypted results generated by this code, against the results from other online tools, the resulting encryption is always different.
 
It's the same with all options, but lets say DES for example purposes since we know the key is always going to be the same (64).
With a string of "test" and a key of "test", this code generates a hex of "1017D5DB5C4065C9". Every other online tool I can find generates it's own UNIQUE results - but why is this? Surely symmetric 64 bit DES encryption should yield the same results? Or am I missing something (like a brain)?
 
Any advice would be very much appreciated!
 
Thanks..
 
One example online tool:
http://support.persits.com/encrypt/demo_text.asp
GeneralThanks!memberPaulo Vaz31 Mar '12 - 4:52 
You probably just saved me a couple of work days. Big Thanks!
GeneralMy vote of 5membermanoj kumar choubey29 Mar '12 - 20:09 
Nice
QuestionPlease help me with decryptionmemberfsman10219 Feb '12 - 8:01 
Hi, I'm doing some file encryption work. I'm reading the file, encrypting the data, and writing it back to the file. This works just fine until I try to decrypt.
I'm successfully getting the string of encrypted characters from the file and passing it to the decrypt sub seen below.
 
    Dim base64EncryptedString As String
    Dim key As New Encryption.Data(My.Settings.Key / 1024)
    Dim encrypted As String
    Dim unencrypted As String
    Public Sub Encrypt(ByVal toencrypt As String)
        Dim sym As New Encryption.Symmetric(Encryption.Symmetric.Provider.Rijndael)
        Dim encryptedData As Encryption.Data
        encryptedData = sym.Encrypt(New Encryption.Data(toencrypt), key)
        base64EncryptedString = encryptedData.ToBase64
        encrypted = base64EncryptedString.ToString
    End Sub
    Public Sub Decrypt(ByVal tounencrypt As String)
        Dim byt As Byte() = System.Text.Encoding.UTF8.GetBytes(tounencrypt)
        Dim todecrypt As String = Convert.ToBase64String(byt)
        Dim sym As New Encryption.Symmetric(Encryption.Symmetric.Provider.Rijndael)
        Dim encryptedData As New Encryption.Data
        encryptedData.Base64 = todecrypt
        Dim decryptedData As Encryption.Data
        decryptedData = sym.Decrypt(encryptedData, key)
        unencrypted = decryptedData.ToString
    End Sub
 
When I try to decrypt the file, the program throws "Cryptographic Exception was unhandled" and says "Unable to decrypt data. The provided key may be invalid."
 
Any ideas of what I did wrong? Unsure | :~
 
Thanks for the help! Big Grin | :-D
GeneralMy vote of 5membersanjon966 Feb '12 - 3:53 
Great Article!!!
To the author:
Do I have permission to use this class in a project I am making for someone else?
SuggestionMisconceptions in this articlememberDEGT2 Feb '12 - 7:37 
The article is not 100% correct, as we know Asymmetric Encryption algorithms such as RSA (Rivest, Shamir, Adleman) use both a Public and Private Key whereas Symmetric Encryption algorithms only have a Secret key.
 
The problem with this article is that it leads the reader to believe that you use the Public key to encrypt and the Private key to decrypt. If this was 100% true, the recipient would have (as indicated in the article) to have the "additional" Private Key and basically if the recipient has the private key your whole asymmetric encryption is as good as shouting your sensitive data out loud.
 
With asymmetric algorithms the Sender has both a Private AND Public key. The Private key is PRIVATE (for that reason), it is kept and guarded ONLY by the SENDER. The sender encrypts a message using the PRIVATE key and can optionally SIGN it.
 
The recipient on the other hand only has the sender's PUBLIC key which is shared and a subset of the entire public/private key parameters. When the recipient receives a signed message, the signature is VERIFIED with the SENDER's PUBLIC key, that way he knows it was signed by the sender because the sender is the only one with the PRIVATE key (unless security has been breached).
 
If the message received is encrypted (asymmetric) then the recipient DECRYPTS that message using the SENDER's PUBLIC key (shared).
 
Now what the confusion here is is that the RSA public key can also be used for encryption but this is only a special case that is used for Key Exchange in which two parties use Asymmetric Encryption and exchange a secret (symmetric) key between each other. In this key exchange the Sender encrypts the secret key with the recipient's PUBLIC key and then the recipient is the only one that can decrypt the symmetric key that was exchanged because the recipient has the PRIVATE key that matches the PUBLIC key that was used for the key exchange. (See [Secret Key Exchange])
 
In other words, the Sender ALWAYS keeps (and never distributes) his/her PRIVATE key which is contrary to what you say in your article.
 
Also, for an example of the above mentioned symmetric key exchange using RSA (and AES as the symmetric algorithm) see http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsaoaepkeyexchangeformatter(v=vs.100).aspx[RSA Key Exchange]
http://www.coralys.com/
http://www.virtual-aviation.net/

GeneralMy vote of 5memberamitmishra70719 Nov '11 - 17:58 
good
excllent
i want in C# to
BugThree errors in .NetFx3 fixedmemberGabriel X27 Jun '11 - 5:04 
I faced an error while launching this class, using .Net Framework 3
here are the solutions:
Text.Encoding --> Encoding
ConfigurationManager.AppSettings --> ConfigurationSettings.AppSettings
ConfigurationErrorsException --> ConfigurationException

Thanx for this great article!
Gabriel X

AnswerRe: Three errors in .NetFx3 fixedmemberDush Abe7 Aug '11 - 18:01 
It is not a bug. I also got 2 configuration errors. All you need is to add reference to System.configuration.
I didn't have the error with Text.Encoding, probably you may need to add reference to System.Text.
 
Also I agree this is a great article!! :|
GeneralMy vote of 5memberSenthil Kumar Selvaraj23 May '11 - 14:32 
Just what i needed. Excellent
GeneralMy vote of 5memberparthii3 Mar '11 - 20:39 
Simple and Clear
GeneralMy vote of 2memberGarry Lowther11 Jun '10 - 3:50 
Your example does not provide code which shows how to encrypt in an example function and decrypt in another! i.e. you decrypt an instance of an encrypted object - not independent strings!
GeneralRe: My vote of 2memberdimethol19 Sep '11 - 0:20 
'Here is the code that does a simple decryption.
'provided that you pass encrypted text to a text file from his Symmetric Demo.
'NOTE: you have to pass encryptedData.Text to the text file from his Demo.
 

 

Sub myDemoSymmetric()
 
        Try
            Dim sr As IO.StreamReader = New IO.StreamReader("encryptedText.txt")
            Dim line As String
 
            line = sr.ReadLine()
            Console.WriteLine(line)
            Dim Key As String = "MyKey"
            Dim p As Encryption.Encryption.Symmetric.Provider = Encryption.Encryption.Symmetric.Provider.DES
 
            Dim decryptedData As Encryption.Encryption.Data
            Dim sym2 As New Encryption.Encryption.Symmetric(p)
            Dim d As New Encryption.Encryption.Data(line)
 
            sym2.Key.Text = Key
 

            Console.WriteLine()
 
            Console.WriteLine("Key")
            Console.WriteLine("  Text    " & sym2.Key.Text)
            Console.WriteLine("  Hex     " & sym2.Key.Hex)
            Console.WriteLine("  Base64  " & sym2.Key.Base64)
            Debug.Print(sym2.Key.Hex)
 
            Console.WriteLine()
 
            ' decryptedData = sym2.Decrypt(sr.BaseStream, sym2.Key)
            decryptedData = sym2.Decrypt(d)
 
            Console.WriteLine("decrypted string")
            Console.WriteLine("  " & decryptedData.Text)
 
            Console.ReadLine()
            sr.Close()
 
        Catch E As Exception
            ' Let the user know what went wrong.
            Console.WriteLine("The file could not be read:")
            Console.WriteLine(E.Message)
            Console.ReadLine()
        End Try
 
    End Sub

GeneralEncrypted text same length as plaintextmembertrhalvorson1 Feb '10 - 6:37 
Beautimous. Lovely article and source code. Thanks a bunch.
 
In some applications, it is necessary to generate encrypted text that has the same length as the plaintext. Which of the encryption algorithms provided in .NET does that? Is there one you particularly recommend?
GeneralSmooth and Easy to Understandmembermjordan16 Dec '09 - 13:58 
I would like to thank you first for sharing this great article, it been really smooth and well-formed, and I have a little question; Is the "salt string" the same for all passwords or it is randomly chosen for each password???
GeneralGreat Article [modified]memberRichard Osafo15 Nov '09 - 4:49 
Thanks so much for the explanation. Really needed it.
 
modified on Sunday, November 15, 2009 10:55 AM

GeneralRe: Great ArticlememberShaneMcDonald12 Aug '10 - 7:08 
Agreed, Thank you for sharing this with us!
QuestionSymmetric encryption - code issue or by design?memberGalleySlave30 Jun '09 - 22:09 
I am using symmetric encryption on a byte stream which is the serialisation of a simple class
 
If I have an input byte arrayof 15 bytes I get an encrypted string of 16 bytes
If however I declare an input byte array of 16 bytes (0 .. 15) I get an encrypted string of 32 bytes
 
i.e.
Dim k(14) as byte ' (i.e. 15 byteps long 0 .. 14)
' fill k with data
Dim sym As New Encryption.Symmetric(Encryption.Symmetric.Provider.Rijndael)
Dim key As New Encryption.Data(GetKey(ClientName))
Dim encryptedData As Encryption.Data = sym.Encrypt(New Encryption.Data(k.toByte()), key)
 
however Dim k(15)
gives encryptedData of 32 bytes.
 
Is this a function of the encryption? I have verified that the length is indeed correct:
in
       Public Function Encrypt(ByVal d As Data) As Data
            Dim ms As New IO.MemoryStream
 
            ValidateKeyAndIv(True)
 
            Dim cs As New CryptoStream(ms, _crypto.CreateEncryptor(), CryptoStreamMode.Write)
            cs.Write(d.Bytes, 0, d.Bytes.Length)
            cs.Close()
            ms.Close()
 
            Return New Data(ms.ToArray)
       end function
 
if d.Bytes.Length = 16 then the length of returned encrypted data is 32
if d.Bytes.Length = 15 then the length of returned encrypted data is 16
 
Thx
GeneralCode translated to C#memberfelipecsl18 Jun '09 - 3:54 
Hi Jeff and everyone,
 
Thanks for sharing your knowlegde. This code was of great value to me. I also translated it to C# and wrote a post on my blog about the usage and a link for download of the C# code. http://blog.felipel.com/post/Hiding-sensitive-data-in-the-query-string.aspx[^]
 
Felipe
GeneralRe: Code translated to C#memberPrishalan3 Aug '09 - 22:45 
Hey Felipe,
 
Thanks for taking the time to do this! and thanks to Jeff for a well explained article
GeneralRe: Code translated to C#membermay_east19 Aug '09 - 10:01 
thanks for the port to c#.
please look at my post about a problem in the Decrypt function in the "Symmetric" Class.
From looking in your port, i see that this problem might still exist.
GeneralRe: Code translated to C#memberbscaer27 Oct '11 - 8:31 
Link has changed:
http://blog.felipel.com/2009/06/hiding-sensitive-data-in-the-query-string/[^]
Question.Clear() method to cleanupmembermongoose_za7 May '09 - 2:03 
Hi there...
 
I think this is a great class which wumpus1 has created also passing on knowledge of a subject I find very complicated but in a simple way. Kudos to you..
 
My question is: When I was doing my MCPD course I remember having to use the Clear method on CryptoGraphic object to overwrite the memory with zeros. Because the garbage collector doesn't take care of the contents of the memory.
 
How does that or how should it apply to this class? I've used this class to encrypt and decrypt information but didn't find a clear method and have no idea how to implement it.
GeneralDecrypt using Symmetric keymembermay_east29 Apr '09 - 6:34 
Hi,
i enjoyed you're code !
it really helped me.
 
i wrote a PKI class that wrappes your code and it works like a charm.
i recently encountered a problem with Decrypting a byte array using 3DES.
 
the problem was referred to in other posts here.
when you descrypt, you don't know what the original size of the byte array was. so you decrypt into a newly created array with the size of the Encrypted array.
 
This results in a byte array that is padded with nulls (0) at the end.
 
in the
Public Function Decrypt(ByVal encryptedData As Data) As Data
you declare the output "b" variable with the length of the input
 
Dim b() As Byte = New Byte(encryptedData.Bytes.Length - 1) {}
then you call
 
cs.Read(b, 0, encryptedData.Bytes.Length - 1)
 
and later :
 
Return New Data(b)
 

in order to solve this problem:
 
declare
 
Dim c() As Byte
right after declaring b()
 
use:
 
Dim i As Integer
i = cs.Read(b, 0, encryptedData.Bytes.Length - 1)
ReDim c(i - 1)
Buffer.BlockCopy(b, 0, c, 0, i)
 
and return "c" instead of "b"
return New Data(c)
 
hope this will help others...
 
here is the complete revised function:
 
  ''' <summary>
    ''' Decrypts the specified data using preset key and preset initialization vector
    ''' </summary>
    Public Function Decrypt(ByVal encryptedData As Data) As Data
        Dim ms As New System.IO.MemoryStream(encryptedData.Bytes, 0, encryptedData.Bytes.Length)
        Dim b() As Byte = New Byte(encryptedData.Bytes.Length - 1) {}
        Dim c() As Byte
        ValidateKeyAndIv(False)
        Dim cs As New CryptoStream(ms, _crypto.CreateDecryptor(), CryptoStreamMode.Read)
 
        Try
            Dim i As Integer
            i = cs.Read(b, 0, encryptedData.Bytes.Length - 1)
            ReDim c(i - 1)
            Buffer.BlockCopy(b, 0, c, 0, i)
 
        Catch ex As CryptographicException
            Throw New CryptographicException("Unable to decrypt data. The provided key may be invalid.", ex)
        Finally
            cs.Close()
        End Try
        Return New Data(c)
    End Function

GeneralRe: Decrypt using Symmetric keymemberJason Vetter22 Sep '10 - 6:41 
Sweet fix man I was getting frustrated by 5 extra bytes in my sample file after decrypting.
Great fix!
GeneralTroubleshooting Decryption in C# - Please HelpmemberClayton Q.18 Mar '09 - 9:57 
Here's my code:
 
      protected void Page_Load(object sender, EventArgs e)
      {
            string original = "1234567890123456";
            Literal1.Text = "original: " + original + "&lt;br /&gt;";
            string base64EncryptedString = SimpleEncrypt(original);
            Literal1.Text += "encrypted: " + base64EncryptedString + "&lt;br /&gt;";
            string decryptedData = SimpleDecrypt(base64EncryptedString);
            Literal1.Text += "decrypted: " + decryptedData.ToString();
      }
      protected string SimpleEncrypt(string original)
      {
            Encryption.Symmetric sym = new Encryption.Symmetric(Encryption.Symmetric.Provider.Rijndael, true);
            Encryption.Data key = new Encryption.Data("My Password");
            Encryption.Data encryptedData = default(Encryption.Data);
            encryptedData = sym.Encrypt(new Encryption.Data(original), key);
            return encryptedData.ToBase64();
      }
      protected string SimpleDecrypt(string base64EncryptedString)
      {
            Encryption.Symmetric sym = new Encryption.Symmetric(Encryption.Symmetric.Provider.Rijndael, true);
            Encryption.Data key = new Encryption.Data("My Password");
            Encryption.Data encryptedData = default(Encryption.Data);
            encryptedData.Base64 = base64EncryptedString;
            Encryption.Data decryptedData = default(Encryption.Data);
            decryptedData = sym.Decrypt(encryptedData, key);
            return decryptedData.ToString();
      }
 

This code Encrypts happily, but fails to Decrypt. On the line in SimpleDecrypt that starts "encryptedData.Base64...", it says the object reference is not set to an instance of an object. When I hover over "encryptedData" in that line it says "null". I don't know why it's null, since it was created in the line above it.
 
I sure would appreciate any help.
AnswerRe: Troubleshooting Decryption in C# - Please HelpmemberPatrick Wolf22 Feb '10 - 0:25 
I know it's a while ago but here this works:
void Main()
{
	string a = "The most secret secret :)";
	string pass = "pass";
	string e = SimpleEncrypt(a,pass);
	string d= SimpleDecrypt(e,pass);
	Console.WriteLine("{0} -> {1} -> {2}",a,e,d);
	Console.WriteLine(a==d);
}
 
// Define other methods and classes here
public static string SimpleEncrypt(string original, string password)
{
	Encryption.Symmetric sym = new Encryption.Symmetric(Encryption.Symmetric.Provider.Rijndael, true);
	Encryption.Data key = new Encryption.Data(password);
	Encryption.Data encryptedData = sym.Encrypt(new Encryption.Data(original),key);			
	return encryptedData.ToBase64();
}
public static string SimpleDecrypt(string base64EncryptedString, string password)
{
	Encryption.Symmetric sym = new Encryption.Symmetric(Encryption.Symmetric.Provider.Rijndael, true);
	Encryption.Data key = new Encryption.Data(password);
	Encryption.Data encryptedData = new Encryption.Data();
	encryptedData.Base64 = base64EncryptedString;
	Encryption.Data decryptedData = sym.Decrypt(encryptedData, key);
	return decryptedData.ToString();
}

QuestionError on RSACryptoServiceProvider.ImportParameters in Utils._ImportKeymembermdepaepe25 Feb '09 - 0:36 
Hello,
 
I developed web services (asmx) using your utilities to encrypt some part of the content using asymetric RSA encryption. In my dev environment, everything went fine and we have deployed the application on a server managed by an outsourcing company (no real access to the server). On both Test and production system (running on the same server), we always get the following error:
 
System.ObjectDisposedException: Safe handle's handle field can only be set if the safe handle is not closed and has a ref count of 1.
at System.Security.Cryptography.Utils._ImportKey(SafeProvHandle hCSP, Int32 keyNumber, CspProviderFlags flags, Object cspObject, SafeKeyHandle& hKey)
at System.Security.Cryptography.RSACryptoServiceProvider.ImportParameters(RSAParameters parameters)
at Encryption.Asymmetric.Decrypt(Data encryptedData, PrivateKey PrivateKey) in d:\.....\Encryption.vb:line 933

 
This is coming very often but and during some periods but at that time, a part of the calls continue to be successful.
 
Could you help ?
 
Many thanks.
 
Michel
GeneralProblem with Keymemberjfsanchez2k28 Nov '08 - 9:49 
I had a problem using Keys that are not exactly compatible with "StepBytes"
 
in method ValidateKeyAndIv()
_crypto.Key = _key.Bytes
 
giving me an error:
"specified key is not valid size for this algorithm".
 
I found a solution:
The property Data.Bytes() validates _maxBytes and _MinBytes, so I added a validation for _stepBytes.
Now it should read like this:
        Public Property Bytes() As Byte()
            Get
                If _MaxBytes > 0 Then
                    If _b.Length > _MaxBytes Then
                        Dim b(_MaxBytes - 1) As Byte
                        Array.Copy(_b, b, b.Length)
                        _b = b
                    End If
                End If
                If _MinBytes > 0 Then
                    If _b.Length < _MinBytes Then
                        Dim b(_MinBytes - 1) As Byte
                        Array.Copy(_b, b, _b.Length)
                        _b = b
                    End If
                End If
                If _StepBytes > 0 Then
                    Dim _stepCheck As Integer = _b.Length Mod Me.StepBytes
                    If _stepCheck > 0 Then
                        Dim b(_b.Length - _stepCheck + _StepBytes - 1) As Byte
                        Array.Copy(_b, b, _b.Length)
                        _b = b
                    End If
                End If
                Return _b
            End Get
            Set(ByVal Value As Byte())
                _b = Value
            End Set
        End Property
 
Thank you for this library.
Generalproblem using the Encryption classmemberHasan Jaffal25 Jun '08 - 0:32 
hello i have a problem
 
i use this code in vb.net 2005 to crypte a file
 
 Dim FileText As String = My.Computer.FileSystem.ReadAllText(Application.StartupPath & "/../../Licence/decrypted.lic")
Dim C As Crypto.Symmetric.Provider = Crypto.Symmetric.Provider.DES
        Dim sym As New Crypto.Symmetric(C)
         sym.Key.Text = "powermap"
 
 Dim encryptedData As Crypto.Data
             encryptedData = sym.Encrypt(New Crypto.Data(FileText))
        
        My.Computer.FileSystem.WriteAllText(Application.StartupPath amp; "/../../Licence/licence.lic", encryptedData.Text, False)
 

and then this code to decrypt it
 
 Dim FileText As String = My.Computer.FileSystem.ReadAllText(Application.StartupPath & "/../../Licence/licence.lic")
 
Dim C As Crypto.Symmetric.Provider = Crypto.Symmetric.Provider.DES
Dim sym As New Crypto.Symmetric(C)
sym.Key.Text = "powermap"
 
Dim decryptedData As Crypto.Data
        Dim encryptedData As New Crypto.Data(FileText)
        Dim sym2 As New Crypto.Symmetric(C)
        sym2.Key.Text = sym.Key.Text
        decryptedData = sym2.Decrypt(encryptedData)
        MsgBox(decryptedData.Text)
 
it gives me an exception, and it says the provided key is invalid
 
" I love deadlines. I like the whooshing sound they make as they fly by. "

GeneralNo decryption for Hashmemberadharbert2 Jun '08 - 9:23 
Am I missing something or was that left out?
 
Andrew D. Harbert

GeneralRe: No decryption for HashmemberJason Barrera5 Jun '08 - 15:08 
There is no "decryption" for a hash. They are in a sort, 1 way encryption.
 
-Jason Barrera

GeneralRe: No decryption for HashmemberCoolVini11 Jun '08 - 22:30 
Hash is somthing like to get a string for example, add make the sum of all the chars. Is not sum, but let say that is somthing like sum.
 
At the end, you try to do that.
Everything that put as input to the hash create function, return a diferent number.
So if for example you have a "password" that create the hash value of "223221", you keep the hash valie, and do not know the word password.
 
Now if some type any other word, then the hash valie is NOT "223221".
But if some type the correct "password" you get the correct hash.
 
So even you, do not know the password, you can verify it.
----------
 
Other think that you can do, is to understand that somthing has change in a compare utility, for example, how you can know very fast and very easy, that some one has really change a text whith out try to compare it char by char ?, you create a hash.
GeneralRe: No decryption for Hashmemberdelyk21 Apr '09 - 8:42 
Sorry, you can’t “dehash” things.
 
Some mathematical functions are not reversible. Modulus (remainder) functions are a good example.
 
If you try to reverse X MOD 9 knowing that it returns a remainder of 1 you will see that many numbers could be used such as, 10,20,30,40, etc.
 
That’s part of the extra security you gain by using Hashing functions.
General?bug in Text property of Data class in case encoding is Unicodememberheryerdeyim18 Apr '08 - 2:13 
Sub Test()
  Dim data as New Data("abc",System.Text.Encoding.Unicode)
  'now data._b is {97,0,98,0,99,0}

  Windows.Forms.MessageBox.Show(data.Text)
  'will not show "abc" because of null handling in Text Property of Data class.
End Sub
 

 
    ''' <summary>
    ''' Sets or returns text representation of bytes using the default text encoding
    ''' </summary>
    Public Property Text() As String
      Get
        If _b Is Nothing Then
          Return ""
        Else
          '-- need to handle nulls here; oddly, C# will happily convert
          '-- nulls into the string whereas VB stops converting at the
          '-- first null!
          Dim i As Integer = Array.IndexOf(_b, CType(0, Byte))
          If i >= 0 Then
            Return Me.Encoding.GetString(_b, 0, i)
          Else
            Return Me.Encoding.GetString(_b)
          End If
        End If
      End Get
      Set(ByVal Value As String)
        _b = Me.Encoding.GetBytes(Value)
      End Set
    End Property

QuestionLicense and terms of use?memberEdwin200831 Mar '08 - 6:00 
Jeff,
 
First of thanks for creating these classes, they have been very usefull within my projects.
 
However I have been using the C# version posted by kalyankrishna1 (member-id 143594) on this message board.
I have maintained all the comments from the VB classes in the C# classes.
 
I have not found any Terms of use or license agreements, so I would like if there are any and what are they?
 
Thanks,
 
Edwin Geveke
Senior Application Architect
Descartes Systems Group
AnswerRe: License and terms of use?memberMember 216504427 Jun '09 - 7:01 
I'd like to know, myself.
 
I plan to include this library in a project that I'm releasing under the BSD license, and I'd like to know if that's acceptable to the author.
QuestionEncryption - Decryption SolutionmemberBill Havens12 Mar '08 - 4:51 
Hello and thank you for the nice job on this article about encryption. I'm a VB.Net developer and I am working on finding a way to do the following but have absolutely no experience with encryption.
 
Test the utilization of a given site key (once password-encrypted):
Step 1: Decrypt the key
Step 2: Decode the key, leaving the resulting values in binary (non-decoded) form.
Step 3: Decode the IV to binary form.
Step 4: Decode the Cipher Text supplied in examples in 6.5.2 below. Cipher Text is Base-64 encoded and must be decoded prior to decrypting.
Step 5: Decrypt the Cipher Text supplied using the values from Steps 1 and 2.
Step 6: The clear text output should match the expected clear text.
 
Can anyone help me with this?
 
Thanks
Cool | :cool:
GeneralThanks to JeffmemberPam Minich6 Mar '08 - 15:37 
The encryption module is a very elegant piece of code and was a godsend on a project where I only needed to encrypt and decrypt credit card numbers. Great work and thanks for making it public!
 
Pam
Generalprobably a very simple errormemberElsys29 Feb '08 - 17:33 
I referenced your code in a dll to a C++ project since I dont have the money to buy the code converter and simply use the header as a classheader. And because I dont really wish to re-learn VB.NET (Bad experiences and it made it alot harder for me to learn C++ dont want to take two steps forward and one back) Anyway so I referenced your dll and I am experiencing three errors which boggle the imagination.
 
class does not have a copy-constructor... it does from what I read of your code and understood but because of this error below.
 
candidate function(s) not accessible
the compiler is unable to access the copy constructor resulting in the first error. I checked through all your methods and functions to be sure the ones I was using and their base functions were declared public as is syntax in C++/CLI
 
A host of conversion problems but since these conversions should work provided the middle error is fixed since the class itself is based on input and output through System.string aka System::String;
 
I hope to hear from you on this issue and I am really looking foward to using your code in my project. It is really well put together just not as optomized for C++ as I would like. I guess if I get really fed up I'll just have to rewrite it though some of the value declarations are impossible to rework the way its written. Thats part of the reason I opted to use a dll reference.
GeneralRe: probably a very simple errormemberMember 364418126 Jun '08 - 4:47 
I experienced the same problems as you did when I tried this DLL in a C++/CLI project.
 
The problem for me seemed to be that C++/CLI didn't like the Optional Boolean parameter in the Symmetric class constructor. I solved it by passing a boolean.
 
For example, this gave me the same errors you had:
Symmetric^ sym = gcnew Symmetric(Symmetric::Provider::Rijndael);
 
but this did work:
Symmetric^ sym = gcnew Symmetric(Symmetric::Provider::Rijndael, true);
 
Hope this helps you!
Questionencryption projectmemberkvsinfotech25 Feb '08 - 19:45 
i would like to design login page which must include encryption coding for password checking.
 
i did coding but how to run the application how to test that .
 
coding :// This sample demonstrates using a key based on the cryptographic service provider (CSP) version
// of the Data Encryption Standard (DES)algorithm to encrypt a string to a byte array, and then
// to decrypt the byte array back to a string.
 
using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;
 
class CryptoMemoryStream
{
// Main method.
public static void Main()
{
// Create a new DES key.
DESCryptoServiceProvider key = new DESCryptoServiceProvider();
 
// Encrypt a string to a byte array.
byte[] buffer = Encrypt("This is some plaintext!", key);
 
// Decrypt the byte array back to a string.
string plaintext = Decrypt(buffer, key);
 
// Display the plaintext value to the console.
Console.WriteLine(plaintext);
}

// Encrypt the string.
public static byte[] Encrypt(string PlainText, SymmetricAlgorithm key)
{
// Create a memory stream.
MemoryStream ms = new MemoryStream();
 
// Create a CryptoStream using the memory stream and the
// CSP DES key.
CryptoStream encStream = new CryptoStream(ms, key.CreateEncryptor(), CryptoStreamMode.Write);
 
// Create a StreamWriter to write a string
// to the stream.
StreamWriter sw = new StreamWriter(encStream);
 
// Write the plaintext to the stream.
sw.WriteLine(PlainText);
 
// Close the StreamWriter and CryptoStream.
sw.Close();
encStream.Close();
 
// Get an array of bytes that represents
// the memory stream.
byte[] buffer = ms.ToArray();
 
// Close the memory stream.
ms.Close();
 
// Return the encrypted byte array.
return buffer;
}
 
// Decrypt the byte array.
public static string Decrypt(byte[] CypherText, SymmetricAlgorithm key)
{
// Create a memory stream to the passed buffer.
MemoryStream ms = new MemoryStream(CypherText);
 
// Create a CryptoStream using the memory stream and the
// CSP DES key.
CryptoStream encStream = new CryptoStream(ms, key.CreateDecryptor(), CryptoStreamMode.Read);
 
// Create a StreamReader for reading the stream.
StreamReader sr = new StreamReader(encStream);
 
// Read the stream as a string.
string val = sr.ReadLine();
 
// Close the streams.
sr.Close();
encStream.Close();
ms.Close();

return val;
}
please guide me how to do that applicaiton . Its great if it could be early .
 
thanks.
Anuradha

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

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 29 Jan 2007
Article Copyright 2005 by wumpus1
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid