views:

516

answers:

5

I am looking for a general string encryption class in .NET. (Not to be confused with the 'SecureString' class.)

I have started to come up with my own class, but thought there must be a .NET class that already allows you to encrypt/decrypt strings of any encoding with any Cryptographic Service Provider.

Public Class SecureString

        Private key() As Byte
        Private iv() As Byte
        Private m_SecureString As String

        Public ReadOnly Property Encrypted() As String
            Get
                Return m_SecureString
            End Get
        End Property

        Public ReadOnly Property Decrypted() As String
            Get
                Return Decrypt(m_SecureString)
            End Get
        End Property

        Public Sub New(ByVal StringToSecure As String)
            If StringToSecure Is Nothing Then StringToSecure = ""
            m_SecureString = Encrypt(StringToSecure)
        End Sub

        Private Function Encrypt(ByVal StringToEncrypt As String) As String

            Dim result As String = ""
            Dim bytes() As Byte = Text.Encoding.UTF8.GetBytes(StringToEncrypt)

            Using provider As New AesCryptoServiceProvider()

                With provider
                    .Mode = CipherMode.CBC                  
                    .GenerateKey()
                    .GenerateIV()
                    key = .Key
                    iv = .IV
                End With

                Using ms As New IO.MemoryStream
                    Using cs As New CryptoStream(ms, provider.CreateEncryptor(), CryptoStreamMode.Write)
                        cs.Write(bytes, 0, bytes.Length)
                        cs.FlushFinalBlock()
                    End Using
                    result = Convert.ToBase64String(ms.ToArray())
                End Using

            End Using

            Return result

        End Function

        Private Function Decrypt(ByVal StringToDecrypt As String) As String

            Dim result As String = ""
            Dim bytes() As Byte = Convert.FromBase64String(StringToDecrypt)

            Using provider As New AesCryptoServiceProvider()

                Using ms As New IO.MemoryStream
                    Using cs As New CryptoStream(ms, provider.CreateDecryptor(key, iv), CryptoStreamMode.Write)
                        cs.Write(bytes, 0, bytes.Length)
                        cs.FlushFinalBlock()
                    End Using
                    result = Text.Encoding.UTF8.GetString(ms.ToArray())
                End Using

            End Using

            Return result

        End Function

    End Class
+3  A: 

The AES algorithm for symmetric encryption is generally the way to go for generic encryption of strings. However, I'm afraid that the .NET BCL doesn't simplify things any further for you the providing the basic encryption/decryption classes and functions.

You can find a good example of how to use the crypographic classes specifically for string encryption on this page. It appears to be very complete and well commented indeed - you may even find that you can use it without any further modifications. Note: Rijndael is the same algorithm as AES. (Technically, the former refers to the algorithm's real name, and the latter the Advanced Encryption Standard.)

Noldorin
@Noldorin - Thanks for the link! Is there any generic function that I can pass a string of any encoding and use any of the Cryptographic Service Providers?
@cryptospin: No problem. Just realised I slightly misunderstood your original question. I've just updated the post with a bit more info, anyway. There's definitely no helper class/methods in the .NET framework to do this for you I'm afraid, though the code on the linked page should provide you with a good starting point. A nice way to go about it might be to use extension methods here.
Noldorin
+2  A: 

If you are trying to achieve the same goal as .NET's SecureString, then your example really doesn't solve the problem. (I could be misunderstanding your goals, in which case I apologize.)

The idea of .NET's SecureString is that it stores the string data encrypted in a non-managed chunk of memory, is immutable once created, and can not be read in .NET using a normal string variable. This protects the string from anyone trying to probe your memory space (i.e. malware, worm, Trojan, whatever), and must be explicitly cleaned up by you. The reasons for this involve how .NET treats strings, and the fact that data in memory is only cleaned up at the whim of the GC.

Even though your SecureString class encrypts the string into a private variable, the original string that was passed in is still insecure. It can also stick around for a while before the GC collects it, or, if that string was interned, it will live for the duration of the process it resides within. Interned strings are stored in a table, which makes them easier to find, too.

On the other side of things...if you Decrypt your SecureString, your getting a new string variable that could run into the same problems as the input string...it is only cleaned up when the GC decides to...and it also may end up interned and live for the duration of the process.

To compound problems, every time you Decrypt, you are getting another copy of your encrypted string. This could build up a surplus of decrypted versions of your secure string, increasing the chances that some piece of malware that is probing for, say, credit card numbers...will actually find one.

I have tried many times to create a better, more .NET like version of .NET 2.0's SecureString, but have never been able to produce something that is truly secure. You could get a pointer to the string variable that was decrypted, wipe it, set each character to nil, etc. However this could be very problematic in the even that something is still referencing that string, causing disappearing text, corrupted reads, etc. If the string is interned, which generally means it is being used by many things for a long duration of time, wiping it wipes the only version, and affects all use of it. Even if you managed to successfully wipe a copy of your secure string, there is no guarantee that it wasn't copied by other code before you wiped it (i.e. you send your string off to some web service...it now lives in more than one process space, quite possibly in different physical locations around the world.)

Its definitely a complicated issue, and only really provides security in the event that your application's memory space has been compromised by malware of some sort.

jrista
Thanks for taking the time to post. If you read the OP I do explicitly state "(Not to be confused with the 'SecureString' class.)"
A: 

Here is a class with two methods for encrypting and decrypting byte array

Check http://stackoverflow.com/questions/472906/net-string-to-byte-array-c how to convert string into byte array and back

public static class Encryptor 
{
    public static byte[] Encrypt(byte[] data, string key) {
        var stream = new MemoryStream();
        var cryptic = new DESCryptoServiceProvider {
            Key = Encoding.ASCII.GetBytes(key),
            IV = Encoding.ASCII.GetBytes(key)
        };
        var crStream = new CryptoStream(stream, cryptic.CreateEncryptor(), CryptoStreamMode.Write);

        crStream.Write(data, 0, data.Length);
        crStream.FlushFinalBlock();
        return stream.ToArray();
    }

    public static byte[] Decrypt(byte[] data, string key) {
        var stream = new MemoryStream();
        stream.Write(data, 0, data.Length);
        stream.Position = 0;
        var cryptic = new DESCryptoServiceProvider {
            Key = Encoding.ASCII.GetBytes(key),
            IV = Encoding.ASCII.GetBytes(key)
        };
        var crStream = new CryptoStream(stream, cryptic.CreateDecryptor(), CryptoStreamMode.Read);
        var plainTextBytes = new byte[data.Length];
        int decryptedByteCount = crStream.Read(plainTextBytes, 0, plainTextBytes.Length);
        var result = new byte[decryptedByteCount];
        for (int i=0; i < decryptedByteCount; i++)
            result[i] = plainTextBytes[i];
        return result;
    }
}
Maksym Kozlenko