Encrypt and Decrypt in C#

G

Guest

Hi,

Is there Buid-In fuction in C# that Encrypt and Decrypt strings?
i have a textbox which i'm writing into file, and i want to encrypt it
before writing, i'm not looking for something fancy, just for a simple
Encryption and Decryption function.

thanks,
Gidi.
 
N

Nicholas Paldino [.NET/C# MVP]

Gidi,

Take a look at the classes in the System.Security.Cryptography
namespace. There are a number of encyrption algorithm implementations there
that you can use.

Hope this helps.
 
G

Guest

Thanks Brendan,

I tried this example, and i had problems running it, so i can't really know
how it works...
 
J

Jon Skeet [C# MVP]

Gidi said:
Is there Buid-In fuction in C# that Encrypt and Decrypt strings?
i have a textbox which i'm writing into file, and i want to encrypt it
before writing, i'm not looking for something fancy, just for a simple
Encryption and Decryption function.

Encryption and decryption typically work on binary data, not text, and
the .NET libraries are no exception. Look at the CryptoStream class,
and convert your text to/from binary data using the Encoding class.
 
S

SP

Gidi said:
Hi,

Is there Buid-In fuction in C# that Encrypt and Decrypt strings?
i have a textbox which i'm writing into file, and i want to encrypt it
before writing, i'm not looking for something fancy, just for a simple
Encryption and Decryption function.

Try the following:
public static string Decrypt(string encrypted)

{

byte[] data = System.Convert.FromBase64String(encrypted);

byte[] rgbKey = System.Text.ASCIIEncoding.ASCII.GetBytes("12121212");

byte[] rgbIV = System.Text.ASCIIEncoding.ASCII.GetBytes("34343434");

MemoryStream memoryStream = new MemoryStream(data.Length);

DESCryptoServiceProvider desCryptoServiceProvider = new
DESCryptoServiceProvider();

CryptoStream cryptoStream = new CryptoStream(memoryStream,
desCryptoServiceProvider.CreateDecryptor(rgbKey, rgbIV),
CryptoStreamMode.Read);

memoryStream.Write(data, 0, data.Length);

memoryStream.Position = 0;

string decrypted = new StreamReader(cryptoStream).ReadToEnd();

cryptoStream.Close();

return decrypted;

}

public static string Encrypt(string decrypted)

{

byte[] data = System.Text.ASCIIEncoding.ASCII.GetBytes(decrypted);

byte[] rgbKey = System.Text.ASCIIEncoding.ASCII.GetBytes("12121212");

byte[] rgbIV = System.Text.ASCIIEncoding.ASCII.GetBytes("34343434");

MemoryStream memoryStream = new MemoryStream(1024);

DESCryptoServiceProvider desCryptoServiceProvider = new
DESCryptoServiceProvider();

CryptoStream cryptoStream = new CryptoStream(memoryStream,
desCryptoServiceProvider.CreateEncryptor(rgbKey, rgbIV),
CryptoStreamMode.Write);

cryptoStream.Write(data, 0, data.Length);

cryptoStream.FlushFinalBlock();

byte[] result = new byte[(int)memoryStream.Position];

memoryStream.Position = 0;

memoryStream.Read(result, 0, result.Length);

cryptoStream.Close();

return System.Convert.ToBase64String(result);

}

HTH



SP
 
H

Helge Jensen

Find one at the bottom. The "MyChoiceOf..." functions reflect more or
less arbitrary choices which I have made for the test -- the choices
taken should be sufficient for most applications.

Note that a more proper use of IV would be to generate it randomly and
include the IV in clear in the encrypted text.

Beware that cryptography is really hard to get right and the sligtest
error often results in a complete compromise of the data thought to be
protected.
Try the following:

There are several things I am not too happy about in that code:

- It uses DES-encryption
- It is designed with the keys in the code
- It uses a constant IV
- It doesn't come with a test (I know, that's a cheap-shot ;)
- It converts data, to and from Base64
- It duplicates the code for creating the en/de-cryption keys
- It only works for strings with a valid ASCII-encoding
- It only works for keys with a valid ASCII-encoding
- It uses the ascii-encoding of key-strings as keys
- It uses a MemoryStream where it's not required

Here is my shot at how to do it. note that it copies the IV and
encrypted-string into a new byte[]. If you are reading/writing to a
stream you can remove that, but you explicitly requested simplicity and
the interface would be much more complicated if the cipher-text and IV
is returned/passed seperatly.

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

class CryptExample
{
public static void InitializeAlgorithm(string secret, HashAlgorithm h,
SymmetricAlgorithm a)
{
byte[] b = System.Text.Encoding.UTF8.GetBytes(secret);
h.TransformFinalBlock(b, 0, b.Length);
byte[] secret_hashed = h.Hash;
byte[] key = new byte[a.KeySize/8];
System.Array.Copy(secret_hashed, 0, key, 0, key.Length);
a.Key = key;
}
public static byte[] Encrypt(string s, SymmetricAlgorithm a)
{
byte[] b = Encoding.UTF8.GetBytes(s);
a.GenerateIV();
byte[] iv = a.IV;
byte[] enc;
using ( ICryptoTransform c = a.CreateEncryptor() )
enc = c.TransformFinalBlock(b, 0, b.Length);
byte[] all = new byte[iv.Length+enc.Length];
System.Array.Copy(iv, 0, all, 0, iv.Length);
System.Array.Copy(enc, 0, all, iv.Length, enc.Length);
return all;
}
public static string Decrypt(byte[] bytes, int offset, int length,
SymmetricAlgorithm a)
{
byte[] iv = new byte[a.BlockSize/8];
System.Array.Copy(bytes, offset, iv, 0, iv.Length);
a.IV = iv;
using ( ICryptoTransform c = a.CreateDecryptor() )
return Encoding.UTF8.GetString(c.TransformFinalBlock(bytes, offset
+ iv.Length, length - iv.Length));
}
public static SymmetricAlgorithm MyChoiceOfEncryptionAlgo()
{
SymmetricAlgorithm alg = Rijndael.Create();
alg.Mode = CipherMode.CBC;
alg.Padding = PaddingMode.PKCS7;
alg.KeySize = 256;
return alg;
}
public static HashAlgorithm MyChoiceOfHashAlgo() { return
SHA512.Create(); }
public static void Main()
{
string secret = "password";
SymmetricAlgorithm enc_algo = MyChoiceOfEncryptionAlgo();
SymmetricAlgorithm dec_algo = MyChoiceOfEncryptionAlgo();

InitializeAlgorithm(secret, MyChoiceOfHashAlgo(), enc_algo);
InitializeAlgorithm(secret, MyChoiceOfHashAlgo(), dec_algo);

for ( int i = 0; i < 1000000; i = (3*i + 1) )
{
string msg = new string('a', i);
byte[] enc = Encrypt(msg, enc_algo);
string dec = Decrypt(enc, 0, enc.Length, dec_algo);
if ( msg != dec )
throw new CryptographicException(string.Format("Plain and
decrypted did not match: {0}!={1}", msg, dec));
}
}
}
 
S

SP

Helge Jensen said:
Find one at the bottom. The "MyChoiceOf..." functions reflect more or
less arbitrary choices which I have made for the test -- the choices
taken should be sufficient for most applications.

Note that a more proper use of IV would be to generate it randomly and
include the IV in clear in the encrypted text.

Beware that cryptography is really hard to get right and the sligtest
error often results in a complete compromise of the data thought to be
protected.


There are several things I am not too happy about in that code:

It was one of those things that once it worked and it was being used then I
did not want to change it. You make some valid points and I do have some
comments and questions inline.
- It uses DES-encryption

Can you explain why DES is not the best choice.
- It is designed with the keys in the code

How can you decrypt without the keys in your code somewhere. I place the
keys in one place and they are encrypted by an obfuscator. How do you avoid
placing the keys in your code?
- It uses a constant IV

Is it better to use an encrypted and unknown IV or a random but known IV?
You suggested above to use a random IV and store it in clear text.
- It doesn't come with a test (I know, that's a cheap-shot ;)

I did not provide the unit tests. They are in a separate class. Of course it
is easy to test.
- It converts data, to and from Base64

Originally it was to be a license key so it may of needed to be typed in.
- It duplicates the code for creating the en/de-cryption keys

Because I do not provide the Encrypt function in the Release build, only the
Decrypt.
- It only works for strings with a valid ASCII-encoding
- It only works for keys with a valid ASCII-encoding
- It uses the ascii-encoding of key-strings as keys

I knew that the text going in was ASCII but do not want to change anything
at this point.
- It uses a MemoryStream where it's not required

I thought the same at the time. I will look at your code to see how to
eliminate the MemoryStream.

Regards

SP.
Here is my shot at how to do it. note that it copies the IV and
encrypted-string into a new byte[]. If you are reading/writing to a
stream you can remove that, but you explicitly requested simplicity and
the interface would be much more complicated if the cipher-text and IV
is returned/passed seperatly.

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

class CryptExample
{
public static void InitializeAlgorithm(string secret, HashAlgorithm h,
SymmetricAlgorithm a)
{
byte[] b = System.Text.Encoding.UTF8.GetBytes(secret);
h.TransformFinalBlock(b, 0, b.Length);
byte[] secret_hashed = h.Hash;
byte[] key = new byte[a.KeySize/8];
System.Array.Copy(secret_hashed, 0, key, 0, key.Length);
a.Key = key;
}
public static byte[] Encrypt(string s, SymmetricAlgorithm a)
{
byte[] b = Encoding.UTF8.GetBytes(s);
a.GenerateIV();
byte[] iv = a.IV;
byte[] enc;
using ( ICryptoTransform c = a.CreateEncryptor() )
enc = c.TransformFinalBlock(b, 0, b.Length);
byte[] all = new byte[iv.Length+enc.Length];
System.Array.Copy(iv, 0, all, 0, iv.Length);
System.Array.Copy(enc, 0, all, iv.Length, enc.Length);
return all;
}
public static string Decrypt(byte[] bytes, int offset, int length,
SymmetricAlgorithm a)
{
byte[] iv = new byte[a.BlockSize/8];
System.Array.Copy(bytes, offset, iv, 0, iv.Length);
a.IV = iv;
using ( ICryptoTransform c = a.CreateDecryptor() )
return Encoding.UTF8.GetString(c.TransformFinalBlock(bytes, offset
+ iv.Length, length - iv.Length));
}
public static SymmetricAlgorithm MyChoiceOfEncryptionAlgo()
{
SymmetricAlgorithm alg = Rijndael.Create();
alg.Mode = CipherMode.CBC;
alg.Padding = PaddingMode.PKCS7;
alg.KeySize = 256;
return alg;
}
public static HashAlgorithm MyChoiceOfHashAlgo() { return
SHA512.Create(); }
public static void Main()
{
string secret = "password";
SymmetricAlgorithm enc_algo = MyChoiceOfEncryptionAlgo();
SymmetricAlgorithm dec_algo = MyChoiceOfEncryptionAlgo();

InitializeAlgorithm(secret, MyChoiceOfHashAlgo(), enc_algo);
InitializeAlgorithm(secret, MyChoiceOfHashAlgo(), dec_algo);

for ( int i = 0; i < 1000000; i = (3*i + 1) )
{
string msg = new string('a', i);
byte[] enc = Encrypt(msg, enc_algo);
string dec = Decrypt(enc, 0, enc.Length, dec_algo);
if ( msg != dec )
throw new CryptographicException(string.Format("Plain and
decrypted did not match: {0}!={1}", msg, dec));
}
}
}


--
Helge Jensen
mailto:[email protected]
sip:[email protected]
-=> Sebastian cover-music: http://ungdomshus.nu <=-
 
H

Helge Jensen

SP said:
It was one of those things that once it worked and it was being used then I
did not want to change it. You make some valid points and I do have some
comments and questions inline.

It wasn't that bad, it was just that when I got started looking at the
code more and more things kept drawing my attention...
Can you explain why DES is not the best choice.

DES is not "secure". it's keys are 56-bits, modern CPU's can brute force
DES faster than you can change the keys, custom hardware can do it in
minutes. Rinjdael (now AES) have longer key-lengths and generally
considered much more resistant to attacks.
How can you decrypt without the keys in your code somewhere. I place the
keys in one place and they are encrypted by an obfuscator. How do you avoid
placing the keys in your code?

The keys were actually duplicated, as the strings "1234...".

To avoid having the keys in the code, either prompt for them, have them
on disk or use any other means of input. Even if you know them to be
constant, have them in a file or something, so you can provide different
keys to different people.

BTW: an obfuscator will not really help against any, even just slightly,
qualified attacker.
Is it better to use an encrypted and unknown IV or a random but known IV?
You suggested above to use a random IV and store it in clear text.

The IV isn't secret, it's used to seed the encryption. No secrecy is
lost by transferring it it clear-text, nor is any secrecy gained by
obscuring it or "encrypting" it.

Choosing a random IV gives you non-deterministic cryptography -- that
is, multiple encryptions of the same clear is encrypted to different
cipher-texts.
I did not provide the unit tests. They are in a separate class. Of course it
is easy to test.

Good, cryptographic code should almost always be unit-tested, it's
really hard to debug by inspecting the encrypted data ;)
Originally it was to be a license key so it may of needed to be typed in.

En/De-cryption should be a separate concen from what format the
input-data is in. If you need to Base64 convert somewhere, just do it on
the in/output of the de/en-cryption.
Because I do not provide the Encrypt function in the Release build, only the
Decrypt.

That doesn't prevent you from having a separate function for creating
the en/de-cryption keys. (http://c2.com/cgi/wiki?OnceAndOnlyOnce)
I knew that the text going in was ASCII but do not want to change anything
at this point.

Fine, note that valud ASCII-text is encoded exactly the same in ASCII
and UTF8.

Using the ascii-encoding of key-strings directly as keys is frowned upon
since at dramatically reduces the used keyspace. Hashing the keys
removes this problem.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top