-
Notifications
You must be signed in to change notification settings - Fork 0
Encryption and Password Hashing in SafeNotes
SafeNotes employs robust encryption and password hashing techniques to ensure the security and privacy of your notes and journal entries.
Password hashing is used to store user passwords securely. Instead of saving the plain text password, SafeNotes hashes the password using the SHA-256 algorithm. This ensures that even if the password storage is compromised, the actual passwords remain protected.
private string HashPassword(string password)
{
using (SHA256 sha256 = SHA256.Create())
{
byte[] bytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(password));
StringBuilder builder = new StringBuilder();
for (int i = 0; i < bytes.Length; i++)
{
builder.Append(bytes[i].ToString("x2"));
}
return builder.ToString();
}
}
- The HashPassword method takes a plain text password as input. • It uses the SHA256 class to compute the hash of the password. • The resulting byte array is converted to a hexadecimal string, which is then stored.
SafeNotes uses AES (Advanced Encryption Standard) to encrypt and decrypt journal entries. AES is a symmetric encryption algorithm, meaning the same key is used for encryption and decryption. A unique salt and initialization vector (IV) are generated for each encryption operation to enhance security.
private string EncryptString(string plainText, string saltedDecryptionKey)
{
try
{
using (Aes aes = Aes.Create())
{
byte[] salt = new byte[16];
using (var rng = new RNGCryptoServiceProvider())
{
rng.GetBytes(salt);
}
var key = new Rfc2898DeriveBytes(saltedDecryptionKey, salt, 10000);
aes.Key = key.GetBytes(32);
aes.GenerateIV();
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
using (MemoryStream ms = new MemoryStream())
{
ms.Write(salt, 0, salt.Length);
ms.Write(aes.IV, 0, aes.IV.Length);
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter sw = new StreamWriter(cs))
{
sw.Write(plainText);
}
}
return Convert.ToBase64String(ms.ToArray());
}
}
}
catch (CryptographicException ex)
{
MessageBox.Show($"Cryptographic error: {ex.Message}", "Encryption Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return null;
}
catch (Exception ex)
{
MessageBox.Show($"General error: {ex.Message}", "Encryption Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return null;
}
}
- A unique salt is generated for each encryption operation.
- The Rfc2898DeriveBytes class derives a 256-bit key from the salted decryption key.
- A random IV is generated for the AES encryption.
- The salt and IV are prepended to the ciphertext for use during decryption.
- The plain text is encrypted and converted to a Base64 string for storage.
private string DecryptString(string cipherText, string saltedDecryptionKey)
{
try
{
DecryptionStatusLabel.Text = "Decrypting...";
DecryptionStatusLabel.Visible = true;
Application.DoEvents();
DecryptionStatusLabel.Text = "";
using (Aes aes = Aes.Create())
{
byte[] fullCipher = Convert.FromBase64String(cipherText);
byte[] salt = new byte[16];
byte[] iv = new byte[aes.BlockSize / 8];
byte[] cipherBytes = new byte[fullCipher.Length - salt.Length - iv.Length];
Array.Copy(fullCipher, 0, salt, 0, salt.Length);
Array.Copy(fullCipher, salt.Length, iv, 0, iv.Length);
Array.Copy(fullCipher, salt.Length + iv.Length, cipherBytes, 0, cipherBytes.Length);
var key = new Rfc2898DeriveBytes(saltedDecryptionKey, salt, 10000);
aes.Key = key.GetBytes(32);
aes.IV = iv;
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
using (MemoryStream ms = new MemoryStream(cipherBytes))
{
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
{
using (StreamReader sr = new StreamReader(cs))
{
string decryptedText = sr.ReadToEnd();
DecryptionStatusLabel.Visible = false;
return decryptedText;
}
}
}
}
}
catch (CryptographicException ex)
{
MessageBox.Show($"Cryptographic error: {ex.Message}", "Decryption Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
DecryptionStatusLabel.Visible = false;
return null;
}
catch (FormatException ex)
{
MessageBox.Show($"Format error: {ex.Message}", "Decryption Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
DecryptionStatusLabel.Visible = false;
return null;
}
catch (Exception ex)
{
MessageBox.Show($"General error: {ex.Message}", "Decryption Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
DecryptionStatusLabel.Visible = false;
return null;
}
}
- The salt and IV are extracted from the beginning of the ciphertext.
- The Rfc2898DeriveBytes class derives the same 256-bit key from the salted decryption key and salt.
- The ciphertext is decrypted using the derived key and IV.
- The decrypted text is returned after removing the salt and IV.
Using these techniques, SafeNotes ensures that your data remains secure and private, protecting it from unauthorized access.