UWP - Cross Device Data Encryption - c#

My UWP app stores data in encrypted form in local SQLite database on the device. I use Windows.Security.Cryptography.DataProtection classes for static data and also data streams encryption/decryption (Ref: https://learn.microsoft.com/en-us/windows/uwp/security/cryptography)
I have provided OneDrive data backup facility with the idea that the user can backup entire database to OneDrive from one device and restore it in the app installed on another device. This may help the user use the app on multiple devices and also in case the user acquires a new device.
I use "LOCAL=user" Descriptor for the DataProtectionProvider class (Ref: https://learn.microsoft.com/en-us/uwp/api/windows.security.cryptography.dataprotection.dataprotectionprovider)
I was hoping that if I login using my Microsoft Account on two different devices and I encrypt data on one device, then restore data on other then the data should get decrypted; however this is not happening.
I was unable to get any documentation as well (apart from the references listed above). I searched SO as well for MS Support but no luck. Can somebody help me with this?
My requirement: Data encrypted on one (Windows) device should be decrypted in other (Windows) device (when a user is logged in using same Microsoft Account on both the devices).
[UPDATE]
Here's the code sample:
const BinaryStringEncoding encoding = BinaryStringEncoding.Utf8;
const string strDescriptor = "LOCAL=user";
public static async Task<string> ProtectTextAsync(string strClearText)
{
DataProtectionProvider Provider = new DataProtectionProvider(strDescriptor);
IBuffer buffMsg = CryptographicBuffer.ConvertStringToBinary(strClearText, encoding);
IBuffer buffProtected = await Provider.ProtectAsync(buffMsg);
return CryptographicBuffer.EncodeToBase64String(buffProtected);
}
public static async Task<String> UnprotectTextAsync(string strProtected)
{
DataProtectionProvider Provider = new DataProtectionProvider();
IBuffer buffProtected = CryptographicBuffer.DecodeFromBase64String(strProtected);
IBuffer buffUnprotected = await Provider.UnprotectAsync(buffProtected);
String strClearText = CryptographicBuffer.ConvertBinaryToString(encoding, buffUnprotected);
return strClearText;
}
The code is trivial; however, the process of error reproduction is important and is as follows:
I run the App on my Windows 10 Mobile (OS build: 10.0.14393.1770) then Backup data on OneDrive. My mobile shows that I am using a Microsoft Account (say NP3#msft.com) at Settings-->Accounts-->Your Info.
Now, I log-in to my Windows 10 Laptop (OS build: 15063.674 version: 1703 with Fall Creators Update SDK only applied) using NP3#msft.com account when I run the App and Restore the Backup from OneDrive.
Now, when I try to access the data, I get the error in IBuffer buffUnprotected = await Provider.UnprotectAsync(buffProtected); line of the UnprotectTextAsync method. The error is:
System.Exception: 'The specified data could not be decrypted. (Excep_FromHResult 0x8009002C)'
Please note that if I restore data backed-up on OneDrive from the same device (Mobile or Laptop), then this code works fine. So Backup/Restore functionality is working correctly with no data modification.

I'll try to keep it brief but there are a few ways you can go about this, first let's talk about the UWP storage first.
The UWP provides APIs to store user preferences and settings along with data in Three types of storage:
Local: This is basically storing data as application data in the local storage of the device itself. What can you store here? It's for all sorts of data that can be serialized. It shouldn't be too heavy else it'll throw you an Access Violation Exception. I once used it to store image as byte streams as well so it provides quite much of flexibility when it comes to storage.
PasswordVault: This is generally to store user credentials across multiple devices so that the use doesn't have to sign in to your app on every device, if you have the same Microsoft account, it'll log you in right away. You won't need to explicitly encrypt data inside it since the APIs automatically encrypt the data for you while transferring and storing the data across devices.
Roaming: Now this is what you'll be most interested in. Roaming settings are the ones that get transferred across device if you're signed in with the same Microsoft account. The data wouldn't be implicitly encrypted so you might will have to handle the security aspects for it. It's generally used to transfer Settings for the App and the Preferences for the user if he/she has something (e.g. Application Theme, Wallpaper). Windows 10 OS Utilizes this storage to transfer all sorts of stuff when you install windows 10 on another machine you can find a comprehensive list here. It's just amazing.
Finding the best Fit:
Now that We've had a look at our options, let's try to solution-ate your issue, and how to pick what storage.
Since you have to transfer data over multiple devices, the Local storage is out of question. Now we have two options left PasswordVault and RoamingStorage / RoamingSettings.
The question is, what do you want to transfer (for which you use one drive), is it just a bunch of preferences? or is it file(s) of varied sizes? or is it user credentials?
If it's user credentials, PasswordVault is the ideal fit. It'll not only handle DataTransfer but also provide seamless integrated signIn across devices if the user is using the same Microsoft Account.
If it's just a bunch of preferences, then use RoamingSettings. They'll transfer the data to the other devices using Microsoft's own APIs and all you have to do is, fetch them from the RoamingStorage container and you can start using the data.
But if it's a bunch of files, encrypted and stored on one drive and you want to decrypt on other devices below is a solution that I recommend.
Reading files from oneDrive, Decryption on Other devices:
The approach could be quite simple, if you have files that are stored on one drive,
When the use logs in to the app for the first time, check if the roamSettings for that Microsoft account for your app is present or not, since it's not it'll return you a null. In such a case, create a RoamingStorage and proceed to step 2.
Create the keys that'll be needed for encryption. (explained in
detail in the next section below)
Now that you have the keys, you perform all operations to get the data that needs to be written into the files.
Encrypt the data using the keys for encryption and once the data is encrypted, write it into a file and upload it to oneDrive.
Store the keys (explained in the next section below) into roaming storage for that Microsoft Account.
Now when the user signs in to your app using another device, as in point 1, check if there exists any roamingSettings. Only this time it won't be null and you'll get the user's roamingSettings for the app into your other device. extract the stored key from there and keep it in a variable.
Download the files from oneDrive and read their contents as string.
Use the key stored in the variable (point 6) to decrypt the data of the file
Now you have the actual data, resume your application flow.
Quick Look at Encryption
Encryption is out of the scope of this question so I'll just explain a basic joist of it and if any help is needed, please use the comments section.
The above solution would also depend on the type of encryption you're using here, if its
Symmetric: If you're using symmetric (like AES), then you generate an encryption key and an InitializationVector (also called IV) on the first device as soon as the user logs in and store them in the RoamingSettings
Asymmetric: If you're using asymmetric (like RSA), you'll generate a set of keys publicKey and privateKey use the publicKey to encrypt the data and then store it on one drive and then store the privateKey into the roaming settings.
It's not recommended to share private keys over the network incase of Asymmetric encryption but, this is a little unconventional but you're using Microsoft's established APIs to transfer data (which they claim to be secure) so that'll reduce the risk.
Please do let me know if I've skipped out anything.
Edit from the comments:
To be honest, since you mentioned a single key you're talking about AES-256. Now if you don't want the developer to have access to the key, it's kinda a default, you would be using Cryptography APIs by Microsoft for the AES. So i in a way you would be calling an API that'll give you the key and you'll be calling another API that'll be encrypting the data. Most Importantly The API would be called at runtime so either ways the developer has no access to it.
But if your query is that the developer should not even know what kind of encryption and where is being stored then in that case I would recommend you use a Factory Pattern , where in you abstract out the implementation of the data that gets encrypted you just pass in the data, that, class handles all the creating of key, encryption of data and storing of the key to roaming and then returns the encrypted data.
References:
Store and retrieve settings and other app data
Credential locker (a.k.a PasswordVault)
Windows 10 roaming settings reference
Advanced Encryption Standard-AES
RSA

#region AES Encryption
public static async Task<bool> EncryptAesFileAsync(StorageFile fileForEncryption, string aesKey256, string iv16lenght)
{
bool success = false;
try
{
//Initialize key
IBuffer key = Convert.FromBase64String(aesKey256).AsBuffer();
var m_iv = Convert.FromBase64String(iv16lenght).AsBuffer();
SymmetricKeyAlgorithmProvider provider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesCbcPkcs7);
var m_key = provider.CreateSymmetricKey(key);
//secured data
IBuffer data = await FileIO.ReadBufferAsync(fileForEncryption);
IBuffer SecuredData = CryptographicEngine.Encrypt(m_key, data, m_iv);
await FileIO.WriteBufferAsync(fileForEncryption, SecuredData);
success = true;
}
catch (Exception ex)
{
success = false;
DialogHelper.DisplayMessageDebug(ex);
}
return success;
}
public static async Task<bool> DecryptAesFileAsync(StorageFile EncryptedFile, string aesKey256, string iv16lenght)
{
bool success = false;
try
{
//Initialize key
IBuffer key = Convert.FromBase64String(aesKey256).AsBuffer();
var m_iv = Convert.FromBase64String(iv16lenght).AsBuffer();
SymmetricKeyAlgorithmProvider provider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesCbcPkcs7);
var m_key = provider.CreateSymmetricKey(key);
//Unsecured Data
IBuffer data = await FileIO.ReadBufferAsync(EncryptedFile);
IBuffer UnSecuredData = CryptographicEngine.Decrypt(m_key, data, m_iv);
await FileIO.WriteBufferAsync(EncryptedFile, UnSecuredData);
success = true;
}
catch (Exception ex)
{
success = false;
DialogHelper.DisplayMessageDebug(ex);
}
return success;
}
#endregion

Related

read ssl private key from smartcard with c#

I have a smartcard with a card reader and I decide to implement a client certificate in the latter.
The private key being stored in the card and the public key is stored in the server.
The application scenario is something like this:
application send frames to the Linux server
Linux server answer with a ramdom number
application read private key from (smartcard or pem file) and encrypt received random number and send the result to the server.
server try to decrypt the sent encrypted string via public key (pem file stored in the server) => if succeed access is granted else access is denied.
In my application, there is a mode of certificate authentication (static file .pem) and also uses the private key (also static .pem). I used openssl-net functions such as FromPrivateKey(string pem, string password) and PrivateEncrypt(byte[] msg, RSA.Padding padding) for read private key and encrypt data to send to the server.
The problem that is needed, is that I have no a priori way to export my private key in my smartcard since my pem file.
So after much research I understood that I should use instead of these functions type functions: "ENGINE_load_private_key" with engine "pkcs11."
So I have seen several examples of openssl configuration (eg http://openssl.6102.n7.nabble.com/Private-Key-from-Windows-Cert-Store-td20720.html) with pkcs11 (opensc, engine_pkcs11. so etc. ..) the trouble is that these configurations are for Linux.
Indeed, my need is to develop a client application windows WPF (written in C #) that can read the private key from the smartcard or from a PEM file.

RSA (client side encryption/ server decryption)

This is a continuation of the project in this question, but without the Bouncy Castle.
So I decided to scrap Bouncy Castle (pity, I loved the name)
ANYWAY
I have a server and a client. the client needs to send a serialized object to the server, the server will then process this object.
It does this, however I'd like to add encryption to the process. But without storing a file or anything like that. the process needs to be session based(in a sense)
So, the client will request a key from the server, the server will generate a key pair and send a key to the client.
Client then uses this key to encrypt the object
string key = ASCIIEncoding.ASCII.GetString(RequestKey(tcpclnt));
var RsaClient =new RSACryptoServiceProvider(2048);
while (key.Length > 0) {
RsaClient.FromXmlString(key);
var transmit = ASCIIEncoding.ASCII.GetBytes(stringtosend);
var encrypted = RsaClient.Encrypt(transmit,false);
the server then receives these encrypted bytes and tries to decrypt them
raw = Receive(clientSocket);
byte[] r = TrimBytes(ASCIIEncoding.ASCII.GetBytes(raw),256);
var sdecrypted = ASCIIEncoding.ASCII.GetString(RsaServer.Decrypt(r, false));
But alas, the server can't do this. On Decryption it throws an error
Key does not exist.
So, my question is, what am I doing wrong?
Many thanks in advance for any help you can offer.
UPDATE
Altered the code in the server
var RSAKeyInfo = new RSACryptoServiceProvider(2048, new CspParameters(1)).ExportParameters(true);
New error
The parameter is incorrect
Whilst fine as an exercise in the use of cryptography, the use of basic cryptographic algorithms to build your own system for secure communication is a recipe for insecurity. For every weakness you address in your own system, there are likely 10 (or more!) that you won't even have thought of.
My strong suggestion therefore is to use SSL/TLS to secure your communications. This should provide all the security you need whilst also being straightforward to integrate as the .NET Framework's SslStream has the necessary functionality to operate as either the server or client side of the connection.
Doing this will also allow you to optionally use additional security mechanisms in the future, e.g. certificate based client authentication, with minimal additional effort.

MachineKey.Protect and MachineKey.Unprotect

I'm using .net 4.5 and MachineKey.Protect/MachineKey.Unprotect for encrypting and decrypting values. I'm wondering when we deploy the code to production where we'll have multiple servers, does the MachineKey.Protect/MachineKey.Unprotect works properly without synchronizing machine keys?
Here is the sample code for decrypt:
var bytes = Convert.FromBase64String(Token);
var decryValue = MachineKey.Unprotect(bytes, Purpose);
string plainText = Encoding.UTF8.GetString(decryValue);
Let me know your thoughts!
To unprotect data you'll need the same machine key that the one used to protect data. So if you need to unprotect data protected by another server, your servers must share the same machine key.

Ways around putting a password in code

I have a bit of code that needs to run with elevated privileges (more that I want the rest of my code running at).
I have my code that sets up the Impersonation working, but it requires a username, domain and password. As my code is in C#.net I know that the password can be found by anyone determined enough.
Is there a way to encrypt the password in my code? Or otherwise secure this password and still be able to pass it in?
Here is the code I am calling:
using (new Impersonator("UserNameGoesHere", "DomainNameGoesGere", "Password Goes Here"))
{
uint output;
NetUserAdd(AUTHENTICATION_SERVER, 1, ref userinfo, out output);
return output;
}
I would love an example that shows how to fix this to not show my password in plain text.
I am using Visual Studio 2008, .NET 3.5 SP1, and running on Windows Server 2003.
Vaccano,
I would recommend investigating the data protection API (DPAPI) for what you're attempting to achieve. It is considered part of the solution in many best practice approaches to reversibly storing passwords needed by applications.
A good article discussing the DPAPI (and other techniques + concerns) can be found here:
http://msdn.microsoft.com/en-us/magazine/cc164054.aspx
With C# 2.0, P/Invoking isn't even required; managed wrappers exist:
http://blogs.freshlogicstudios.com/Posts/View.aspx?Id=41ca5a99-ddc0-4d0a-9919-2ce10bf50c7e
I hope this helps!
You have multiple options here.
You can hash the password the very first time and store the hash to a file. Now the next time, you want to execute the code with elevated privileges, you need to accept/retype the password and re-compute the hash and match it with the stored hash. Only if it matches will you execute your code in elevation modes. You could hash using SHA. Please look at System.Crytography namespace for examples on hashing.
Second option is to encrypt the password using algorithms like AES. However you will need to have a key to do this and you will have to worry about securing this key.
Third option is to use DPAPI and encrypt the password but not worry about securing the keys - much easier option than 2.
I would recommend 1 if you do not mind re-entering the password every time the application starts. If that is not a possibility, I would suggest going with 3 and use DPAPI.
Here are some links to get you started.
1.http://www.obviex.com/samples/dpapi.aspx
2. http://www.obviex.com/samples/Encryption.aspx
You can use safe-config nuget package. Internally it uses data protection api to encrypt and decrypt data.
//Save some configuration data at folder data\temp\
var configManager = new ConfigManager()
.WithOptions(DataProtectionScope.CurrentUser)
.Set("password", "my-massword")
.AtFolder(#"data\temp\")
.Save();
...
//Load configuration data
var loadedValue = new ConfigManager()
.AtFolder(#"data\temp\")
.Load()
.Get<string>("password");

Best practices for encrypting and decrypting passwords? (C#/.NET)

I need to store and encrypt a password in a (preferably text) file, that I later need to be able to decrypt. The password is for another service that I use, and needs to be sent there in clear text (over SSL). This is not something I can change. What are best practices in this area? How can achieve some degree of protection of the password from malicious users?
My platform is WinForms with C#/.NET 3.5.
Thanks.
I am assuming that you want to encrypt the password as it will be on the users machine and they will (possibly) be able to find it and use it? If so you are basically screwed - no matter what you do, since it is in the users domain they will be able to get it and figure out the encryption and get the password for the encryption (remember that using Reflector - and it's clones - isn't out of the reach of most) and decrypt it and they have it. In short all you are doing is obfuscating the password, not securing it.
What I would recommend is actually move it out of the users control. For example put up a web service which communicates with the client and returns the password securely when requested. This also allows you to change the password, if needed in future as well as provides you with a way to validate legitimate users.
Why you need to decrypt the password? Usually a salted hash of the password is stored and compared. If you encrypt/decrypt the password you have the password as plain text again and this is dangerous. The hash should be salted to avoid duplicated hash if the some users have the same passwords. For the salt you can take the user name.
HashAlgorithm hash = new SHA256Managed();
string password = "12345";
string salt = "UserName";
// compute hash of the password prefixing password with the salt
byte[] plainTextBytes = Encoding.UTF8.GetBytes(salt + password);
byte[] hashBytes = hash.ComputeHash(plainTextBytes);
string hashValue = Convert.ToBase64String(hashBytes);
You can calculate the salted hash of the password and store that within your file. During the authentication you calculate the hash from the user entries again and compare this hash with the stored password hash.
Since it should be very difficult (its never impossible, always a matter of time) to get the plain text from a hash the password is protected from reading as plain text again.
Tip: Never store or send a password unencrypted. If you get a new password, encrypt is as soon as possible!
System.Security.Cryptography.ProtectedData in the System.Security assembly uses some Windows APIs to encrypt data with a password only it knows.
One possibly use of this would be to have a Windows service that actually does the operation requiring the password. The application that the user interacts with calls into the service via remoting or WCF. As long as the service used DataProtectionScope.CurrentUser and the service user is different from the logged on user, the password should be pretty safe.
This of course assumes that the users are running as limited users who cannot modify the service or run program as the service's user.
Because you are using WinForms and .Net, your code is going to be visible in MSIL - even if obfuscated, and therefore your decryption code is visible.
Who are you trying to hide the password from? Is the user of the app not supposed to know the password?
I think you are going to need to do some user validation, and I would be tempted to put keys to the decryption in a separate database and provide some other mechanism to get that out which should require authentication. That way you can get the decryption code out of the winforms app.
I would also suggest a separate service which runs to regularly change the encryption decryption keys and updates all passwords in the database.
Encrypted in AES if you must store it in a text file.
AES is better known as Rijndael in c#
http://www.obviex.com/samples/Encryption.aspx
Better place would be the registry, since it would protect other users of the machine getting to it.
Still not the best storing it anywhere that a user might be able to get to is dangerous a 1/2 way decent developer can load up your app in reflector and find your key.
Or there is System.Security.Cryptography.ProtectedData that someone else suggested.
The best you could do on a machine is create a certificate and encrypt/decrypt with it loaded and locked down in the machine's keystore. (Still have to deal with the certificate password being in your code)
I just implemented something like this for storing a user supplied password. I converted the encrypted result to a base 64 encoded string, so that I could easily store it in my application's user settings.
From your question, it seems that your malicious user is actually using your application, so this will only provide obfuscation. Though no key would be revealed through the use of Reflector, the plain text would be visible in a debugger.
static byte[] entropy = { 65, 34, 87, 33 };
public string Password
{
get
{
if (this.EncryptedPassword == string.Empty)
{
return string.Empty;
}
var encrypted = Convert.FromBase64String(this.EncryptedPassword);
var data = ProtectedData.Unprotect(encrypted, entropy, DataProtectionScope.CurrentUser);
var password = Encoding.UTF8.GetString(data);
return password;
}
set
{
if (value == string.Empty)
{
this.EncryptedPassword = string.Empty;
return;
}
var data = Encoding.UTF8.GetBytes(value);
var encrypted = ProtectedData.Protect(data, entropy, DataProtectionScope.CurrentUser);
var stored = Convert.ToBase64String(encrypted);
this.EncryptedPassword = stored;
}
}
Do not store the password as part of the code. Aside from the issues of decompilation and relying on security through obscurity, if you change the password you need to recompile and redistribution your application.
Store the password as a webservice or in a database that the application has access to. You're communicating with a service over the web, so you will be connected, after all.
One of the most important thing is the permissions on the file. Even if the content is encrypted you need to make sure that only the processes that need access to the file can read it.
Since you must send the password in unencrypted form over the network, there is nothing you can do to protect it 100%.
AES is good enough if you need to store locally, and talking about disasms, network sniffers etc is not particulary good contra-argument becuase the same thing can be done with any program (sure, ASM is harder then CIL but its a minior point).
Such password protecting is good enough to prevent casual pick up, not to prevent decoding by proffesionals.

Categories