RSA (client side encryption/ server decryption) - c#

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.

Related

UWP - Cross Device Data Encryption

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

Send encrypted Mail to LotusNotes from Intranet WebApp

Can someone give me a starting point on how to send an encypted mail from my C# .NET Application to a Lotus Notes inbox (in the company intranet)?
I requested a certificate and Notes User from our support.
But now I'm stuck. I read through this guide, and implemented the code but know the mails in my inbox do not have any content, but just a file named smime.p7m. So I am generally unsure if this is the right method.
Can you give me a hint to a tutorial or tell me the steps I need to do?
Or is the linked guide generally right and I goofed something up? In this case please leave a comment an I'll add my code.
Thank you very much in advance!
UPDATE 1 (26.08.16):
Here is what I'm now at so far:
System.Net.Mail.SmtpClient smtp = new System.Net.Mail.SmtpClient("smtp.services.companyname");
smtp.Credentials = new System.Net.NetworkCredential("NOTESUSER","password");
smtp.Send(message);
In Notes itself I ticket the checkbox for "Send my mails encrypted". The thought behind it was the following:
I assumed this way the Notes User passes the credentials to the Smtp Server and uses the usersettings.
The eMails get delivered, but are not encrypted.
Maybe you could try and break down things a bit further. What about sending an encrypted email from a basic mail client like Thunderbird to a person who will open it in her Notes client ?
The fundamental thing is that the recipient must have a private key symetric to the public key you used for encryption. In normal use, Domino does this very well as it comes with its own two-factors PKI : users can't sign in without their private key, which is stored on their workstation in a tiny (~3 ko) file named something like hername.id or user.id. The corresponding public key is for all to see, as it should, in the Domino Directory (names.nsf)
While based on standard RSA stuff, those usual pairs of keys are managed and deployed in ways very specific to Domino.
Now, it is perfectly possible for a user to import a private key issued by a third-party certification authority. I don't have the exact procedure at hand right now buy you'll find it in the help.nsf available to any Notes client.
But I wonder. You are inside the intranet, which means that you do have access to the Domino Directory, thus to the usual public key of the recipient. Your application will probably need its own user.id and it's more than likely that you'll need to have the 1352 hole punched in various firewalls. By the way, if it helps to alleviate any concern, by virtue of the aformentioned native PKI, it is very easy to encrypt communications on port 1352 from end to end.
Another option is as follow. The Domino server is also a web server. Sometimes this option is activated, sometimes not. If it is, or if you can make it happen, the directory is available as a web application. Zooming in on the public key of a user would require some tinkering and some HTML parsing but should be doable.
One last one for the road, although you may not like it : Domino is a very good platform for intranet applications, be it of the client-server persuasion or of the HTTP creed.
Okay, here is what I finally did:
Domino.NotesSession nSession = new Domino.NotesSession();
nSession.Initialize("secretpassword"); //password for the Notes User
Domino.NotesDatabase nDatabase = nSession.GetDatabase("SERVER", "names"); //Server and location of the names.nfs file
Domino.NotesDocument nDocument = nDatabase.CreateDocument();
NotesStream nStream;
nDocument.ReplaceItemValue("Subject", tmp.Subject);
nBody = nDocument.CreateMIMEEntity();
nStream = nSession.CreateStream();
nStream.WriteText(tmp.Body);
nBody.SetContentFromText(nStream , "text/HTML;charset=UTF-8", MIME_ENCODING.ENC_IDENTITY_7BIT);
nDocument.EncryptOnSend = true;
nDocument.Send(false, user.INS_EMAIL);
This creates a Notes Session with the latest Notes User logged in. So you install the Notes client on the Server, log in with the user and it works so far.

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.

How do I safely store database login and password in a C# application?

I have a C# application that needs to connect to an SQL database to send some data from time to time. How can I safely store the username and password used for this job?
There is a nice MSDN article about how to secure connection strings in .Net.
You might want to use protected configuration.
Use integrated Windows authentication whenever possible. It takes the onus off of your application and lets Windows handle it. Using Windows authentication instead of SQL authentication is considered a best practice.
Read this accepted answer: the best way to connect sql server (Windows authentication vs SQL Server authentication) for asp.net app
See also: http://www.mssqltips.com/sqlservertip/1831/using-windows-groups-for-sql-server-logins-as-a-best-practice/
And: http://www.greensql.com/content/sql-server-security-best-practices
Incidentally, if this is a "job" as implied by the question, it may be a great candidate for a simple Windows service or scheduled task, both of which can run in a specific security context (i.e. as a specific Windows user).
in your app.config or web.config and then you encrypt them using the .net encryption provider
for more info check here
http://msdn.microsoft.com/en-us/library/dx0f3cf2%28v=vs.80%29.aspx
Encrypting Configuration Information Using Protected Configuration
http://msdn.microsoft.com/en-us/library/53tyfkaw%28v=vs.80%29.aspx
You may want to look at the RijndaelManaged key, which is quite a secure symmetric encryption key. A good article on this information (and tutorial) can be found here;
http://www.obviex.com/samples/Encryption.aspx
Not sure about your exact requirements, but first and foremost, you have to encrypt the password.
Also, when transmitting such sensitive information, consider using a secured connection.
Store an encrypted version in your connection string and form the connection string programmatically after decrypting the password.
You could use any encryption mechanism of your choice - from trivial to complex.
you can use encryption and dyscryption algorithm for passwords and log your user information by who created user and what datetime it created and save this in database.
and even if someone update or edit log that information in database.
Code to Convert stirng into md5
using System.Text;
using System.Security.Cryptography;
public static string ConvertStringtoMD5(string strword)
{
MD5 md5 = MD5.Create();
byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(strword);
byte[] hash = md5.ComputeHash(inputBytes);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < hash.Length; i++)
{
sb.Append(hash[i].ToString("x2"));
}
return sb.ToString();
}

Why do I have to add the server SSL certificate if my client program is in Java and not when it is in C#?

If I use HttpsURLConnection in a Java program and try to open an URL starting with https:// I'll get an error message:
unable to find valid certification path to requested target
and the solution I found is to add the server certificate to the client certificate storage. But if I write a C# program that uses HttpWebRequest then I don't have to add anything anywhere.
So for me it looks like a C# client "just works" and a Java client only works after being tweaked with a hammer.
Why is an extra step required for a Java client? Can I somehow skip saving the certificate to the client storage of JVM?
HttpWebRequest will use Window's own certificate store to validate certificates, i.e. the same as IE. If your IE can validate the certificate correctly, either by having the certificate or a CA path back to a trusted root, then HttpWebRequest should accept the certificate OK.
In the Java case I suspect adding the server certificate itself is wrong, unless it's self-signed in which case you'll have no choice. You should add the CA path back to a trusted root instead - you can probably pull these certificates out of Windows's CA store or download them from the root CA's website if you need them.
I believe it is because C# uses the same HTTP client as MSIE, so it has a lot of pre-installed SSL certificates including one that your use. JVM has less certificates pre-installed.
By default, Java uses its own set of trust anchors (in the default truststore, see the JSSE Reference Guide).
If you want to use the Windows certificate store, you can use the Windows-ROOT keystore as a trust store.
A good source of information on this topic is the Leveraging Security in the Native Platform Using Java SE 6 Technology and Java Secure Socket Extension (JSSE) Reference Guide on the Oracle site.
If you want Java to use the Windows certificate store to validate certificates then you can specify the the following system properties on launch:
-Djavax.net.ssl.keyStoreType=Windows-MY -Djavax.net.ssl.trustStoreType=Windows-ROOT
If you want only one connection to use the Windows certificate store to validate certificates you can modify the following code to fit your needs:
KeyStore ks = KeyStore.getInstance("Windows-MY");
ks.load(null, null);
KeyStore ts = KeyStore.getInstance("Windows-ROOT");
ts.load(null, null);
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ts);
KeyManagerFactory kmf = KeyManagerFactory
.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, new char[0]);
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
URL url = new URL("https://some.web.site.org");
javax.net.ssl.HttpsURLConnection urlConnection =
(javax.net.ssl.HttpsURLConnection) url.openConnection();
urlConnection.setSSLSocketFactory(ctx.getSocketFactory());
urlConnection.connect();
try (InputStream in = urlConnection.getInputStream();) {
byte[] chunk = new byte[1024];
for (int len; (len = in.read(chunk)) > -1;) {
System.out.write(chunk, 0, len);
}
} finally {
urlConnection.disconnect();
}

Categories