Introduction and Background
In the previous posts, I had shown how you can use MonoDevelop IDE of Mono Project to get started programming C# applications on Linux environment and for the operating system I used Linux distro, Ubuntu operating system. However, since all of the topics are already covered and I am just skimming through the snippets and small portions of the data that I can share, this is another post in the series before I continue to write a guide for this, in a compiled form. In this post, I am going to talk about cryptographic support provided in Mono itself, for Ubuntu. However, you can always write your own compiled modules that run the cryptographic services and you can also write your own modules that represent the procedures and steps shown in the certified algorithms for cryptography. But, in this post, I will talk about the built-in classes and objects provided to you for these services.
I have also talked about security tweaks a lot before, and I would like you to read my previous posts about security in .NET framework too, A few tips for security in .NET framework. Since this is much more about Ubuntu and C# programming using Mono Project, I recommend that you read the previous posts in this series of articles.
- Guide for building C# apps on Ubuntu: MonoProject Introduction
- Guide for building C# apps on Ubuntu: Language quickies
- Guide for building C# apps on Ubuntu: Project files and output
So basically, this is another post in the series of Ubuntu programming using C# language, Mono Project has been a great tool for C# geeks. In this post, I am going to talk about the hashing algorithms, and what else Mono Project has for us!
Security APIs in Mono
No wonder Mono is influenced based on .NET’s philosophy and C# language, but still it lacks many things when it comes to the core APIs, such as security API. It does not have a full package of the APIs in it. For example, on .NET framework, the support has been increased to SHA256, SHA512 and more, whereas on Mono, there are not much flavors currently added and you only have to stick to either one of them provided, or you would have to manage the base algorithms and write your own implementation of the algorithms. Which, definitely, would be hard job! Until Mono introduces some new algorithms, let’s stick to the provided ones and learn about them, how to use them and what they can serve us with.
In Mono APIs, you get two namespaces for security algorithms. The algorithms can be for simple encryption and decryption or it may be for the password hashing purposes. Now, these two are different in many ways, however they are categorized under “Cryptography” in computer science.
- Encrypting/decrypting: is a process in which you encode the data in such a way, that a special secret key is required to bring the data back in its original form. It is used while securing the data from potential spywares, because each time you have to access the data, you need to pass a special secret key with it.
- Hashing: is a process, typically used for passwords, but is not only restricted to passwords. Hashing is a technique, in which data is encrypted, in such a way that it is impossible to be converted back to its original form.
Mono namespaces provide you with objects that allow you to work around with these functions and add a layer of security to your applications. Now, let us first of all, talk about password hashing and then we will get into the encryption and decryption techniques provided in Mono runtimes for developers.
During the article, I will only focus on the objects provided in System.Security.Cryptography
, however you can still use Mono.Security.Cryptography
, but the recommended one is the native .NET framework’s cryptography namespace.
Hashing the Passwords
Hashing the passwords has been widely used in every network based application, or online application. Hashing is a process that is not just restricted to the passwords, as I have already said, the hashing has been widely used to determine the file consistency. Most of the software packages are introduced with MD5 or SHA hash values, they are used to determine if the file is in its real form or if it has been tampered with on its way to your machine. This ensures that the software package that you are installing is actually the “safe” package and has not been mixed with any malware or spyware content. The code from open source communities, such as Ubuntu, Linux and other open-source projects are widely exposed to such attacks, and if you install such packages, they make expose your private data and even ask you for some revenue, that happens in cases of ransomware, Linux.Encoder.1 was one of such viruses, that encrypted the user data and then asked them to pay revenue to get their data back. However, hashing is a very simple task in .NET framework at least.
Usually, there are many algorithms provided in every framework that can be used in your applications, most commonly used are:
- MD5
- SHA-128
- SHA-256
- SHA-512
- So on…
Now, before I move any further, I should warn that you should never ever use MD5 for hashing the passwords. MD5 algorithm is very weak and a simple rainbow table attack would expose the passwords. In many cases, you should use SHA-128, or SHA-512. But the recommended one is SHA-256, because of the digest that it creates and the security that it has. I would personally recommend that you use SHA-256, if you want to store a small size of digest (hashed password string; in hex), otherwise, my personal advice is to store SHA-512.
The benefit of having SHA-512 over SHA-256, is that you can minimize the chances of collisions while generating the hashes for the passwords. A collision would typically occur when the hash results are similar for different values. The thing is that the hash function would return a hashed string
to a limited size, but it can get an input of any size. Bigger files of larger byte arrays may result in a collision. So, to overcome the collision you may want to generate a hash of bigger size.
Now, talking of hashing the passwords, let me share how to hash the passwords in C#. The procedure is actually similar, if you have a code for .NET on Windows, same would be used on Mono on Ubuntu. Have a look below:
public static string HashPassword(string message) {
using (var algo = new SHA256Managed ()) {
var bytes = System.Text.Encoding.UTF8.GetBytes (message);
var hashedBytes = algo.ComputeHash (bytes);
System.Text.StringBuilder builder = new System.Text.StringBuilder ();
foreach (byte bite in hashedBytes) {
builder.Append (bite.ToString("x2"));
}
return builder.ToString ();
}
}
So, basically, what I have done is that I have just used that algorithm and I have got what I was expecting from it. Now, the way we call it defines how we use it. In this sample, I will be calling it to write the hash of it, to the screen and nothing else.
Console.WriteLine ("Enter the string to work on:");
string message = Console.ReadLine ();
string hashedStr = Crypto.HashPassword (message);
Console.WriteLine ("Hashed string is: " + hashedStr);
Basically, we have already created the function that does the thing for us. So we are only calling it in this code. So, if I run the above code, it would be something like this…
Figure 1: Working of the hashing algorithm on the word, “Afzaal”.
You would store this hashed string
in your database when you want to save it. Never save the passwords or sensitive information that you do not want to get back in the actual form, in plain-text form.
Adding Some Salt to the Hash
Now since we are talking about hashing the passwords, it is necessary to add a specific string
text to the actual string, which acts as salt to the data. The procedure is very much simple and straightforward, you simply add extra string
to the actual string
and then find the hash for it. Where you add the salt is your choice, you can append it, prepend it, or insert it at the medians or what-so-ever, that is your choice.
HashPassword (password + salt);
HashPassword (salt + password);
HashPassword (salt + password + salt);
But only thing that you should consider is that you should use the same method to get the hash again, because if you calculate hash differently, their hash value would be different.
Figure 2: Demonstration of the hashing a string message using salt.
When to Use Hashing?
You can use the following list items to determine when to use hashing functions on your data.
- When you want to secure your data from potential sights.
- When your data is valuable only for comparison and not required in its raw form. Passwords are a good example of this type of data.
- When you want to check if the file system is tampered with.
References
If you want to learn more about hashing functions, you should go and read the following links:
- Security in .NET Framework
- System.Security.Cryptography namespace on MSDN
- SHA-2 on Wikipedia
Encryption and Decryption of Data
Now that we have already talked about the hashing of the passwords and the data, we can now continue to talk about the encryption and decryption of data in Mono using C#. Encryption and decryption techniques are used to hide the data from unwanted users. It can be shared with other users, and they can also view it, but any user who is not required to be using or viewing the information can be removed from the list of viewers.
Image courtesy: This image demonstrates how encryption and decryption is done.
Now we will talk about the coding practices in encryption and decryption. The plain-image, pseudocode and algorithm is very much easy, however, the coding in .NET environment is also very much easy. In the coming sections, you will be shown and taught how to use .NET objects, to perform security restrictions in your applications.
As far as the algorithms are concerned, just like in case of hashing, there are a lot of encryption and decryption algorithms: AES, Rijndael, DES etc. All of them are used, but there are some problems with the later ones and that is why AES algorithm is recommended. However, in my case, I will use Rijndael algorithm, you can change it to AES (and you should change it to AES, I am only using it for demonstration purposes!).
What we do is that we actually divide the process in a number of steps:
- Create the object for algorithm; Rijndael in this case.
- Case the memory stream to hold the data.
- Create a cryptostream for that memory stream.
- Create a stream writer/reader based on encryption or decryption process undergoing.
- Return the encrypted or decrypted text.
Each encryption algorithm would require you to pass a special “Key
” that would be used for encryption and decryption. The key is the backbone. Without that key, data cannot be converted back to its original form. That is why, keys are kept secretly, in safe places so that potential hackers cannot get to the data. So for demonstration, let’s use the IDE to write some code in it.
1. Encryption Function
First of all, let us write a function that encrypts the data as we mentioned in the steps above. A hash function would return an array of bytes, so we would define our custom function to do the same, so that later when working with the values, we can change the data in any form, or save it just the way that it is.
public static byte[] Encrypt(string data) {
byte[] bytes = null;
using (var rjndl = new RijndaelManaged ()) {
rjndl.Key = key;
rjndl.IV = iv;
using (MemoryStream stream = new MemoryStream ()) {
using (CryptoStream cStream = new CryptoStream
(stream, rjndl.CreateEncryptor(), CryptoStreamMode.Write)) {
using (StreamWriter writer = new StreamWriter (cStream)) {
writer.Write (data);
}
}
bytes = stream.ToArray ();
}
}
return bytes;
}
This function is enough, this would encrypt the data and would provide us with the bytes of the data, in encrypted form. We can then convert those bytes to string
, or save them in BLOB format or what-so-ever as required. I will demonstrate the usage in a later section, currently I just want to jump to the decryption part.
2. Decryption Function
As the name suggests, it is an inverse of the encryption function. The steps required are similar, only that we create a decryptor object for the cryptostream and then start reading the stream in a decryptor object using the same key that was used to encrypt the data in this bytes form. If you use a different key, results are “unknown”.
The following code does the thing for us:
public static string Decrypt (byte[] data) {
string message = null;
using (var rjndl = new RijndaelManaged ()) {
rjndl.Key = key;
rjndl.IV = iv;
using (MemoryStream stream = new MemoryStream (data)) {
using (CryptoStream cStream = new CryptoStream
(stream, rjndl.CreateDecryptor (), CryptoStreamMode.Read)) {
using (StreamReader reader = new StreamReader (cStream)) {
message = reader.ReadToEnd ();
}
}
}
}
return message;
}
We now have the counterpart of our encryption/decryption algorithm or service (call it what you like!). Now that we have both of our functions ready, we can now test the function and see if it works in our cases for encryption and decryption.
I am going to enter my name, and then I will get the encrypted text plus the decryption function would be executed to get the data back.
Following is the main function:
Console.WriteLine ("Enter the string to work on:");
string message = Console.ReadLine ();
Crypto.Setup ();
var encrypted = Crypto.Encrypt (message);
var decrypted = Crypto.Decrypt (encrypted);
string encryptedStr = null;
StringBuilder strBuilder = new StringBuilder ();
foreach (var b in encrypted) {
strBuilder.Append (b.ToString("x2"));
}
encryptedStr = strBuilder.ToString ();
Console.WriteLine ("Original text was '" +
message + "', it was encrypted to: \n" + encryptedStr);
Console.WriteLine ("Decrypted text is: " + decrypted);
The output of this program was:
Figure 4: Encryption and decryption function on “Afzaal Ahmad Zeeshan” string.
Pretty simple, right? :-) So, finally, we have encrypted and decrypted the text in Ubuntu using Mono Project…
Tips
- Consider changing the Rijndael to AES.
- Keep a strong key, use the provided functions to generate a “strong” random key.
- Decrypt when needed.
Using Rijndael or AES?
Rijndael and AES can be confusing somehow. Don’t worry, I was also confused as to which is better and which is not. The thing is, Rijndael algorithm was developed along with numerous other algorithms, to come on top as “best algorithm for encryption and decryption“. Rijndael won, and was selected as AES algorithm.
Does that make sense? It should… If that doesn’t, read this blog post.
Points of Interest
This is another post in the series of “Programming C# on Ubuntu” articles. In this, I have talked about cryptographic programming in Mono Project on Ubuntu. The services are similar to what we have in .NET framework on Windows operating system. However, there are some other namespaces provided by Mono itself, but still, .NET namespaces rule them out. The services that you can find in .NET are amazing, and C# language itself is just perfect language to be used for any project! I am writing this guide, to share the beauty of C# on cross-platform environments too, for those who are unaware of this currently.
In this post, you were given a few tips and you were shown how to perform cryptographic functions on your data, including hashing the passwords, encrypting and decrypting the data on your machine. Cryptography can greatly influence your application’s performance, and your users would like the privacy and other services that you have for them, such as encryption and decryption of the data, using which they can save their data from unwanted users, and yes, hackers!
In a later post, I will talk about NuGet package managements, and then I will head over to writing a guide, in the form of a book itself. See you in the later posts. :-)