Why is SecureString decryption giving different results between executables? - c#

In proxy.exe I am creating a secure string the following way:
public SecureString GetSecureEncryptionKey()
{
string strPassword = "8charPwd";
SecureString secureStr = new SecureString();
if (strPassword.Length > 0)
{
foreach (var c in strPassword.ToCharArray()) secureStr.AppendChar(c);
}
return secureStr;
}
Then in main.exe I am decrypting it using this function:
public string convertToUNSecureString(SecureString secstrPassword)
{
IntPtr unmanagedString = IntPtr.Zero;
try
{
unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(secstrPassword);
return Marshal.PtrToStringUni(unmanagedString);
}
finally
{
Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
}
}
The issue is that the returned string is empty, unless I encrypt the initial string within main.exe, then the returned decrypted string is indeed "8charPwd". Why is this happening? Is SecureString encryption bound to the executable?

The purpose of SecureString is to keep strings safety inside your application memory(keep the string secure in RAM)
SecureString object is not a serialize-able.
You cannot transfer an instance between applications.
SecureString encrypt the string by using RtlEncryptMemory (WINAPI) with the flag:"0" (only the same process can decrypt the content). RtlEncryptMemory API
if you don't want to expose the password(at any time) in the RAM, you can create a simple obfuscation(or encryption) logic, and then transfer the content.
Edit:
I found 2 old questions that might be helpful for you:
When would I need a SecureString in .NET?
Wcf-Authentication and Logging

Related

Encrypting a connection string in memory using a class

I am writing a Windows Service using C# and .Net 4.6. The service is configured such that it runs perpetually by sleeping for a configurable period of time, before running and performing some tasks. As part of the initial start-up, the service goes and gets a list of connection strings so it can connect to a list of database servers and gather some information. I want to be able to persist the connection strings in memory. The idea is that the service grabs the connection strings on startup and holds them in memory until the service stops. Next time it starts it goes and grabs them again. This has led me down the path of encrypting the connection strings as some may contain username/password combinations.
So What I have tried to do it create a class to store this information, and handle the encryption/decryption of the connection string on the fly with the get and set properties.
Note: I have hard-coded a length of the byte array to 1024, but this should probably be dynamically adjusted to the nearest 16.
using System;
using System.Text;
using System.Security.Cryptography;
namespace XXXXXXX.DB
{
public class Instance
{
private byte[] _connectionString = new byte[1024];
System.Text.ASCIIEncoding ae = new ASCIIEncoding();
public string Name { get; set; }
public string ConnectionString
{
set
{
if (value.Length < _connectionString.Length)
value = value.PadRight(_connectionString.Length, ' ');
else
value = value.Substring(0, _connectionString.Length);
_connectionString = ae.GetBytes(value);
ProtectedMemory.Protect(_connectionString, MemoryProtectionScope.SameProcess);
}
get
{
ProtectedMemory.Unprotect(_connectionString, MemoryProtectionScope.SameProcess);
return ae.GetString(_connectionString).Trim();
}
}
}
So I set the ConnectionString property on an Instance object and it is encrypted as I expect. But when I access the unencrypted ConnectionString, the result is still encrypted:
using (SqlConnection connection = new SqlConnection(_theInstance.ConnectionString))
I think this is the fact that the private member variable for ConnectionString is a byte array which is a reference type? To be honest I'm scratching my head a bit on this.
Please note I've looked at many, many examples that make a simple console app and do the encryption and unencrypted all in the same method - but can it be done as I'm trying to do?

Convert from console to string for return [duplicate]

What I really want to do is this
static string Main(string[] args)
but that doesn't work, your only options are void and int. So, What are some different ways to return the string that I need to return to the calling application?
Background
I need to write a console app that is specifically designed to be called from another application
Process.Start("MyCode.exe -Option 12aaa1234");
How can this calling program receive a string returned from that executable?
Research
From what I can tell, at this point in time my only option is to have the calling application attach a listening stream to the Standard Output stream of the process before starting it, and send the "return" using Console.Out.Write from inside my executable. Is this in fact the ONLY way to do this, or is there something different/better I can use?
Is this in fact the ONLY way to do this, or is there something different/better I can use?
This isn't the only way to do this, but it is the most common.
The other options would involve some form of interprocess communication, which is likely going to be significantly more development effort for a single string.
Note that, if the calling application is a .NET application, and you have control over both applications, it might make more sense to just write a class library instead of a console application. This would allow you to keep the code completely separate, but have the executable "call into" your library to get the string data.
Idea 1:
Using MyCode.exe, create an encrypted text file, which is saved in a specified path, which can then be decrypted in the current app and read.
In the app: "MyCode.exe", add this code:
public void ReturnToOther()
{
string ToReturn = "MyString";
System.IO.File.WriteAllText("Path", Encrypt(ToReturn));
}
public String Encrypt(string ToEncrypt)
{
string Encrypted = null
char[] Array = ToEncrypt.ToCharArray();
for (int i = 0; i < Array.Length; i++)
{
Encrypted += Convert.ToString(Convert.ToChar(Convert.ToInt32(Array[i]) + 15));
}
return Encrypted;
}
In the app you are making now:
public void GetString()
{
string STR = Decrypt(System.IO.File.ReadAllText("Path"));
Console.WriteLine("The string is: {0}", STR);
}
// If you want to keep this running before the file exists, use this:
/*
public void GetString()
{
for(int i = 0; i > -1; ++i)
{
if(System.IO.File.Exists("Path"))
{
string STR = Decrypt(System.IO.File.ReadAllText("Path"));
Console.WriteLine("The string is: {0}", STR);
break;
}
else
{
//Do something if you want
}
}
} */
public String Decrypt(string ToDecrypt)
{
string Decrypted = null
char[] Array = ToDecrypt.ToCharArray();
for (int i = 0; i < Array.Length; i++)
{
Decrypted += Convert.ToString(Convert.ToChar(Convert.ToInt32(Array[i]) - 15));
}
return Decrypted;
}
Idea 2:
Use TCP to upload the string to a port, e.g. LocalHost (127.0.0.1), and then receive the string on the app you are developing, using a TCP Listener
An article on TCP - http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.aspx
Hope this helps :)
EDIT:
Have a look at Sockets too: http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.aspx

CredUIPromptForCredentials from .NET with SecureString

I'd like to show the standard system dialog to ask the user for an account username and password to use this information to start a process with these credentials.
I've been pointed to the CredUIPromptForCredentials function that shows that dialog. It returns username and password as string. But the ProcessStartInfo structure expects a password as SecureString.
I understand that I could now use the password as string and convert it to a SecureString character by character (there's no single function for that) - but it would defeat the idea behind the SecureString entirely.
So I guess there must be some way to directly accept the password from the unmanaged call to CredUIPromptForCredentials as SecureString in .NET. After all, I really don't need to access the password in my application in any way. It's just supposed to be used to start another process and can then be forgotten as soon as possible.
So how would my P/Invoke declaration for CredUIPromptForCredentials look like with a SecureString? (I've started with the one from pinvoke.net for C#.)
Update: Oh, and if somebody has an example for the new function CredUIPromptForWindowsCredentials in Windows Vista/7, that would be cool as well, because I can't even figure out how to use that at the moment.
You can cast the IntPtr of an unmanaged string buffer to char* and use the SecureString(char*, int) constructor.
// somehow, we come into posession of an IntPtr to a string
// obviously, this would be a foolish way to come into it in
// production, since stringOriginalContents is already in managed
// code, and the lifetime can therefore not be guaranteed...
var stringOriginalContents = "foobar";
IntPtr strPtr = Marshal.StringToHGlobalUni(stringOriginalContents);
int strLen = stringOriginalContents.Length;
int maxLen = 100;
// we copy the IntPtr to a SecureString, and zero out the old location
SecureString ssNew;
unsafe
{
char* strUPtr = (char*)strPtr;
// if we don't know the length, calculate
//for (strLen = 0; *(strUPtr + strLen) != '\0'
// // stop if the string is invalid
// && strLen < maxLen; strLen++)
// ;
ssNew = new SecureString((char*)strPtr, strLen);
// zero out the old memory and release, or use a Zero Free method
//for (int i = 0; i < strLen; i++)
// *(strUPtr + i) = '\0';
//Marshal.FreeHGlobal(strPtr);
// (only do one of these)
Marshal.ZeroFreeGlobalAllocUnicode(strPtr);
}
// now the securestring has the protected data, and the old memory has been
// zeroed, we can check that the securestring is correct. This, also should
// not be in production code.
string strInSecureString =
Marshal.PtrToStringUni(
Marshal.SecureStringToGlobalAllocUnicode(ssNew));
Assert.AreEqual(strInSecureString, stringOriginalContents);

How to securely save username/password (local)?

I'm making a Windows application, which you need to log into first.
The account details consist of username and password, and they need to be saved locally.
It's just a matter of security, so other people using the same computer can't see everyone's personal data.
What is the best/most secure way to save this data?
I don't want to use a database, so I tried some things with Resource files.
But since I'm kind of new with this, I'm not entirely sure of what I'm doing and where I should be looking for a solution.
If you are just going to verify/validate the entered user name and password, use the Rfc2898DerivedBytes class (also known as Password Based Key Derivation Function 2 or PBKDF2). This is more secure than using encryption like Triple DES or AES because there is no practical way to go from the result of RFC2898DerivedBytes back to the password. You can only go from a password to the result. See Is it ok to use SHA1 hash of password as a salt when deriving encryption key and IV from password string? for an example and discussion for .Net or String encrypt / decrypt with password c# Metro Style for WinRT/Metro.
If you are storing the password for reuse, such as supplying it to a third party, use the Windows Data Protection API (DPAPI). This uses operating system generated and protected keys and the Triple DES encryption algorithm to encrypt and decrypt information. This means your application does not have to worry about generating and protecting the encryption keys, a major concern when using cryptography.
In C#, use the System.Security.Cryptography.ProtectedData class. For example, to encrypt a piece of data, use ProtectedData.Protect():
// Data to protect. Convert a string to a byte[] using Encoding.UTF8.GetBytes().
byte[] plaintext;
// Generate additional entropy (will be used as the Initialization vector)
byte[] entropy = new byte[20];
using(RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
{
rng.GetBytes(entropy);
}
byte[] ciphertext = ProtectedData.Protect(plaintext, entropy,
DataProtectionScope.CurrentUser);
Store the entropy and ciphertext securely, such as in a file or registry key with permissions set so only the current user can read it. To get access to the original data, use ProtectedData.Unprotect():
byte[] plaintext= ProtectedData.Unprotect(ciphertext, entropy,
DataProtectionScope.CurrentUser);
Note that there are additional security considerations. For example, avoid storing secrets like passwords as a string. Strings are immutable, being they cannot be notified in memory so someone looking at the application's memory or a memory dump may see the password. Use SecureString or a byte[] instead and remember to dispose or zero them as soon as the password is no longer needed.
I have used this before and I think in order to make sure credential persist and in a best secure way is
you can write them to the app config file using the ConfigurationManager class
securing the password using the SecureString class
then encrypting it using tools in the Cryptography namespace.
This link will be of great help I hope : Click here
I wanted to encrypt and decrypt the string as a readable string.
Here is a very simple quick example in C# Visual Studio 2019 WinForms based on the answer from #Pradip.
Right click project > properties > settings > Create a username and password setting.
Now you can leverage those settings you just created. Here I save the username and password but only encrypt the password in it's respectable value field in the user.config file.
Example of the encrypted string in the user.config file.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<userSettings>
<secure_password_store.Properties.Settings>
<setting name="username" serializeAs="String">
<value>admin</value>
</setting>
<setting name="password" serializeAs="String">
<value>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAQpgaPYIUq064U3o6xXkQOQAAAAACAAAAAAAQZgAAAAEAACAAAABlQQ8OcONYBr9qUhH7NeKF8bZB6uCJa5uKhk97NdH93AAAAAAOgAAAAAIAACAAAAC7yQicDYV5DiNp0fHXVEDZ7IhOXOrsRUbcY0ziYYTlKSAAAACVDQ+ICHWooDDaUywJeUOV9sRg5c8q6/vizdq8WtPVbkAAAADciZskoSw3g6N9EpX/8FOv+FeExZFxsm03i8vYdDHUVmJvX33K03rqiYF2qzpYCaldQnRxFH9wH2ZEHeSRPeiG</value>
</setting>
</secure_password_store.Properties.Settings>
</userSettings>
</configuration>
Full Code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Security;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace secure_password_store
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Exit_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void Login_Click(object sender, EventArgs e)
{
if (checkBox1.Checked == true)
{
Properties.Settings.Default.username = textBox1.Text;
Properties.Settings.Default.password = EncryptString(ToSecureString(textBox2.Text));
Properties.Settings.Default.Save();
}
else if (checkBox1.Checked == false)
{
Properties.Settings.Default.username = "";
Properties.Settings.Default.password = "";
Properties.Settings.Default.Save();
}
MessageBox.Show("{\"data\": \"some data\"}","Login Message Alert",MessageBoxButtons.OK, MessageBoxIcon.Information);
}
private void DecryptString_Click(object sender, EventArgs e)
{
SecureString password = DecryptString(Properties.Settings.Default.password);
string readable = ToInsecureString(password);
textBox4.AppendText(readable + Environment.NewLine);
}
private void Form_Load(object sender, EventArgs e)
{
//textBox1.Text = "UserName";
//textBox2.Text = "Password";
if (Properties.Settings.Default.username != string.Empty)
{
textBox1.Text = Properties.Settings.Default.username;
checkBox1.Checked = true;
SecureString password = DecryptString(Properties.Settings.Default.password);
string readable = ToInsecureString(password);
textBox2.Text = readable;
}
groupBox1.Select();
}
static byte[] entropy = Encoding.Unicode.GetBytes("SaLtY bOy 6970 ePiC");
public static string EncryptString(SecureString input)
{
byte[] encryptedData = ProtectedData.Protect(Encoding.Unicode.GetBytes(ToInsecureString(input)),entropy,DataProtectionScope.CurrentUser);
return Convert.ToBase64String(encryptedData);
}
public static SecureString DecryptString(string encryptedData)
{
try
{
byte[] decryptedData = ProtectedData.Unprotect(Convert.FromBase64String(encryptedData),entropy,DataProtectionScope.CurrentUser);
return ToSecureString(Encoding.Unicode.GetString(decryptedData));
}
catch
{
return new SecureString();
}
}
public static SecureString ToSecureString(string input)
{
SecureString secure = new SecureString();
foreach (char c in input)
{
secure.AppendChar(c);
}
secure.MakeReadOnly();
return secure;
}
public static string ToInsecureString(SecureString input)
{
string returnValue = string.Empty;
IntPtr ptr = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(input);
try
{
returnValue = System.Runtime.InteropServices.Marshal.PtrToStringBSTR(ptr);
}
finally
{
System.Runtime.InteropServices.Marshal.ZeroFreeBSTR(ptr);
}
return returnValue;
}
private void EncryptString_Click(object sender, EventArgs e)
{
Properties.Settings.Default.password = EncryptString(ToSecureString(textBox2.Text));
textBox3.AppendText(Properties.Settings.Default.password.ToString() + Environment.NewLine);
}
}
}
DPAPI is just for this purpose. Use DPAPI to encrypt the password the first time the user enters is, store it in a secure location (User's registry, User's application data directory, are some choices). Whenever the app is launched, check the location to see if your key exists, if it does use DPAPI to decrypt it and allow access, otherwise deny it.
This only works on Windows, so if you are planning to use dotnet core cross-platform, you'll have to look elsewhere. See https://github.com/dotnet/corefx/blob/master/Documentation/architecture/cross-platform-cryptography.md
For simple scenarios can also use Windows Credential Management API using C# wrapper CredentialManagement. It gives single place to store/retrieve passwords, easy to change.
https://stackoverflow.com/a/32550674/1129978

Howto save a password in the registry

I have a desktop application with a remote interface. The access to the remote interface is secured by a username and password.
What would be the best way to save these password securely, preferably in the registry?
If you do need to store an unhashed password, look at using the ProtectedData class. This makes use of the Data Protection API (DPAPI) which is the best way of securing data on Windows.
Here's a little class that wraps ProtectedData and provides two extension methods on String to Encrypt and Decrypt data:
public static class DataProtectionApiWrapper
{
/// <summary>
/// Specifies the data protection scope of the DPAPI.
/// </summary>
private const DataProtectionScope Scope = DataProtectionScope.CurrentUser;
public static string Encrypt(this string text)
{
if (text == null)
{
throw new ArgumentNullException("text");
}
//encrypt data
var data = Encoding.Unicode.GetBytes(text);
byte[] encrypted = ProtectedData.Protect(data, null, Scope);
//return as base64 string
return Convert.ToBase64String(encrypted);
}
public static string Decrypt(this 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);
}
}
You would need to save the hashed password (be it in the registry or somewhere else). Then when the user enters their password you check the hashed version of what they enter with the hashed version as stored. If these match then the passwords match and you can let the user in.
This way you're not storing the password in plain text for anyone (including yourself) to get at and gain access as someone else.
As to which hash algorithm to use - I don't know. There are plenty to choose from, so I'm reluctant to recommend one blind. I'd suggest you find several and evaluate them. CSharpFriends has an article which looks like it might be a good starting point.

Categories

Resources