30

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?

Cœur
  • 37,241
  • 25
  • 195
  • 267
kart
  • 625
  • 3
  • 12
  • 21
  • 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. – Cogwheel Nov 05 '09 at 05:41
  • 1
    decryption of passwords is a very significant security vulnerability. Passwords should be hashed, not encrypted. – Jason Coyne Jul 10 '19 at 15:31

9 Answers9

14

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);
    }
this. __curious_geek
  • 42,787
  • 22
  • 113
  • 137
  • nice answer, i didn`t understand the Scope part of the protect method. I google it and i found you can use DataProtection.CurrentUser. Is that ok? or will it bring problems when decrypting? can you explain what you did to create your Scope Class. Thank you. – euther Jan 14 '11 at 14:27
  • 9
    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. – Brett Aug 25 '11 at 14:21
  • 1
    Visual Studio doesn't recognise "Scope"? – Amrit Sharma Jun 08 '13 at 14:26
  • what do I have to add to `using`, using Win8 + C# 2012 it can't find `ProtectedData.` – Daniel W. Jul 02 '13 at 07:34
  • 2
    @DanFromGermany add reference to the System.Security assembly. See http://msdn.microsoft.com/en-us/library/system.security.cryptography.protecteddata(v=vs.110).aspx – Stewart Mbofana Jan 03 '14 at 08:02
  • 1
    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) – Brian Low Mar 02 '14 at 22:47
  • 7
    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. – Joel Coehoorn Mar 23 '15 at 02:11
  • @ Telos: One issue is that optionalEntopy is null when ProtectedData.Unprotect() is called. I'm not sure what other issues Joel might see. More generally this isn't secure. Anybody that decompiles the code will have access to the raw data... even if you add entropy. This only prevents superficial attacks. Sometimes that's enough. A better solution is needed for the implementation to be considered secure. There are only 3 ways to do this that I know of: 1) network solution, 2) user, request password, 3) scoping the protect() function to the current user with DataProtectionScope.CurrentUser. – jarederaj Jun 18 '15 at 18:44
  • Almost used this before realizing what @Brett said, if you implement this code in production and change servers, you are screwed. – Brandon Aug 24 '15 at 16:57
  • AFAIK passwords are non decryptable: they must be encrypted one-way. when someone authenticates - the systems encrypts the user input and compares the result with the encrypted password in the user management repository (database?) – Yaron Mar 07 '19 at 14:25
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));
    }
Cogwheel
  • 22,781
  • 4
  • 49
  • 67
  • 2
    SHA1 has been compromised, as shown here: http://okami-infosec.blogspot.com/2007/01/hash-sha-1-compromised.html – James Black Nov 05 '09 at 06:50
  • I don't believe any of the SHA-2 family has been compromised, you may want to use one of these: http://en.wikipedia.org/wiki/SHA_hash_functions#SHA-2_family – James Black Nov 05 '09 at 06:52
  • But, it depends on how secure, or how paranoid, you will be. At the university I was very paranoid. – James Black Nov 05 '09 at 06:53
  • 10
    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. – CodesInChaos Jan 10 '13 at 14:24
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());
            }
        }
    }
Pavel Belousov
  • 1,848
  • 2
  • 14
  • 22
  • 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`. – JiBéDoublevé Nov 14 '12 at 19:03
  • 5
    Your IV use is incorrect. The whole point of an IV is to be different for each encryption. Don't use a constant IV. – CodesInChaos Jan 10 '13 at 14:29
  • I had to convert the string to base64 string first https://stackoverflow.com/a/57293370/5237614 – Arun Prasad E S Aug 11 '19 at 12:57
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.

James Black
  • 41,583
  • 10
  • 86
  • 166
  • Besides portability, are there any substantial benefits to using base-64 instead of binary (if the db supports it)? – Cogwheel Nov 05 '09 at 05:59
  • 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. – James Black Nov 05 '09 at 06:14
  • Good point... I converted the hash to a string once during debugging and compared the resulting kanji > – Cogwheel Nov 05 '09 at 06:31
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>
}
Eilon
  • 25,582
  • 3
  • 84
  • 102
star test
  • 51
  • 1
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?

Jrud
  • 820
  • 3
  • 7
  • 21
  • 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) – Cogwheel Nov 05 '09 at 05:55
  • 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. – Jrud Nov 05 '09 at 19:30
  • 2
    Key reuse is an absolutely deadly sin with stream ciphers. Makes them *really* easy to break. – CodesInChaos Jan 10 '13 at 14:28
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());
            }
        }
Jeet Poria
  • 23
  • 6
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.

Jason Coyne
  • 6,509
  • 8
  • 40
  • 70
-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);
    }
Case
  • 31
  • 2
  • 4
    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. – CodesInChaos Jan 10 '13 at 14:26