Really simple encryption with C# and SymmetricAlgorithm

95,940

Solution 1

If you don't want to handle keys yourself then let the operating system do it for your. E.g. use Windows Data Protection (DPAPI).

You can write your own, string-based, version of System.Security.Cryptography.ProtectedData.Protect and Unprotect methods by using something like:

public static string Crypt (this string text)
{
    return Convert.ToBase64String (
        ProtectedData.Protect (
            Encoding.Unicode.GetBytes (text) ) );
}

public static string Decrypt (this string text)
{
    return Encoding.Unicode.GetString (
        ProtectedData.Unprotect (
             Convert.FromBase64String (text) ) );
}

Solution 2

How about something like this?

Code

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

public static class StringUtil
{
    private static byte[] key = new byte[8] {1, 2, 3, 4, 5, 6, 7, 8};
    private static byte[] iv = new byte[8] {1, 2, 3, 4, 5, 6, 7, 8};

    public static string Crypt(this string text)
    {
        SymmetricAlgorithm algorithm = DES.Create();
        ICryptoTransform transform = algorithm.CreateEncryptor(key, iv);
        byte[] inputbuffer = Encoding.Unicode.GetBytes(text);
        byte[] outputBuffer = transform.TransformFinalBlock(inputbuffer, 0, inputbuffer.Length);
        return Convert.ToBase64String(outputBuffer);
    }

    public static string Decrypt(this string text)
    {
        SymmetricAlgorithm algorithm = DES.Create();
        ICryptoTransform transform = algorithm.CreateDecryptor(key, iv);
        byte[] inputbuffer = Convert.FromBase64String(text);
        byte[] outputBuffer = transform.TransformFinalBlock(inputbuffer, 0, inputbuffer.Length);
        return Encoding.Unicode.GetString(outputBuffer);
    }
}

Unit Test

[Test]
public void Test()
{
    string expected = "this is my test string";
    string a = expected.Crypt();
    Debug.WriteLine(a);
    string actual = a.Decrypt();
    Assert.AreEqual(expected, actual);
}

EDIT:

To clarify: I am aware this is not good practice.

"I'm aware of the risks of this approach. "

Iv'e made the assumption that the OP is also aware and will make relevant code changes before considering using anything like this in a production environment.

The question emphasizes simplicity over good practice.

Solution 3

You'll need to set the cipher mode to CipherMode.ECB or use an IV.

SymmetricAlgorithm symmetricAlgorithm = DES.Create();
symmetricAlgorithm.Key = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };
symmetricAlgorithm.Mode = CipherMode.ECB;
...

Another point is not to use Unicode encoding. Use Base64 instead. Unicode might "destroy" bytes that are not UTF-16.

Share:
95,940
Ignacio Soler Garcia
Author by

Ignacio Soler Garcia

I am now acting as a delivery manager focused on the three main pillars of software creation: People, Procedures and Code working mainly with Javascript teams (React / Redux / Node) building applications 100% in the cloud with CI/CD, etc. I am open to proposals, let's talk. Previously I used to be an experienced technical leader commanding .Net technologies, passionate about Agile methodologies and a people person.

Updated on March 24, 2021

Comments

  • Ignacio Soler Garcia
    Ignacio Soler Garcia about 3 years

    I'm looking for a very simple crypt / decrypt method. I will be using always the same static key. I'm aware of the risks of this approach. Currently I'm using the following code but it does not generate the same result after crypting and decripting the same string (there is some garbage in the middle of the string).

    public static string Crypt(this string text)
    {
        string result = null;
    
        if (!String.IsNullOrEmpty(text))
        {
            byte[] plaintextBytes = Encoding.Unicode.GetBytes(text);
    
            SymmetricAlgorithm symmetricAlgorithm = DES.Create();
            symmetricAlgorithm.Key = new byte[8] {1, 2, 3, 4, 5, 6, 7, 8};
            using (MemoryStream memoryStream = new MemoryStream())
            {
                using (CryptoStream cryptoStream = new CryptoStream(memoryStream, symmetricAlgorithm.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    cryptoStream.Write(plaintextBytes, 0, plaintextBytes.Length);
                }
    
                result = Encoding.Unicode.GetString(memoryStream.ToArray());
            }
        }
    
        return result;
    }
    
    public static string Decrypt(this string text)
    {
        string result = null;
    
        if (!String.IsNullOrEmpty(text))
        {
            byte[] encryptedBytes = Encoding.Unicode.GetBytes(text);
    
            SymmetricAlgorithm symmetricAlgorithm = DES.Create();
            symmetricAlgorithm.Key = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
            using (MemoryStream memoryStream = new MemoryStream(encryptedBytes))
            {
                using (CryptoStream cryptoStream = new CryptoStream(memoryStream, symmetricAlgorithm.CreateDecryptor(), CryptoStreamMode.Read))
                {
                    byte[] decryptedBytes = new byte[encryptedBytes.Length];
                    cryptoStream.Read(decryptedBytes, 0, decryptedBytes.Length);
                    result = Encoding.Unicode.GetString(decryptedBytes);
                }
            }
        }
    
        return result;
    }
    

    I can change whatever is needed, no limits (but I want just to have on method to crypt and another one to decrypt without sharing variables between them).

    Thanks.

  • Ignacio Soler Garcia
    Ignacio Soler Garcia over 12 years
    Anyway I get the beggining of the string corrupted.
  • Jon Hanna
    Jon Hanna over 12 years
    +1. An alternative can be to just return (and then use) the raw bytes rather than a string, but either way the problem is that Encoding.Unicode.GetString is going to catch and "fix" cases where the encrypted bytes aren't valid UTF-16, which ruins the plan.
  • Ignacio Soler Garcia
    Ignacio Soler Garcia over 12 years
    Greeeeeeeat. Now it works, thanks! (It's hard when you have to work with things that you don't understand and you don't want to understand ;) thanks again.
  • CodesInChaos
    CodesInChaos over 12 years
    IV should be random and stored with the message.
  • Sani Singh Huttunen
    Sani Singh Huttunen over 12 years
    @CodeInChaos: Nothing wrong with using ECB. It all depends on the context. To solve his/her problem the necessary steps to take is what I described in my answer, ECB or IV. Though I'd never use ECB myself, using ECB is one of the possible solutions.
  • Jonathan DeMarks
    Jonathan DeMarks over 11 years
    Be careful with this, you can't decrypt the encrpyted string on any other computer or even with a different profile on the same machine. Only good for storing things very locally.
  • JARRRRG
    JARRRRG almost 10 years
    Served it's purpose for my little project just fine, thanks :)
  • Ryan Griffith
    Ryan Griffith almost 10 years
    @JonathanDeMarks, The latest version of the base class libraries DO allow this to be encrypted/decrypted by both CurrentUser as well as LocalMachine. The signature for the encrypt is as follows: public static byte[] Protect (byte[] userData, byte[] optionalEntropy, DataProtectionScope scope) where scope can be DataProtectionScope.CurrentUser or DataProtectionScope.LocalMachine
  • Toolkit
    Toolkit over 9 years
    he is saying "I will be using always the same static key". And you are offering something that will get him into trouble
  • TheVillageIdiot
    TheVillageIdiot over 7 years
    @JonathanDeMarks thanks for killing the joy of finding simple method...
  • Tomáš Kratochvíla
    Tomáš Kratochvíla over 5 years
    The Protect and Unprotect do not allow single argument. Therefore, I had to use, for example: ProtectedData.Protect(Encoding.Unicode.GetBytes(text),null,D‌​ataProtectionScope.C‌​urrentUser) and ProtectedData.Unprotect(Convert.FromBase64String(text), null, DataProtectionScope.CurrentUser)
  • Bruno Soares
    Bruno Soares over 5 years
    Remember do add a reference to System.Security.dll in your project.
  • user1034912
    user1034912 almost 4 years
    This just throws an error "System.Security.Cryptography.CryptographicException: Bad Data."
  • Toolkit
    Toolkit about 3 years
    what changes do I need to do to make it production worthy?