29

I want simple encryption and decryption of password in C#. How to save the password in encrypted format in database and retrieve as original format by decryption?

2
  • 22
    Is there any particular reason you need to retrieve it? Most of the time you can simply use a hash function to store it. Then when they enter their password, you hash their entry and compare. Commented Nov 5, 2009 at 5:41
  • 1
    decryption of passwords is a very significant security vulnerability. Passwords should be hashed, not encrypted. Commented Jul 10, 2019 at 15:31

10 Answers 10

13

Here you go. I found it somewhere on the internet. Works well for me.

    /// <summary>
    /// Encrypts a given password and returns the encrypted data
    /// as a base64 string.
    /// </summary>
    /// <param name="plainText">An unencrypted string that needs
    /// to be secured.</param>
    /// <returns>A base64 encoded string that represents the encrypted
    /// binary data.
    /// </returns>
    /// <remarks>This solution is not really secure as we are
    /// keeping strings in memory. If runtime protection is essential,
    /// <see cref="SecureString"/> should be used.</remarks>
    /// <exception cref="ArgumentNullException">If <paramref name="plainText"/>
    /// is a null reference.</exception>
    public string Encrypt(string plainText)
    {
        if (plainText == null) throw new ArgumentNullException("plainText");

        //encrypt data
        var data = Encoding.Unicode.GetBytes(plainText);
        byte[] encrypted = ProtectedData.Protect(data, null, Scope);

        //return as base64 string
        return Convert.ToBase64String(encrypted);
    }

    /// <summary>
    /// Decrypts a given string.
    /// </summary>
    /// <param name="cipher">A base64 encoded string that was created
    /// through the <see cref="Encrypt(string)"/> or
    /// <see cref="Encrypt(SecureString)"/> extension methods.</param>
    /// <returns>The decrypted string.</returns>
    /// <remarks>Keep in mind that the decrypted string remains in memory
    /// and makes your application vulnerable per se. If runtime protection
    /// is essential, <see cref="SecureString"/> should be used.</remarks>
    /// <exception cref="ArgumentNullException">If <paramref name="cipher"/>
    /// is a null reference.</exception>
    public string Decrypt(string cipher)
    {
        if (cipher == null) throw new ArgumentNullException("cipher");

        //parse base64 string
        byte[] data = Convert.FromBase64String(cipher);

        //decrypt data
        byte[] decrypted = ProtectedData.Unprotect(data, null, Scope);
        return Encoding.Unicode.GetString(decrypted);
    }
Sign up to request clarification or add additional context in comments.

10 Comments

Perhaps I am mistaken, but it looks like this solution is not portable across users / machines and is therefore not suitable for storing encrypted data. From the documentation: "the DPAPI stores the key data in user profiles". If you use this method to encrypt and store data, you will not be able to retrieve and decrypt the data from a different machine, or heaven forbid, if you rebuild your server.
Visual Studio doesn't recognise "Scope"?
@DanFromGermany add reference to the System.Security assembly. See msdn.microsoft.com/en-us/library/…
Scope must be DataProtectionScope.LocalMachine (encryption/decryption must be done on the same machine) or DataProtectionScope.CurrentUser (encryption/decryption must be done by the same user)
This is a joke right? Because it's the accepted answer to a question that gets a lot of views, and it's something that no one should ever do.
|
12

EDIT: this is a very old answer. SHA1 was deprecated in 2011 and has now been broken in practice. https://shattered.io/ Use a newer standard instead (e.g. SHA256, SHA512, etc).

If your answer to the question in my comment is "No", here's what I use:

    public static byte[] HashPassword(string password)
    {
        var provider = new SHA1CryptoServiceProvider();
        var encoding = new UnicodeEncoding();
        return provider.ComputeHash(encoding.GetBytes(password));
    }

4 Comments

SHA1 has been compromised, as shown here: okami-infosec.blogspot.com/2007/01/hash-sha-1-compromised.html
I don't believe any of the SHA-2 family has been compromised, you may want to use one of these: en.wikipedia.org/wiki/SHA_hash_functions#SHA-2_family
But, it depends on how secure, or how paranoid, you will be. At the university I was very paranoid.
Don't use a fast hash for hashing passwords. Not SHA-1, and not SHA-2 either. Use scrypt, bcrypt or PBKDF2. It's also not an answer to the question, since the OP needs reversibility.
4

I use RC2CryptoServiceProvider.

    public static string EncryptText(string openText)
    {
        RC2CryptoServiceProvider rc2CSP = new RC2CryptoServiceProvider();
        ICryptoTransform encryptor = rc2CSP.CreateEncryptor(Convert.FromBase64String(c_key), Convert.FromBase64String(c_iv));
        using (MemoryStream msEncrypt = new MemoryStream())
        {
            using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
            {
                byte[] toEncrypt = Encoding.Unicode.GetBytes(openText);

                csEncrypt.Write(toEncrypt, 0, toEncrypt.Length);
                csEncrypt.FlushFinalBlock();

                byte[] encrypted = msEncrypt.ToArray();

                return Convert.ToBase64String(encrypted);
            }
        }
    }

    public static string DecryptText(string encryptedText)
    {
        RC2CryptoServiceProvider rc2CSP = new RC2CryptoServiceProvider();
        ICryptoTransform decryptor = rc2CSP.CreateDecryptor(Convert.FromBase64String(c_key), Convert.FromBase64String(c_iv));
        using (MemoryStream msDecrypt = new MemoryStream(Convert.FromBase64String(encryptedText)))
        {
            using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
            {
                List<Byte> bytes = new List<byte>();
                int b;
                do
                {
                    b = csDecrypt.ReadByte();
                    if (b != -1)
                    {
                        bytes.Add(Convert.ToByte(b));
                    }

                }
                while (b != -1);

                return Encoding.Unicode.GetString(bytes.ToArray());
            }
        }
    }

3 Comments

Just in case you want to know to populate with random and valid data c_iv and c_key, there's a property Key and IV in the instance of RC2CryptoServiceProvider.
Your IV use is incorrect. The whole point of an IV is to be different for each encryption. Don't use a constant IV.
I had to convert the string to base64 string first stackoverflow.com/a/57293370/5237614
3

First create a class like:

public class Encryption
    { 
        public static string Encrypt(string clearText)
        {
            string EncryptionKey = "MAKV2SPBNI99212";
            byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
            using (Aes encryptor = Aes.Create())
            {
                Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
                encryptor.Key = pdb.GetBytes(32);
                encryptor.IV = pdb.GetBytes(16);
                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(clearBytes, 0, clearBytes.Length);
                        cs.Close();
                    }
                    clearText = Convert.ToBase64String(ms.ToArray());
                }
            }
            return clearText;
        }

        public static string Decrypt(string cipherText)
        {
            string EncryptionKey = "MAKV2SPBNI99212";
            byte[] cipherBytes = Convert.FromBase64String(cipherText);
            using (Aes encryptor = Aes.Create())
            {
                Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
                encryptor.Key = pdb.GetBytes(32);
                encryptor.IV = pdb.GetBytes(16);
                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(cipherBytes, 0, cipherBytes.Length);
                        cs.Close();
                    }
                    cipherText = Encoding.Unicode.GetString(ms.ToArray());
                }
            }
            return cipherText;
        }
    }

**In Controller **

add reference for this encryption class:

using testdemo.Models

public ActionResult Index() {
            return View();
        }
        [HttpPost]
        public ActionResult Index(string text)
        {
            if (Request["txtEncrypt"] != null)
            {
                string getEncryptionCode = Request["txtEncrypt"];
                string DecryptCode = Encryption.Decrypt(HttpUtility.UrlDecode(getEncryptionCode));
                ViewBag.GetDecryptCode = DecryptCode;
                return View();
            }
            else {
                string getDecryptCode = Request["txtDecrypt"];
                string EncryptionCode = HttpUtility.UrlEncode(Encryption.Encrypt(getDecryptCode));
                ViewBag.GetEncryptionCode = EncryptionCode;
                return View();
            }

        }

In View

<h2>Decryption Code</h2>
@using (Html.BeginForm())
{
    <table class="table-bordered table">
        <tr>
            <th>Encryption Code</th>
            <td><input type="text" id="txtEncrypt" name="txtEncrypt" placeholder="Enter Encryption Code" /></td>
        </tr>
        <tr>
            <td colspan="2">
                <span style="color:red">@ViewBag.GetDecryptCode</span>
            </td>
        </tr>
        <tr>
                <td colspan="2">
                    <input type="submit" id="btnEncrypt" name="btnEncrypt"value="Decrypt to Encrypt code" />
                </td>
            </tr>
    </table>
}
    <br />
    <br />
    <br />
    <h2>Encryption Code</h2>
@using (Html.BeginForm())
{
    <table class="table-bordered table">
        <tr>
            <th>Decryption Code</th>
            <td><input type="text" id="txtDecrypt" name="txtDecrypt" placeholder="Enter Decryption Code" /></td>
        </tr>

        <tr>
            <td colspan="2">
                <span style="color:red">@ViewBag.GetEncryptionCode</span>
            </td>
        </tr>
        <tr>
            <td colspan="2">
                <input type="submit" id="btnDecryt" name="btnDecryt" value="Encrypt to Decrypt code" />
            </td>
        </tr>
    </table>
}

Comments

3

This question will answer how to encrypt/decrypt: Encrypt and decrypt a string in C#?

You didn't specify a database, but you will want to base-64 encode it, using Convert.toBase64String. For an example you can use: http://www.opinionatedgeek.com/Blog/blogentry=000361/BlogEntry.aspx

You'll then either save it in a varchar or a blob, depending on how long your encrypted message is, but for a password varchar should work.

The examples above will also cover decryption after decoding the base64.

UPDATE:

In actuality you may not need to use base64 encoding, but I found it helpful, in case I wanted to print it, or send it over the web. If the message is long enough it's best to compress it first, then encrypt, as it is harder to use brute-force when the message was already in a binary form, so it would be hard to tell when you successfully broke the encryption.

3 Comments

Besides portability, are there any substantial benefits to using base-64 instead of binary (if the db supports it)?
No benefit, other than the fact that it is easier to store, to treat as a string, and if you need to move it around I find it easier. I am not a fan of using blobs, mainly because I spent so long on mysql where they really didn't have support, so I just think that way. Besides, if you want to print out the encrypted message then it is in a printable fashion, which can be handy, just to see what happened.
Good point... I converted the hash to a string once during debugging and compared the resulting kanji ><
0

One of the simplest methods of encryption (if you absolutely MUST make one up yourself since .NET has such awesome encryption libraries already [as provided by Cogwheel just before me]) is to XOR the ASCII value of each character of the input string against a known "key" value. XOR functionality in C# is accomplished using the ^ key I believe.

Then you can convert the values back from the result of the XOR to ASCII Chars, and store them in the database. This is not highly secure, but it is one of the easiest encryption methods.

Also, if using an access database, I've found that some characters when put in front of a string make the entire field unreadable when opening the database itself. But the field is still readable by your app even though it is blank to a malicious user. But who uses access anymore anyway right?

3 Comments

I know, right? look around innocently (Actually, I'm in the middle of writing a proposal to get rid of the system I inherited and enter the 21st century)
I feel his pain. The only reason I knew that about access is because I was dealing with a project at my job that used an old access Database. It was already being up-converted at the time, but that didn't stop the customers from requesting new features of the old version.
Key reuse is an absolutely deadly sin with stream ciphers. Makes them really easy to break.
0
 string clearText = txtPassword.Text;
        string EncryptionKey = "MAKV2SPBNI99212";
        byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
        using (Aes encryptor = Aes.Create())
        {
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
            encryptor.Key = pdb.GetBytes(32);
            encryptor.IV = pdb.GetBytes(16);
            using (MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(clearBytes, 0, clearBytes.Length);
                    cs.Close();
                }
                clearText = Convert.ToBase64String(ms.ToArray());
            }
        }

Comments

0

Do not encrypt/decrypt passwords, that is a significant security vulnerability. HASH passwords, using a strong hash algorithm such as PBKDF2, bcrypt, scrypts, or Argon.

When the user sets their password, hash it, and store the hash (and salt).

When the user logs in, re-hash their provided password, and compare it to the hash in the database.

Comments

0
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;


public class StringEncryptor
{
    private readonly byte[] key;
    private readonly byte[] iv;

    public StringEncryptor(string keyString, string ivString)
    {
        key = Encoding.UTF8.GetBytes(keyString);
        iv = Encoding.UTF8.GetBytes(ivString);
    }

    public string Encrypt(string plainText)
    {
        using var aes = Aes.Create();
        aes.Key = key;
        aes.IV = iv;

        var encryptor = aes.CreateEncryptor(aes.Key, aes.IV);

        using var memoryStream = new MemoryStream();
        using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
        {
            using (var streamWriter = new StreamWriter(cryptoStream))
            {
                streamWriter.Write(plainText);
            }
        }

        return Convert.ToBase64String(memoryStream.ToArray());
    }

    public string Decrypt(string cipherText)
    {
        using var aes = Aes.Create();
        aes.Key = key;
        aes.IV = iv;

        var decryptor = aes.CreateDecryptor(aes.Key, aes.IV);

        using var memoryStream = new MemoryStream(Convert.FromBase64String(cipherText));
        using var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
        using var streamReader = new StreamReader(cryptoStream);

        return streamReader.ReadToEnd();
    }
}

class Program
{
    static void Main(string[] args)
    {
        string key = "ThisIsASuperSecretKey"; // Must be 16, 24, or 32 bytes long
        string iv = "ThisIsASuperSecretIV"; // Must be 16 bytes long

        var encryptor = new StringEncryptor(key, iv);

        string originalString = "Hello, world!";
        Console.WriteLine("Original: " + originalString);

        string encryptedString = encryptor.Encrypt(originalString);
        Console.WriteLine("Encrypted: " + encryptedString);

        string decryptedString = encryptor.Decrypt(encryptedString);
        Console.WriteLine("Decrypted: " + decryptedString);
    }
}

1 Comment

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
-1

You can use the managed .Net cryptography library, then save the encrypted string into the database. When you want to verify the password you can compare the stored database string with the hashed value of the user input. See here for more info about SHA512Managed

using System.Security.Cryptography;

    public static string EncryptSHA512Managed(string password)
    {
        UnicodeEncoding uEncode = new UnicodeEncoding();
        byte[] bytPassword = uEncode.GetBytes(password);
        SHA512Managed sha = new SHA512Managed();
        byte[] hash = sha.ComputeHash(bytPassword);
        return Convert.ToBase64String(hash);
    }

1 Comment

1) Bad method name, since you hash and don't encrypt. 2) Don't use a fast hash for hashing passwords. A single iteration of SHA-2 is not good enough. Use scrypt, bcrypt or PBKDF2. It's also not an answer to the question, since the OP needs reversibility.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.