I want to generate a cypher text by using DpapiProtectedConfigurationProvider.
All the codes I am seeing on the internet are do this inside a app.config. I know it is the reason this is originally build for. But I have a different usage. I have interface where user has to enter the text in a textbox and with a a click of button I need to generate the cpher text by using DpapiProtectedConfigurationProvider. How to achieve this?
Currently I am generating this inside the app.config by using following code. But this is not what I want
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
//Configuration config = ConfigurationManager.OpenExeConfiguration(exefilePath);
ConfigurationSection section = config.GetSection(sectionKey);
if (section != null)
{
if (section.ElementInformation.IsLocked)
{
Console.WriteLine("Section: {0} is locked", sectionKey);
}
else
{
if (!section.SectionInformation.IsProtected)
{
//%windir%\system32\Microsoft\Protect\S-1-5-18
section.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");
section.SectionInformation.ForceSave = true;
Console.WriteLine("Encrypting: {0} {1}", section.SectionInformation.Name, section.SectionInformation.SectionName);
}
else
{ // display values for current config application name value pairs
//
section.SectionInformation.UnprotectSection();
section.SectionInformation.ForceSave = true;
Console.WriteLine("Decrypting: {0} {1}", section.SectionInformation.Name, section.SectionInformation.SectionName);
}
}
}
else
{
Console.WriteLine("Section: {0} is null", sectionKey);
}
//
config.Save(ConfigurationSaveMode.Full);
Console.WriteLine("Saving file: {0}", config.FilePath);
How I do this?
The DpapiProtectedConfigurationProvider class "uses the Windows built-in cryptographic services and can be configured for either machine-specific or user-account-specific protection."
Depending on the flags used, data encrypted using DPAPI can only be decrypted by code running on the same machine where it was encrypted, or code running under the same user account where it was encrypted.
The precise algorithm used may vary depending on the version of Windows being used. From what I can see, the CryptProtectData function uses either 3DES or AES256:
c# - Which encryption algorithm does the ProtectData class use? - Stack Overflow
c# - Which Encryption algorithm does ProtectedData use? - Stack Overflow
Related
I want to block access to certain apps on my computer. I used the gpedit.msc tool on the computer in the category: dont run specific windows application.
I am now looking for a .netcore C # algorithm that can automatically block an app in gpedit.msc
i use this code:
public static class GPAwareHelper
{
private const String REG_PATH =
"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer";
public static Object GetGPOverride(
String keyName, Object configValue)
{
Object keyValue = null;
RegistryKey demoKey = null;
//if (isHKLM)
// // open named key in HKEY_LOCAL_MACHINE section
// demoKey = Registry.LocalMachine.OpenSubKey(REG_PATH);
//else
// // open named key in HKEY_CURRENT_USER section
demoKey = Registry.CurrentUser.OpenSubKey(REG_PATH);
if (demoKey != null)
{
// get the specified value from this key
keyValue = demoKey.GetValue(keyName);
demoKey.Close();
// check that a value was found and, if not, return `enter code here`
// the value provided in method parameters
if (keyValue != null)
{
return keyValue;
}
else
return configValue;
}
else
{
// key not found, so return value provided
// in method parameters
return configValue;
}
}
Group Policies are registry entries. Just write those registry entries with .netcore.
You can block certain apps by adding keys in
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies
Here's a good introduction.
To write registry entries with dotnet core you have to add the package Microsoft.Win32.Registry
dotnet add package Microsoft.Win32.Registry
I've written a C# piece that encrypts/decrypts a string using RtlEncryptMemory/RtlDecryptMemory. This string is then saved in a config file, it all works well but the problem is that once I logoff/logon, I can no longer decrypt the string. I am using the RTL_ENCRYPT_OPTION_SAME_LOGON option which means the internal mechanism uses something from the Windows session in order to perform the decryption. I am looking for a solution that works in the same manner but is tied to the network user (or token, etc...). Is Windows providing something already?
My goal is to be able to decrypt the string from anywhere as long as the process is running under the same user (network credentials). I also do not want to have the user type in a password or use an internal value as that could be compromised. Ideally it would be just like the RTL functions but provide an RTL_ENCRYPT_OPTION_SAME_USER option.
You want to use the DataProtection API
Here is a simple implementation that adds Encrypt and Decrypt string extensions...
public static class StringExtensions
{
public static string Encrypt(this string s)
{
if (String.IsNullOrEmpty(s))
{
return s;
}
else
{
var encoding = new UTF8Encoding();
byte[] plain = encoding.GetBytes(s);
byte[] secret = ProtectedData.Protect(plain, null, DataProtectionScope.CurrentUser);
return Convert.ToBase64String(secret);
}
}
public static string Decrypt(this string s)
{
if (String.IsNullOrEmpty(s))
{
return s;
}
else
{
byte[] secret = Convert.FromBase64String(s);
byte[] plain = ProtectedData.Unprotect(secret, null, DataProtectionScope.CurrentUser);
var encoding = new UTF8Encoding();
return encoding.GetString(plain);
}
}
}
Here is an example...
class Program
{
static void Main(string[] args)
{
string password = "Monkey123";
string encrypted = password.Encrypt();
Console.WriteLine($"Encrypted password = '{encrypted}'");
string decrypted = encrypted.Decrypt();
Console.WriteLine($"Decrypted password = '{decrypted}'");
}
}
Which produces this output...
Encrypted password = 'AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAA/6wDgM21DkStrNJQ35QDiwAAAAACAAAAAAAQZgAAAAEAACAAAAAPr3/aqafbt/RRoPVe75b+PFBhE6h9MLcQ2Ivsd3adOwAAAAAOgAAAAAIAACAAAABYxqEdzotL+7qXpWnbbpPRkfWZF6oh/meFsXzFtLPnrBAAAAB59VGbboP4Tye1N3dB7E3jQAAAAMQn8cAlnTDe1mwDEJriADizdT2Qr0DtPgpMje+rbjdkVpL+cKiEQs4om4i1hlLPgPn5MG5oVWFFnxU0d4c9TFg='
Decrypted password = 'Monkey123'
Notes:
Only the currently logged in user can decrypt the data encrypted with this code. This works across the network as long as the current user has a roaming profile.
Alternatively the scope can be local machine in which case only users logged in to the same machine can decrypt the data.
This is .NET Core 3.1 code and works only on Windows machines
Using statements...
using System;
using System.Security.Cryptography;
using System.Text;
You should not be using RtlEncryptMemory if you want to store the string, it is meant to only keep strings secure inside the running applications memory, it therefore can be stored/serialized and decrypted.
Have a look at DPAPI password encryption I think it should meet your needs.
I have a Nuget package you might like:
DataJuggler.Net.Cryptography .Net Framework
DataJuggler.Core.Cryptography Dot Net Core
Pretty simple to work with, here is a live demo:
https://blazorcrypto.datajuggler.com/
Source code and video link is available above also.
Usage:
Encryption:
// get the encryptedText
encryptedResult = CryptographyHelper.EncryptString(textToEncrypt, keyCode);
Decryption:
// get thedecryptedText
decryptedResult = CryptographyHelper.DecryptString(textToDecrypt, keyCode);
It also includes password hashing.
Let me know if you think it is worth the price of free.
I have developed an C# win forms application in Visual Studio 2010 and to provide security to it I am generating a machine dependent key by using systems cpuId, biosId, diskId. It looks like
Now in Setup I am just getting one key input area like below.
and I want to show the machine key which is created for the specific system, above the serial key input area.
My need is that the end user or buyer of the Software call me and give me the machine key and then I will calculate a key using that key and send back to client or buyer.
This is my first setup project so I am totally unaware of this thing. I will really appreciate your humble response.
I like to break your question into two parts
Creating a UI with required fields or controls where user can provide the license key
There are two way to get the user input during the installation,
Creating a windows form with required controls to get the input(You can not open windows form as a modal pop up during the installation)
Creating a .wid file to get the user input(This would be the recommended approach)
Validating the license Key and aborting the installation when invalid key is used
Once you have got the user input during the installation you have to validate it, You can use Installer Class for this.
Install() method example
public override void Install(System.Collections.IDictionary stateSaver)
{
//Invoke the base class method
base.Install(stateSaver);
if (!keyEnteredByUser.Equals(generatedKey))
{
//This would abort the installation
throw new Exception("Invalid Key");
}
}
I think better you should take look in this Article.
In that he have taken the same way to generating the unique key as per the system. And the way to generate the unique key is follows.
public static string GetSystemInfo(string SoftwareName)
{
if (UseProcessorID == true)
SoftwareName += RunQuery("Processor", "ProcessorId");
if (UseBaseBoardProduct == true)
SoftwareName += RunQuery("BaseBoard", "Product");
if (UseBaseBoardManufacturer == true)
SoftwareName += RunQuery("BaseBoard", "Manufacturer");
// See more in source code
SoftwareName = RemoveUseLess(SoftwareName);
if (SoftwareName.Length < 25)
return GetSystemInfo(SoftwareName);
return SoftwareName.Substring(0, 25).ToUpper();
}
private static string RunQuery(string TableName, string MethodName)
{
ManagementObjectSearcher MOS =
new ManagementObjectSearcher("Select * from Win32_" + TableName);
foreach (ManagementObject MO in MOS.Get())
{
try
{
return MO[MethodName].ToString();
}
catch (Exception e)
{
System.Windows.Forms.MessageBox.Show(e.Message);
}
}
return "";
}
And following method which describes how to generate the password code which matches the unique key ,
static public string MakePassword(string st, string Identifier)
{
if (Identifier.Length != 3)
throw new ArgumentException("Identifier must be 3 character length");
int[] num = new int[3];
num[0] = Convert.ToInt32(Identifier[0].ToString(), 10);
num[1] = Convert.ToInt32(Identifier[1].ToString(), 10);
num[2] = Convert.ToInt32(Identifier[2].ToString(), 10);
st = Boring(st);
st = InverseByBase(st, num[0]);
st = InverseByBase(st, num[1]);
st = InverseByBase(st, num[2]);
StringBuilder SB = new StringBuilder();
foreach (char ch in st)
{
SB.Append(ChangeChar(ch, num));
}
return SB.ToString();
}
So when the user enters the correct password it will be stored in the user system and the next run it wont ask for the password.
public static void WriteFile(string FilePath, string Data)
{
FileStream fout = new FileStream(FilePath, FileMode.OpenOrCreate,
FileAccess.Write);
TripleDES tdes = new TripleDESCryptoServiceProvider();
CryptoStream cs = new CryptoStream(fout, tdes.CreateEncryptor(key, iv),
CryptoStreamMode.Write);
byte[] d = Encoding.ASCII.GetBytes(Data);
cs.Write(d, 0, d.Length);
cs.WriteByte(0);
cs.Close();
fout.Close();
}
So as you asked when the unique key generated , the user as to call you and read his code after based on the code you can generate the password as by above method .
But my point of view is different, this method is not good to collaborate with user. Its waste of time that user needs to call you for password. Better try some other method where user just need to click the link which makes project as full from trail. Anyway the above method will solve your question, I guess.
I suggest using an approach of symmetric or asymmetric encryption - that is direction you must look in to provide machine-based secret key generation. Look for its model in .NET.
Of course, if you want your application to be much more secured, you'll have to provide an activation server for it with client keyhashes database.
There are similar questions
How to Manage Key in a Symmetric Algorithm
Where to store a secret key to use in a SHA-1 hash?
My question is same, But I want to ask it differently
I have C# application. I am encrypting some data in the application. For encryption I am using secret key or password. This same thing is needed for decryption.
Where/how to store this secret key or password in application? its easy to view string password from reflection. I may use some combination to generate password, but some smart guys can guess that with some efforts.
Is there any secured way to store or manage secret password which is used in application to encrypt data?
I doubt there is any guaranteed secure way to store the key. Ultimately your program has to get access to the key, and a cracker could easily work out how that is happening via reverse engineering and redirect that string to wherever they want to.
Your best options are to:
Obfuscate the key as much as possible. This makes it more difficult to access the "secret key" but does not make it impossible (see above). Rather than storing it as a string, generate it using a function, or use a seed and pass that through a function to get the secret string.
If your use case allows it, use a public/private key pair. It only works if you want your application to encrypt the data, send it to your servers, and then you want to decrypt it. In this case, you embed the public key into the application (doesn't matter if crackers discover that), and keep the private key to yourself or your server.
If you store the key as an app-setting, and encrypt the app-settings, then I think you're pretty save.
You can use the following code to encrypt sections of the app.config.
using System;
using System.Configuration;
public static class ConfigurationEncryptor {
[Flags]
public enum ConfigurationSectionType {
ConnectionStrings = 1,
ApplicationSettings = 2
}
/// <summary>
/// Encrypts the given sections in the current configuration.
/// </summary>
/// <returns>True is the configuration file was encrypted</returns>
public static bool Encrypt(ConfigurationSectionType section) {
bool result = false;
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
if (config == null)
throw new Exception("Cannot open the configuration file.");
if (section.HasFlag(ConfigurationSectionType.ConnectionStrings)) {
result = result || EncryptSection(config, "connectionStrings");
}
if (section.HasFlag(ConfigurationSectionType.ApplicationSettings)) {
result = result || EncryptSection(config, "appSettings");
}
return result;
}
/// <summary>
/// Encrypts the specified section.
/// </summary>
/// <param name="config">The config.</param>
/// <param name="section">The section.</param>
private static bool EncryptSection(Configuration config, string section) {
ConfigurationSection currentSection = config.GetSection(section);
if (currentSection == null)
throw new Exception("Cannot find " + section + " section in configuration file.");
if (!currentSection.SectionInformation.IsProtected) {
currentSection.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");
config.Save();
// Refresh configuration
ConfigurationManager.RefreshSection(section);
return true;
}
return false;
}
}
And use it like this (e.g. in your Main() method):
ConfigurationEncryptor.Encrypt(
ConfigurationEncryptor.ConfigurationSectionType.ApplicationSettings |
ConfigurationEncryptor.ConfigurationSectionType.ConnectionStrings
);
How can I search for specific value in the registry keys?
For example I want to search for XXX in
HKEY_CLASSES_ROOT\Installer\Products
any code sample in C# will be appreciated,
thanks
In case you don't want to take a dependency on LogParser (as powerful as it is): I would take a look at the Microsoft.Win32.RegistryKey class (MSDN). Use OpenSubKey to open up HKEY_CLASSES_ROOT\Installer\Products, and then call GetSubKeyNames to, well, get the names of the subkeys.
Open up each of those in turn, call GetValue for the value you're interested in (ProductName, I guess) and compare the result to what you're looking for.
Help here...
Microsoft has a great (but not well known) tool for this - called LogParser
It uses a SQL engine to query all kind of text based data like the Registry,
the Filesystem, the eventlog, AD etc...
To be usable from C#, you need to build an Interop Assembly from the
Logparser.dll COM server using following (adjust LogParser.dll path)
command.
tlbimp "C:\Program Files\Log Parser 2.2\LogParser.dll"
/out:Interop.MSUtil.dll
Following is a small sample, that illustrates how to query for the Value
'VisualStudio' in the \HKLM\SOFTWARE\Microsoft tree.
using System;
using System.Runtime.InteropServices;
using LogQuery = Interop.MSUtil.LogQueryClass;
using RegistryInputFormat = Interop.MSUtil.COMRegistryInputContextClass;
using RegRecordSet = Interop.MSUtil.ILogRecordset;
class Program
{
public static void Main()
{
RegRecordSet rs = null;
try
{
LogQuery qry = new LogQuery();
RegistryInputFormat registryFormat = new RegistryInputFormat();
string query = #"SELECT Path from \HKLM\SOFTWARE\Microsoft where
Value='VisualStudio'";
rs = qry.Execute(query, registryFormat);
for(; !rs.atEnd(); rs.moveNext())
Console.WriteLine(rs.getRecord().toNativeString(","));
}
finally
{
rs.close();
}
}
}
This method will search a specified registry key for the first subkey that contains a specified value. If the key is found then the specified value is returned. Searchign is only one level deep. If you require deeper searching then I suggest modifying this code to make use of recursion. Searching is case-sensitive but again you can modify that if required.
private string SearchKey(string keyname, string data, string valueToFind, string returnValue)
{
RegistryKey uninstallKey = Registry.LocalMachine.OpenSubKey(keyname);
var programs = uninstallKey.GetSubKeyNames();
foreach (var program in programs)
{
RegistryKey subkey = uninstallKey.OpenSubKey(program);
if (string.Equals(valueToFind, subkey.GetValue(data, string.Empty).ToString(), StringComparison.CurrentCulture))
{
return subkey.GetValue(returnValue).ToString();
}
}
return string.Empty;
}
Example usage
// This code will find the version of Chrome (32 bit) installed
string version = this.SearchKey("SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall", "DisplayName", "Google Chrome", "DisplayVersion");
#Caltor your solution gave me the answer I was looking for. I welcome improvements or a completely different solution that does not involve the registry. I am working with enterprise applications on Windows 10 with devices joined to Azure AD. I want/need to use Windows Hello for devices and for HoloLens 2 in a UWP app. My problem has been getting the AAD userPrincipal name from Windows 10. After a couple days searching and trying lots of code I searched the Windows Registry for my AAD account in the Current User key and found it. With some research it appears that this information is in a specific key. Because you can be joined to multiple directories there may be more than one entry. I was not trying to solve that issue, that is done with the AAD tenant Id. I just needed the AAD userPrincipal name.
My solution de-dups the return list so that I have a list of unique userPrincipal names. App users may have to select an account, this is tolerable for even HoloLens.
using Microsoft.Win32;
using System.Collections.Generic;
using System.Linq;
namespace WinReg
{
public class WinRegistryUserFind
{
// Windows 10 apparently places Office/Azure AAD in the registry at this location
// each login gets a unique key in the registry that ends with the aadrm.com and the values
// are held in a key named Identities and the value we want is the Email data item.
const string regKeyPath = "SOFTWARE\\Classes\\Local Settings\\Software\\Microsoft\\MSIPC";
const string matchOnEnd = "aadrm.com";
const string matchKey = "Identities";
const string matchData = "Email";
public static List<string> GetAADuserFromRegistry()
{
var usersFound = new List<string>();
RegistryKey regKey = Registry.CurrentUser.OpenSubKey(regKeyPath);
var programs = regKey.GetSubKeyNames();
foreach (var program in programs)
{
RegistryKey subkey = regKey.OpenSubKey(program);
if(subkey.Name.EndsWith(matchOnEnd))
{
var value = (subkey.OpenSubKey(matchKey) != null)? (string)subkey.OpenSubKey(matchKey).GetValue(matchData): string.Empty;
if (string.IsNullOrEmpty(value)) continue;
if((from user in usersFound where user == value select user).FirstOrDefault() == null)
usersFound.Add(value) ;
}
}
return usersFound;
}
}
}