1

I would like to encrypt a short textbox or string (not a file) in my program to render its contents for human unreadable or encrypt it with simple encryption that it is safe (like any sensitive passwords etc.). In Visual Basic were easy five-liners to do this which aren't working in my C# when I copy it there. I could not find something appropriate. There are only very difficult examples out with huge amount of code needed which mostly throws a lot of errors and requires yourself setting up any complex keys or key pairs or hashes, utf encodings or both to make it working and it just never does. I have no clue of all that and I need just a simple function which works both ways for encryption. Could not find anything like that for C# which is really working without errors and does the Job forward and also backward. In VB encrypted me the XOR function which isn't existing in C#.

Or how would I get that code sample below working, it is the most promising one: it gives me many errors if I copy it in my C# in the button1_click event:

Error 1: Type or Namespace Definition or end-the-file expected

Error 2: The type or Namespace "TripleDESCryptoServiceProvider" could not be found

Error 3: "CipherMode" does not exist in the current context

Error 4: "Getkey" does not exist in the current context

Error 5: "PaddingMode" does not exist in the current context Error 6: Error 8 The type or namespace name 'ICryptoTransform' could not be found (are you missing a using directive or an essemble reference?)

public static string Encrypt(string data)
{
    TripleDESCryptoServiceProvider DES = new TripleDESCryptoServiceProvider();

    DES.Mode = CipherMode.ECB;
    DES.Key = GetKey("a1!B78s!5(");

    DES.Padding = PaddingMode.PKCS7;
    ICryptoTransform DESEncrypt = DES.CreateEncryptor();
    Byte[] Buffer = ASCIIEncoding.ASCII.GetBytes(data);

    return Convert.ToBase64String(DESEncrypt.TransformFinalBlock(Buffer, 0, Buffer.Length));
}

public static string Decrypt(string data)
{
    TripleDESCryptoServiceProvider DES = new TripleDESCryptoServiceProvider();

    DES.Mode = CipherMode.ECB;
    DES.Key = GetKey("a1!B78s!5(");

    DES.Padding = PaddingMode.PKCS7;
    ICryptoTransform DESEncrypt = DES.CreateDecryptor();
    Byte[] Buffer = Convert.FromBase64String(data.Replace(" ","+"));

    return Encoding.UTF8.GetString(DESEncrypt.TransformFinalBlock(Buffer, 0, Buffer.Length));
}
feedwall
  • 1,473
  • 7
  • 28
  • 48
  • Your title and your body do not quite match. Do you want the string encrypted or merely rendered unreadable? The two goals are not necessarily mutually exclusive, but one is much simpler than the other. – Jesse C. Slicer Jun 13 '13 at 15:52
  • 2
    It sounds like you are saying that you implemented your own encryption. That is something that is extremely difficult to do right, so it is not something you should be doing in any real application. – Tim B Jun 13 '13 at 15:54
  • After trying to read your question I'm thinking, you could just retype the context of the text box yourself, it should make it unreadable by others. – Jodrell Jun 13 '13 at 15:55
  • possible duplicate of [Simple obfuscation of string in .NET?](http://stackoverflow.com/questions/13025949/simple-obfuscation-of-string-in-net) – Jodrell Jun 13 '13 at 15:58
  • In the updated post with code, what is the implementation of `GetKey()`? – Jesse C. Slicer Jun 13 '13 at 16:00
  • 4
    @AndréNeves: Actually XORing the key with the plaintext is *unbreakable* encryption provided that (1) the key is crypto-strength random, (2) the key is secret, (3) the key is as long as the message being encrypted, and (4) the key is used *only once*. If all four conditions are met then this is provably unbreakable. If any of those four conditions are not met then as Michael Howards says, you haven't got encryption, you've got encraption; it is trivially breakable. – Eric Lippert Jun 13 '13 at 16:15
  • Ok, now the simple errors in your code you list are due to missing namespace imports (mostly). put `using System.Cryptography` at the top of the source file. However, `GetKey` is yours. Or whoever you got the code from. It's not from the framework. – Jesse C. Slicer Jun 13 '13 at 16:15
  • You should consider using AES instead of 3DES. @EricLippert encraption! LOL – Kevin Jun 13 '13 at 16:30
  • Do you want to encrypt data singularly for the entire application (eg just to mask passwords stored within the exe), per installation (for settings) or per user (for user data)? – bendataclear Jun 13 '13 at 16:33

6 Answers6

1

If all you are really trying to do is mask the contents of a text input box.. In Windows Forms use the TextBox control and set the PasswordChar property to a character. In WPF, use the PasswordBox and optionally set the PasswordChar property to a character.

If you really need encryption, don't look for shortcuts (implementing it yourself, hardcoding passwords or keys) as you will end up with something that looks secure, but really can be hacked in minutes by someone who knows what they are doing.

Tim B
  • 2,340
  • 15
  • 21
  • 2
    If this is a distributed executable, they have all the code to decrypt and extract anyway (http://stackoverflow.com/questions/17069052/encryption-key-protection-in-c-sharp/17071150#17071150). – Jesse C. Slicer Jun 13 '13 at 16:11
  • @feedwall you could look at code stenography http://www.codeproject.com/Articles/6650/Steganography-VII-Hiding-more-Text-in-NET-Assembli – Jodrell Jun 13 '13 at 16:17
  • You can't hide data in your executable using .NET. Your algorithm and/or key/password can be easily decompiled. – Tim B Jun 13 '13 at 17:04
  • Any executable can be decompiled, including Visual Studio, but the results may not be easy to understand. When you decompile a .NET assembly, you can actually get source code which looks nearly identical to the original code (check out http://ilspy.net/). You can use obfuscation (http://www.preemptive.com/products/dotfuscator) to make the decompiled code much more difficult to understand, but a hacker could probably still find your encryption key quite easily. – Tim B Jun 13 '13 at 17:38
  • Depending on the circumstances, it may be illegal in some parts of the world, but laws won't stop a criminal. – Tim B Jun 13 '13 at 20:38
1

Here, your methods will now work as such:

public static string Encrypt(string data)
{
    using (var des = new TripleDESCryptoServiceProvider { Mode = CipherMode.ECB, Key = GetKey("a1!B78s!5(j$S1c%"), Padding = PaddingMode.PKCS7 })
    using (var desEncrypt = des.CreateEncryptor())
    {
        var buffer = Encoding.UTF8.GetBytes(data);

        return Convert.ToBase64String(desEncrypt.TransformFinalBlock(buffer, 0, buffer.Length));
    }
}

public static string Decrypt(string data)
{
    using (var des = new TripleDESCryptoServiceProvider { Mode = CipherMode.ECB, Key = GetKey("a1!B78s!5(j$S1c%"), Padding = PaddingMode.PKCS7 })
    using (var desEncrypt = des.CreateDecryptor())
    {
        var buffer = Convert.FromBase64String(data.Replace(" ", "+"));

        return Encoding.UTF8.GetString(desEncrypt.TransformFinalBlock(buffer, 0, buffer.Length));
    }
}

The problems were A) invalid key length (I'm guessing due to lack of GetKey() definition - but 16 characters by 8 bits per character is the minimum 128 bits for Triple DES) and B) Getting the bytes of the source string as ASCII for encryption, but after decryption, using UTF8 encoding.

Jesse C. Slicer
  • 19,901
  • 3
  • 68
  • 87
1

In addition to my answer in the linked question, you could do somthing like,

public static string Obfuscate(string before)
{
    var beforeArray = Encoding.Unicode.GetBytes(before);
    var count = beforeArray.Length;
    var resultArray = new byte[count];
    var o = count % 32;

    for (var i = 0; i < count; i++)
    {
       var xor = o + 32;
       resultArray[i] = (byte)(beforeArray[i] ^ xor);
       o = ++o % 32;
    }

    return Encoding.Unicode.GetString(resultArray)
}

Its a trivial XOR of the bytes in the string. Its not encryption but it makes the string hard for a human to read.

If you really want strong encryption you'll have to start by avoiding TDES.

Jodrell
  • 34,946
  • 5
  • 87
  • 124
1

Complementing the accepted answer from Jesse C. Slicer, here is the "GetKey" code, I found it here

  private static byte[] GetKey(string password)
  {
     string pwd = null;

     if (Encoding.UTF8.GetByteCount(password) < 24)
     {
         pwd = password.PadRight(24, ' ');
     }
     else
     {
         pwd = password.Substring(0, 24);
     }
     return Encoding.UTF8.GetBytes(pwd);
  }
0

Better yet... use AES instead of 3DES. For an explanation of why you can see here in another SO answer.

Below are some Encrypt / Decrypt methods I use. The input and output are base64Strings.

static string EncryptStringToBase64String(string plainText, byte[] Key, byte[] IV)
{
    // Check arguments. 
    if (plainText == null || plainText.Length <= 0)
        throw new ArgumentNullException("plainText");
    if (Key == null || Key.Length <= 0)
        throw new ArgumentNullException("Key");
    if (IV == null || IV.Length <= 0)
        throw new ArgumentNullException("Key");
    byte[] encrypted;
    // Create an RijndaelManaged object 
    // with the specified key and IV. 
    using (RijndaelManaged rijAlg = new RijndaelManaged())
    {
        rijAlg.Key = Key;
        rijAlg.IV = IV;

        // Create a decrytor to perform the stream transform.
        ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);

        // Create the streams used for encryption. 
        using (MemoryStream msEncrypt = new MemoryStream())
        {
            using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
            {
                using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                {
                    //Write all data to the stream.
                    swEncrypt.Write(plainText);
                }
                encrypted = msEncrypt.ToArray();
            }
        }
    }

    // return encrypted bytes converted to Base64String
    return Convert.ToBase64String(encrypted);
}

static string DecryptStringFromBase64String(string cipherText, byte[] Key, byte[] IV)
{
    // Check arguments. 
    if (cipherText == null || cipherText.Length <= 0)
        throw new ArgumentNullException("cipherText");
    if (Key == null || Key.Length <= 0)
        throw new ArgumentNullException("Key");
    if (IV == null || IV.Length <= 0)
        throw new ArgumentNullException("Key");

    // Declare the string used to hold 
    // the decrypted text. 
    string plaintext = null;

    // Create an RijndaelManaged object 
    // with the specified key and IV. 
    using (RijndaelManaged rijAlg = new RijndaelManaged())
    {
        rijAlg.Key = Key;
        rijAlg.IV = IV;

        // Create a decrytor to perform the stream transform.
        ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);

        // Create the streams used for decryption. 
        using (MemoryStream msDecrypt = new MemoryStream(Convert.FromBase64String(cipherText)))
        {
            using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
            {
                using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                {
                    // Read the decrypted bytes from the decrypting stream 
                    // and place them in a string.
                    plaintext = srDecrypt.ReadToEnd();
                }
            }
        }
    }

    return plaintext;
}

Here is some test code since I see you create your Key / IV inside your encrypt / decrypt.

    var inputString = "SomeText";
    var r = RijndaelManaged.Create();
    r.GenerateKey();
    r.GenerateIV();
    var key = r.Key;
    var iv = r.IV;

    var a = EncryptStringToBase64String(inputString, key, iv);
    var b = DecryptStringFromBase64String(a, key, iv);
    Assert.AreEqual(b, inputString);
    Assert.AreNotEqual(a, inputString);
Community
  • 1
  • 1
Kevin
  • 4,586
  • 23
  • 35
  • MemoryStream and StreamReader are in System.IO. You send your input to EncryptStringToBase64String and get your output from DecryptStringFromBase64String. – Kevin Jun 13 '13 at 18:47
0

using System.Security.Cryptography; ;

public class StringCipher
{

    private const int keysize = 256;

    public static string Encrypt(string plainText)
    {
        byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
        using (PasswordDeriveBytes password = new PasswordDeriveBytes("123", null))
        {
            byte[] keyBytes = password.GetBytes(keysize / 8);
            using (RijndaelManaged symmetricKey = new RijndaelManaged())
            {
                symmetricKey.Mode = CipherMode.CBC;
                using (ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes))
                {
                    using (MemoryStream memoryStream = new MemoryStream())
                    {
                        using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
                        {
                            cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
                            cryptoStream.FlushFinalBlock();
                            byte[] cipherTextBytes = memoryStream.ToArray();
                            return Convert.ToBase64String(cipherTextBytes);
                        }
                    }
                }
            }
        }
    }

    public static string Decrypt(string cipherText)
    {
        byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
        using (PasswordDeriveBytes password = new PasswordDeriveBytes("123", null))
        {
            byte[] keyBytes = password.GetBytes(keysize / 8);
            using (RijndaelManaged symmetricKey = new RijndaelManaged())
            {
                symmetricKey.Mode = CipherMode.CBC;
                using (ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes))
                {
                    using (MemoryStream memoryStream = new MemoryStream(cipherTextBytes))
                    {
                        using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
                        {
                            byte[] plainTextBytes = new byte[cipherTextBytes.Length];
                            int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
                            return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
                        }
                    }
                }
            }
        }
    }
}

}

Ravan Scafi
  • 6,382
  • 2
  • 24
  • 32