I build a C# program, to be run on Windows 10. I want to send emails from this program (calculation results) by just pressing a button. I put the from: e-mail address and the subject:, etc. in C# properties, but I do not want to put a clear text password anywhere in the program, AND I don't want the user to have to type in the password for the server each time a mail is sent.
Can that be done?
If so, how (generally)?
I was thinking of putting all that e-mail information, including an encrypted password for the server in a data file to be read during startup of the program.
Or maybe Windows 10 has a facility for that...
You can use the Windows Credential Management API. This way you will ask the user for the password only once and then store the password in Windows Credentials Manager.
Next time your application starts and it needs to use the password it will read it from Windows Credentials Manager. One can use the Windows Credential Management API directly using P/Invoke (credwrite, CredRead, example here) or via a C# wrapper CredentialManagement.
Sample usage using the NuGet CredentialManagement package:
public class PasswordRepository
{
private const string PasswordName = "ServerPassword";
public void SavePassword(string password)
{
using (var cred = new Credential())
{
cred.Password = password;
cred.Target = PasswordName;
cred.Type = CredentialType.Generic;
cred.PersistanceType = PersistanceType.LocalComputer;
cred.Save();
}
}
public string GetPassword()
{
using (var cred = new Credential())
{
cred.Target = PasswordName;
cred.Load();
return cred.Password;
}
}
}
I don't recommend storing passwords in files on client machines. Even if you encrypt the password, you will probably embed the decryption key in the application code which is not a good idea.
Related
First, I am pretty new to C# and sorry for the bad writing, I have a razor page web app with individual accounts authentication type. Now I am working on a UWP app in which users can log in to the UWP app with the username and password provided in the razor app. Users have the same username and password for both applications.
Is there any possible way to log in user to the UWP app and also limit users to access different parts of the app just like razor pages(Role manager)?
Please note that the razor app is on a local server (on-premise), not a cloud, also the UWP app is on the same network so it can access the database.
What is expected to happen is that users must provide a username and password in the UWP app, they have limited access based on their roles, user names and passwords are fetched from the razor page application Db, UWP app doesn't need the ability to create or edit user accounts(it's all managed by razor app)
Update
Please be more specific about your question next time.
if you want to hash the password in UWP apps, you could use HashAlgorithmProvider Class to hash the text. The HashAlgorithmProvider class support MD5,SHA1,SHA256,SHA384,SHA512. You could choose the same way as you choosed in your razor app.
The sample code looks like this:
public string SampleHashMsg()
{
string strAlgName = HashAlgorithmNames.Md5;
string strMsg = "thisistest";
// Convert the message string to binary data.
IBuffer buffUtf8Msg = CryptographicBuffer.ConvertStringToBinary(strMsg, BinaryStringEncoding.Utf8);
// Create a HashAlgorithmProvider object.
HashAlgorithmProvider objAlgProv = HashAlgorithmProvider.OpenAlgorithm(strAlgName);
// Demonstrate how to retrieve the name of the hashing algorithm.
string strAlgNameUsed = objAlgProv.AlgorithmName;
// Hash the message.
IBuffer buffHash = objAlgProv.HashData(buffUtf8Msg);
// Verify that the hash length equals the length specified for the algorithm.
if (buffHash.Length != objAlgProv.HashLength)
{
throw new Exception("There was an error creating the hash");
}
// Convert the hash to a string (for display).
string strHashBase64 = CryptographicBuffer.EncodeToHexString(buffHash);
// Return the encoded string
return strHashBase64;
}
Old
Your post contains many questions. Please focus on question in one post next time.
First, you need to check the document: Use a SQL Server database in a UWP app. This tutorial shows the steps about how to connect to a sql server in UWP apps. Then you will have to write your own logic for checking the input for username and password and verify it with the data in the database.
After that, you might need to create a userinfo class which contains a flag that could indicate the role or the user after you verified the user. Before navigation, you could check the flag do decide if the user could access the page. If not, then cancel the navigation.
I have a scenario where a C#.NET program must be supplied a secret that is derived from a Username/Password combination. This secret is non-reversible (think of it like a hash) but has the requirement that the secret can only be created with a .NET library.
The problem here is that there is the program that actually contains the username/password is different than the program that needs the secret and is not a .NET program, so the information has to be sent through some IPC.
It is worth noting that the program the has the username/password keeps them in memory for as long as the user is logged in. I realize that this itself is very insecure, but it isn't something that I am able to change.
I am looking for a way for the C#.NET program to get the secret as securely as possible.
Two options that I came up with are to use a Named Pipe to transfer the username/password directly from one application to the other, or to use COM components so the first application can send the username/password to the COM component, which can compute the secret and write it to a location that can be read later by the second application.
for the Named Pipe method I would expect the credential requesting component to look something like the following
using (var a = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, PipeOptions.Asynchronous, TokenImpersonationLevel.Impersonation))
{
var requestString = new StreamString(a);
var credString = new StreamString(a);
await a.ConnectAsync();
a.ReadMode = PipeTransmissionMode.Message;
requestString.WriteString(JsonConvert.SerializeObject(new CredentialRequest()));
var cred = JsonConvert.DeserializeObject<Credential>(credString.ReadString());
var secret = await CreateSecret(cred.Username, cred.Password);
a.Close();
}
Based on that, the side opposite side of the pipe should be pretty obvious.
For the COM solution I am thinking that I would create an object that has the following method
public void ComputeAndStoreSecret(string username, string password)
{
var secret = CreateSecret(username, password);
using (var applicationStorageFileForUser = IsolatedStorageFile.GetUserStoreForAssembly())
{
using (var applicationStorageStreamForUser = new IsolatedStorageFileStream("secret_store.txt", FileMode.Create, applicationStorageFileForUser))
{
using (StreamWriter sw = new StreamWriter(applicationStorageStreamForUser))
{
sw.WriteLine(secret);
}
}
}
}
There would also be a COM component that reads from that storage location and returns the secret.
I am basically looking for any insight as to why I would want to use one of these techniques over the other or maybe consider any other options (RPC, Mailbox, etc.)
Some things that I have discovered/considered
Named Pipe solution is vulnerable to Pipe Squatting
Named Pipes require username/password to leave process space of the first application
Storage Location of secret using COM solution can be seen and edited by everything
Isolated File Storage in COM solution is not intended to be used for secret information
I realize that neither of these solutions are secure, but I am looking for a solution that at least doesn't make it drastically more insecure.
I have created the registration and login form. Both work perfectly. But how do i recognize the user logged in as the PHP does by using SESSIONS and COOKIES. I can use static class to get data between different pages, but how can i retrieve the logged user data if he closes the application.
Is there any way for achieving this?
Thanks!
I'm assuming that you want something like instant messenger applications like Skype, or cloud storage applications like DropBox, OneDrive or Mega do. They ask you to enter user name and password once, and then start automatically without asking for user's credentials again.
They achieve this by storing user name and password in encrypted format in the file they normally keep in application folder under specific user account. See the following link for details: How can I get the current user directory?
This is standard practice, as another user will not be automatically logged into your app, if they not entered their own credentials.
Make sure you encrypt the user name and password or the whole file before saving it to disk, otherwise it may become an easy target for password stealing malware.
You should use user settings to do this, as this mechanism hides all the necessary work for creating files in the right locations, etc. from the developer. It works fine and it is made for stuff like this.
You design them in Visual Studio in the project properties on the "Settings" tab. Make sure to select the settings type correctly, as application settings are read-only.
Assume you have to settings UserName and UserPassword. Then, in your code, you could do this:
if (String.IsNullOrWhitespace(Properties.Settings.Default.UserName))
{
// USER NEEDS TO LOG IN
string userName;
string password;
if (Login(out userName, out password))
{
try
{
Properties.Settings.Default.UserName = Encrypt(userName);
Properties.Settings.Default.Password = Encrypt(password);
Properties.Settings.Default.Save();
}
catch (Exception exp)
{
...
}
}
}
else
{
// USER IS ALREADY LOGGED IN
}
private bool Login(out string userName, out string password) would be a method that shows a login user interface and returns true on success or false on failure.
private string Encrypt(string input) would be a method to encrypt a string.
I have a C#.NET application that must be able to change the user password on an IBM System i (iSeries / AS400) machine. I am currently using the following code to perform this operation using IBM's proprietary cwbx.dll.
using cwbx;
public void ChangePassword(string system, string user, string currentPassword, string newPassword)
{
AS400System as400 = new AS400System();
as400.Define(system);
try
{
as400.ChangePassword(user, currentPassword, newPassword);
}
finally
{
as400.Disconnect(cwbcoServiceEnum.cwbcoServiceAll);
}
}
This works well enough, but forces me (and all users of the application) to take a proprietary dependency on cwbx.dll. I would like to eliminate this dependency.
Is there any way to change the password using SQL similar to MS SQL Server's alter login mechanism?
I know I can accomplish this with the IBM.Data.DB2.iSeries .NET data provider by invoking programs from SQL using the following code from Integrating DB2 Universal Universal
Database for iSeries with for iSeries with
Microsoft ADO .NET.
/// <summary>
/// Call a program directly on the iSeries with parameters
/// </summary>
public string CallPgm(string cmdtext)
{
string rc = " ";
// Construct a string which contains the call to QCMDEXC.
// Because QCMDEXC uses single quote characters, we must
// delimit single quote characters in the command text
// with an extra single quote.
string pgmParm = "CALL QSYS/QCMDEXC('"
+ cmdtext.Replace("'", "''")
+ "', "
+ cmdtext.Length.ToString("0000000000.00000")
+ ")";
// Create a command to execute the program or command.
iDB2Command cmd = new iDB2Command(pgmParm, _connection);
try
{
cmd.ExecuteNonQuery();
}
catch (iDB2Exception ex)
{
rc = ex.Message;
}
// Dispose the command since we're done with it.
cmd.Dispose();
// Return the success or failure of the call.
return rc;
}
The problem with this technique is that I must have an existing connection before I can attempt to change a password. Unfortunately, if the user's password has expired they cannot connect to the database (iDB2CommErrorException) and as a result cannot change their password.
Is there any way accomplish this without the cwbx.dll?
To programmatically change expired passwords on an IBM i (aka System i / iSeries / AS400) from a .NET application without taking a dependency on a local installation of IBM i Access for Windows (for cwbx.dll), consider one of the following options.
Programmatically establish a Telnet connection to the IBM i and transmit a sequence of characters that mimics the user input necessary to perform a change password operation. *Note that this is insecure without further configuration.
IBM Toolbox for Java includes an OS/400 or i5/OS Java class that can be used in Java programs to change passwords. The Java help for the class is available in iSeries Information Center a the following Web site: http://publib.boulder.ibm.com/pubs/html/as400/v5r1/ic2924/index.htm
The following example demonstrates how to perform a change password operation on an expired password using the IBM Toolbox for Java. This can be invoked from a C# program using System.Diagnostics.Process.Start("java ChangeIBMiPassword hostname username oldpw newpw"); (assuming appropriate classpaths). Also note that it is possible to use Java API's directly from .NET with the IKVM.NET library.
import com.ibm.as400.access.AS400;
public class ChangeIBMiPassword {
public static void main(String[] args) {
if (args.length < 4)
System.exit(-1);
String host = args[0];
String user = args[1];
String oldpw = args[2];
String newpw = args[3];
AS400 sys = new AS400(host, user);
try {
sys.changePassword(oldpw, newpw);
} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
}
}
Write a secure web service that runs on the IBM i. This web service will accept parameters for username, current password and new password. When a user calls this web service, it will perform the change password operation on behalf of the calling program.
Write a secure web service that does not run on the IBM i. This web service will accept parameters for username, current password and new password. When a user calls this web service, it will use the cwbx library to perform the change password operation on behalf of the calling program. This does not totally eliminate the dependency on cwbx.dll, but it lowers it to a single system.
http://www-01.ibm.com/support/docview.wss?uid=nas10043a8b0e0544f1386256ba100659bcd
Write a stored procedure or function that invokes CHGUSRPRF. It would need to run under high enough authority (and thereby expose the system to additional risk), but it'd then be easy to interact with SQL. Seems like a very questionable idea.
What's the best way of saving sensitive data to a local file in Windows 8? I'm developing a C# application that needs to store oAuth tokens/passwords. I've heard it was common in .NET to encrypt/decrypt data, but I don't have any experience with those mechanics. Is encryption still recommended/neccesary given that Windows 8 apps have their own personal/protected storage area similar to Windows Phone?
Also, doesn't encrypting/decrypting each time when you request the data causes a performance issue? (would it be better to write a custom/lite algorithm?)
UPDATE: Please be aware that while modern/metro apps are restricted from poking at each other's stuff, desktop applications will have unrestricted access to all data stored through these APIs. See http://www.hanselman.com/blog/SavingAndRetrievingBrowserAndOtherPasswords.aspx which includes code demonstrating this.
Win8 has a new API called PasswordVault that's designed for taking care of all these hard problems for you. Really easy to use, secure, and can be configured by users to roam between their machines so they only have to enter credentials once. I've successfully used this for OAuth tokens
Retrieving credentials (note the stupid exception that WinRT raises... they really should just return null):
const string VAULT_RESOURCE = "[My App] Credentials";
string UserName { get; set; };
string Password { get; set; };
var vault = new PasswordVault();
try
{
var creds = vault.FindAllByResource(VAULT_RESOURCE).FirstOrDefault();
if (creds != null)
{
UserName = creds.UserName;
Password = vault.Retrieve(VAULT_RESOURCE, UserName).Password;
}
}
catch(COMException)
{
// this exception likely means that no credentials have been stored
}
Storing credentials:
vault.Add(new PasswordCredential(VAULT_RESOURCE, UserName, Password));
Removing credentials (when the user clicks the logout button in your app):
vault.Remove(_vault.Retrieve(VAULT_RESOURCE, UserName));
It depends on what you need, if you realy need to store the passwords you should use a 2-way encryption algorithm like 3DES/RC2/Rijndael etc.
However, if all you need to be able to do is verify if a password is correct it is recommended to use a oneway function to store a hash.
When dealing with sensitive data I realy recommend the encrypt/hash it, even if you use windows 8. Encryption does mean extra overhead but in most cases you will not notice the speed difference.
Would it be better to write your own custom/lite algorithm? As a security guy I advise against it. People spend years testing, improving and trying to find holes in existing algoritms. The ones that survived are therefore quite good.
you could encrypt like this:
public static string EncodePassword(string password)
{
byte[] bytes = Encoding.Unicode.GetBytes(password);
byte[] inArray = HashAlgorithm.Create("SHA1").ComputeHash(bytes);
return Convert.ToBase64String(inArray);
}
And when checking the user input, you also trow it into this method and check for it to match.
In case of data that you put in an xml (for example) that you want to encrypt/decrypt you can use RijndaelManaged.
-Edit1-
An example:
if you have a small login screen that pops up (ShowDialog) you can is it like this snip-it:
private void settings_Click(object sender, RoutedEventArgs e)
{
Login log = new Login(); //login window
log.ShowDialog(); //show the login window
string un = log.userName.Text; //the user input from the username field
string pw = log.passWord.Password; //the userinput from the password input
if (EncodePassword(un) == Properties.Settings.Default.adminUsername && EncodePassword(pw) == Properties.Settings.Default.adminPassword) //in my case, i stored it in the app settings, but this could also be somewhere else.
{
//login was correct
//do something
}
else
{
//login was not correct
}
}