Reputation: 1973
I'm learning C# and am trying to implement a Login Function. I have a registration form, a login form and my data (including this user information) gets saved into an XML File.
I have the following Class:
public static class UserController
{
// Inspiration from https://stackoverflow.com/questions/12657792/how-to-securely-save-username-password-local
private static readonly byte[] entropy = new byte[20];
public static string EncryptString(string password)
{
// Convert Password to byte[]
byte[] data = Encoding.UTF8.GetBytes(password);
// use RandomNumberGenerator instead of using RNGCryptoServiceProvider which is obsolete
//https://stackoverflow.com/questions/72418725/rngcryptoserviceprovider-is-obsolete
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(entropy);
}
// Protect (Encrypt) the String
byte[] ciphertext = ProtectedData.Protect(data, entropy, DataProtectionScope.CurrentUser);
// return as Base64
return Convert.ToBase64String(ciphertext);
}
public static string DecryptString(string password)
{
byte[] plaintext = ProtectedData.Unprotect(Convert.FromBase64String(password), entropy, DataProtectionScope.CurrentUser);
return Encoding.UTF8.GetString(plaintext);
}
public static bool CheckLoginCredentials(string username, string password)
{
bool isOK = false;
var myUser = XmlHandler.GetUserFromXml(username);
if (myUser != null)
{
// Decrypt Password
string plainpassword = DecryptString(myUser.Password);
if (username == myUser.UserName && password == plainpassword)
isOK = true;
}
return isOK;
}
}
When I create a User in my registration form (which gets his password encrypted with DecryptString()
) and then Login with that user, everything works.
However, if I close the application and try to login again, the DecryptString()
can't decrypt the Password to plain text anymore.
Why is that? Do I have to store a key somewhere?
Errormsg:
Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException
HResult=0x8007000D
Nachricht = The data is invalid.
Quelle = System.Security.Cryptography.ProtectedData
Stapelüberwachung:
bei System.Security.Cryptography.ProtectedData.ProtectOrUnprotect(Byte[] inputData, Byte[] optionalEntropy, DataProtectionScope scope, Boolean protect)
bei System.Security.Cryptography.ProtectedData.Unprotect(Byte[] encryptedData, Byte[] optionalEntropy, DataProtectionScope scope)
bei Semesterprojekt_ContactManager.UserController.DecryptString(String password) in C:\Install\xxx\UserController.cs: Zeile37
bei Semesterprojekt_ContactManager.UserController.CheckLoginCredentials(String username, String password) in C:\Install\xxx\UserController.cs: Zeile54
bei Semesterprojekt_ContactManager.Login_View.CmdLogin_Click(Object sender, EventArgs e) in C:\Install\xxx\Login_View.cs: Zeile22
bei System.Windows.Forms.Control.OnClick(EventArgs e)
bei System.Windows.Forms.Button.OnClick(EventArgs e)
bei System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
bei System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
bei System.Windows.Forms.Control.WndProc(Message& m)
bei System.Windows.Forms.ButtonBase.WndProc(Message& m)
bei System.Windows.Forms.Button.WndProc(Message& m)
bei System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
bei System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
bei System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, WM msg, IntPtr wparam, IntPtr lparam)
Upvotes: 0
Views: 160
Reputation: 502
The point of generating entropy
is that it's random - It's highly unlikely to contain the same values twice in a row, therefore you can't use to decrypt a password after restarting your application.
However, you should never need to decrypt a password - you should just verify it's correct via a hash. See BCrypt.NET as an example.
Upvotes: 1