-2

I'm creating a messaging application that will use an outlook account to send an email. However, I'm unsure about the proper steps to store the e-mail password on the user's computer. Suppose I had the following code:

SmtpClient SmtpServer = new SmtpClient("smtp.live.com");
var mail = new MailMessage();
mail.From = new MailAddress("youremail@hotmail.com");
mail.To.Add("to@gmail.com");
mail.Subject = "Test Mail - 1";
mail.IsBodyHtml = true;
string htmlBody;
htmlBody = "Write some HTML code here";
mail.Body = htmlBody;
SmtpServer.Port = 587;
SmtpServer.UseDefaultCredentials = false;
SmtpServer.Credentials = new System.Net.NetworkCredential("youremail@hotmail.com", "password");
SmtpServer.EnableSsl = true;
SmtpServer.Send(mail);

Obviously, I don't want "password" stored as a string inside my application. What would be the ideal/proper solution to storing a password on the user's machine so I can read it into my application, and pass it to the NetworkCredential constructor?

I've done reading here, and here. The first link suggest storing it in a file or registry, not sure how to store it in a registry. How would I properly store it in a file?

Community
  • 1
  • 1
Nexusfactor
  • 101
  • 7

1 Answers1

0

The best approach would be to serialize the credentials and then encrypt it and then write the encrypted bytes to a file. Reversing the process will work for retrieving the data.

First, create a class AES.cs:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace AES_Password_Storer
{
    public static class AES
    {
        public static byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
    {
        byte[] encryptedBytes = null;

        // Set your salt here, change it to meet your flavor:
        // The salt bytes must be at least 8 bytes.
        byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };

        using (MemoryStream ms = new MemoryStream())
        {
            using (RijndaelManaged AES = new RijndaelManaged())
            {
                AES.KeySize = 256;
                AES.BlockSize = 128;

                var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
                AES.Key = key.GetBytes(AES.KeySize / 8);
                AES.IV = key.GetBytes(AES.BlockSize / 8);

                AES.Mode = CipherMode.CBC;

                using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
                    cs.Close();
                }
                encryptedBytes = ms.ToArray();
            }
        }

        return encryptedBytes;
    }
    public static byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
    {
        byte[] decryptedBytes = null;

        // Set your salt here, change it to meet your flavor:
        // The salt bytes must be at least 8 bytes.
        byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };

        using (MemoryStream ms = new MemoryStream())
        {
            using (RijndaelManaged AES = new RijndaelManaged())
            {
                AES.KeySize = 256;
                AES.BlockSize = 128;

                var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
                AES.Key = key.GetBytes(AES.KeySize / 8);
                AES.IV = key.GetBytes(AES.BlockSize / 8);

                AES.Mode = CipherMode.CBC;

                using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
                    cs.Close();
                }
                decryptedBytes = ms.ToArray();
            }
        }

        return decryptedBytes;
    }
}
}

Next, create a class Credentials.cs: N.B. - Now I have created the Credentials class to hold only one user's credentials. You can tweak it to hold multiple ones by creating a list.

[Serializable]
public class Credentials
{
public string Email { get; set; }
public string Password { get; set; }
}

Next, for encryption (writing the data to a file):

        XmlSerializer xs = new XmlSerializer(typeof(Credentials));
        MemoryStream ms = new MemoryStream();
        xs.Serialize(ms, new Credentials() { Email = "email@service.com",   Password = "passworduser" });
        byte[] encrypted = AES.AES_Encrypt(ms.ToArray(), Encoding.UTF8.GetBytes("encryptionkey")); //This is the key
        File.WriteAllBytes("passwordfile.pwd", encrypted);

Now, for decryption:

        MemoryStream ms = new   MemoryStream(AES.AES_Decrypt(File.ReadAllBytes("passwordfile.pwd"), Encoding.UTF8.GetBytes("encryptionkey"))); //Here goes the key
        XmlSerializer xs = new XmlSerializer(typeof(Credentials));
        Credentials c = (Credentials)xs.Deserialize(ms);
        // This 'c' contains your credentials.

Now in the codes for encryption and decryption, there is a string "encryptionkey". This is the main key to all this. You can (in fact, should) change this and keep it in a safe place (in your app).

Fᴀʀʜᴀɴ Aɴᴀᴍ
  • 6,131
  • 5
  • 31
  • 52