My requirement is that I need simple encryption/decryption methods in C# to encrypt and
decrypt an image (maybe gif/jpeg).Simple cause I have to store it in the database in a BLOB field andsome other developers in some other programming language(like java) may need to extract and display this image.I don't need much security cause its just a matter of "security by obscuring"(life).
Gulp..can someone help...
Since you "don't need much security" you can probably manage to get by with something like AES (Rijndael). It uses a symmetric-key and there is plenty of help in the .NET framework to make is easy to implement. There is plenty of info in MSDN on the Rijndael class that you might find helpful.
Here is a very stripped down example of encrypt / decrypt methods which can be used for working with byte arrays (binary contents)...
using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;
public class RijndaelHelper
{
// Example usage: EncryptBytes(someFileBytes, "SensitivePhrase", "SodiumChloride");
public static byte[] EncryptBytes(byte[] inputBytes, string passPhrase, string saltValue)
{
RijndaelManaged RijndaelCipher = new RijndaelManaged();
RijndaelCipher.Mode = CipherMode.CBC;
byte[] salt = Encoding.ASCII.GetBytes(saltValue);
PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, salt, "SHA1", 2);
ICryptoTransform Encryptor = RijndaelCipher.CreateEncryptor(password.GetBytes(32), password.GetBytes(16));
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, Encryptor, CryptoStreamMode.Write);
cryptoStream.Write(inputBytes, 0, inputBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] CipherBytes = memoryStream.ToArray();
memoryStream.Close();
cryptoStream.Close();
return CipherBytes;
}
// Example usage: DecryptBytes(encryptedBytes, "SensitivePhrase", "SodiumChloride");
public static byte[] DecryptBytes(byte[] encryptedBytes, string passPhrase, string saltValue)
{
RijndaelManaged RijndaelCipher = new RijndaelManaged();
RijndaelCipher.Mode = CipherMode.CBC;
byte[] salt = Encoding.ASCII.GetBytes(saltValue);
PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, salt, "SHA1", 2);
ICryptoTransform Decryptor = RijndaelCipher.CreateDecryptor(password.GetBytes(32), password.GetBytes(16));
MemoryStream memoryStream = new MemoryStream(encryptedBytes);
CryptoStream cryptoStream = new CryptoStream(memoryStream, Decryptor, CryptoStreamMode.Read);
byte[] plainBytes = new byte[encryptedBytes.Length];
int DecryptedCount = cryptoStream.Read(plainBytes, 0, plainBytes.Length);
memoryStream.Close();
cryptoStream.Close();
return plainBytes;
}
}
Look at the System.Security.Cryptography namespace.
Here is an article about encrypting data.
Your question is very general - the linked article gives you examples of encryption using the built in functions.
Related
I am looking for a ReactNative equivalent for the following C# Crypto methods. Basically, I am calling a C# API endpoint that requires Json calls to be encrypted. Its also sending back encrypted results using the same Cryptography. The C# methods where provided by my client.
I am fairly new to ReactNative as such I have been unable to successfully reproduced the methods in ReactNative.
I have looked at similar functions online such as one highlighted here but to no avail.
I will higly appreciate your help.
C# METHODS
public string EncryptFromDataObject(string jsonString)
{
byte[] initVectorBytes = Encoding.UTF8.GetBytes(MySecret.sInitVector);
byte[] plainTextBytes = Encoding.UTF8.GetBytes(jsonString);
PasswordDeriveBytes password = new PasswordDeriveBytes(MySecret.sPassPhrase, null);
byte[] keyBytes = password.GetBytes(MySecret.iKeySize / 8);
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes);
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] cipherTextBytes = memoryStream.ToArray();
memoryStream.Close();
cryptoStream.Close();
//string s = Convert.ToBase64String(cipherTextBytes); // base64 without padding
//s = s.PadRight(s.Length + (s.Length * 3) % 4, '='); // add padding
return Convert.ToBase64String(cipherTextBytes);
}
//Decrypt
public string DecryptToDataObject(string cipherDataObj)
{
byte[] initVectorBytes = Encoding.ASCII.GetBytes(MySecret.sInitVector);
byte[] cipherTextBytes = Convert.FromBase64String(cipherDataObj);
PasswordDeriveBytes password = new PasswordDeriveBytes(MySecret.sPassPhrase, null);
byte[] keyBytes = password.GetBytes(MySecret.iKeySize / 8);
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes);
MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
byte[] plainTextBytes = new byte[cipherTextBytes.Length];
int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
string jsonString = Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
return jsonString;
}
I actually managed though not by using the above C# class but used the implementation here.
I managed to encrypt from C# and decrypt using ReactNative and vise-versa. The only catch is to make sure that the iv value used in ReactNative is generated is obtained from C# code.
I use ECDiffieHellmanCng for exchange of public keys and then AES for encrypting/decrypting.
Sometimes the decryption works, other times I get the following error in decryption method: Padding is invalid and cannot be removed.
Where is the cause of this?
Here is the code:
private void Encryption(byte[] key, byte[] unencryptedMessage,out byte[] encryptedMessage, out byte[] iv) // encryption funkcija
{
using (Aes aes = new AesManaged())
{
aes.Key = key;
//aes.GenerateIV();
iv = aes.IV;
aes.Padding = PaddingMode.PKCS7;
// Encrypt the message
using (MemoryStream ciphertext = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ciphertext, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(unencryptedMessage, 0, unencryptedMessage.Length);
cs.Close();
}
encryptedMessage = ciphertext.ToArray();
}
}
}
private void Decryption(byte[] encryptedMessage, byte[] iv, out byte[] decryptedMessage)
{
using (Aes aes = new AesManaged())
{
aes.Key = receiversKey;
aes.IV = iv;
aes.Padding = PaddingMode.PKCS7;
// Decrypt the message
using (MemoryStream decryptedBytes = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(decryptedBytes, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(encryptedMessage, 0, encryptedMessage.Length);
cs.Close();
}
decryptedMessage = decryptedBytes.ToArray();
}
}
}
Since you're already using the same padding mode for both encryption and decryption, the most likely causes of invalid padding error are:
Different keys that are used for encryption and decryption.
Invalid encrypted message passed to Decryption() method. You could mistakenly pass an empty string or non-encrypted data.
If this does not help, please provide the code that calls Encryption() and Decryption() methods and handles the key used in both cases. It's required because those methods itself looks ok, the most likely problem is in passed arguments.
I am currently working on a project assigned by my teacher and I need to ensure the application it has strong encryption. Below is my encrypt method:
private String Encrypt(string text)
{
RijndaelManaged RijndaelCipher = new RijndaelManaged();
string Password = System.Configuration.ConfigurationManager.AppSettings["Password"];
byte[] PlainText = System.Text.Encoding.Unicode.GetBytes(TextBox1.Text);
byte[] Salt = Encoding.ASCII.GetBytes(Password.Length.ToString());
PasswordDeriveBytes SecretKey = new PasswordDeriveBytes(Password, Salt);
ICryptoTransform Encryptor = RijndaelCipher.CreateEncryptor(SecretKey.GetBytes(32), SecretKey.GetBytes(16));
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, Encryptor, CryptoStreamMode.Write);
cryptoStream.Write(PlainText, 0, PlainText.Length);
cryptoStream.FlushFinalBlock();
byte[] CipherBytes = memoryStream.ToArray();
memoryStream.Close();
cryptoStream.Close();
string EncryptedData = Convert.ToBase64String(CipherBytes);
return EncryptedData;
}
This is my Decrypt Method
public string Decrypt(string encrypted)
{
RijndaelManaged RijndaelCipher = new RijndaelManaged();
string Password = System.Configuration.ConfigurationManager.AppSettings["Password"];
string DecryptedData;
try
{
byte[] EncryptedData = Convert.FromBase64String(TextBox2.Text);
byte[] Salt = Encoding.ASCII.GetBytes(Password.Length.ToString());
PasswordDeriveBytes SecretKey = new PasswordDeriveBytes(Password, Salt);
ICryptoTransform Decryptor = RijndaelCipher.CreateDecryptor(SecretKey.GetBytes(32), SecretKey.GetBytes(16));
MemoryStream memoryStream = new MemoryStream(EncryptedData);
CryptoStream cryptoStream = new CryptoStream(memoryStream, Decryptor, CryptoStreamMode.Read);
byte[] PlainText = new byte[EncryptedData.Length];
int DecryptedCount = cryptoStream.Read(PlainText, 0, PlainText.Length);
memoryStream.Close();
cryptoStream.Close();
DecryptedData = Encoding.Unicode.GetString(PlainText, 0, DecryptedCount);
}
catch
{
DecryptedData = TextBox3.Text;
}
return DecryptedData;
}
As you can see from my codes, I am using the password from the web config and I do not store any IV and key into the database. So my question is if the encryptions method that I use is as secure as using AES method. If it isn't, is there any other possible solutions that I can refer to? Thanks for replying and sorry for my poor english skills.
This bad in several ways:
It's unauthenticated. Add a MAC on use an existing authenticated algorithm like AES-GCM, AES-SIV.
The salt is derived deterministically from the password, which is equivalent to using no salt at all. Each user needs to use a different salt.
Similar to the salt, the point of an IV is to ensure that encrypting similar or identical plaintexts using a fixed key produces completely different outputs every time. If your key is single-use (e.g. because its derivation involves a single-use salt), a fixes IV would be acceptable.
PasswordDeriveBytes is a mix of PBKDF1 and undocumented Microsoft specific extensions. Don't use it. At minimum use Rfc2898DeriveBytes which is standard compliant PBKDF2-HMAC-SHA1. Using about 100000 iterations, instead of the much too small default.
I recommend using jbtule's answer to Encrypt and decrypt a string in C#
I'm writing a program at the moment that works under the following scenario:
I've got some confidential log files that I need to backup to a server.
I have a program that generates these log files every day.
These log files would rarely if ever need to be opened.
I have only one RSA public/private key pair.
The program has only the RSA public key.
I generate a random AES key each time the program makes one of these confidential files.
The program uses this AES key to encrypt the log file.
I then use the RSA public key to encrypt the AES Key
I then backup both the AES encrypted file and RSA encrypted AES key to the server.
As far as I understand, that protocol is fitting for my use case.
The issue I'm having is coding it up in C#. I ran into needing an Initialization Vector(IV) for my AES encryption, I tried to encrypt this along with the AES key by using the public RSA key on both. But the 512(2 * 256) size is larger than RSA is happy to encrypt. So I figured out since I created the Initialization Vector randomly each time just like the AES Key, I can add the IV to the front of the AES ciphertext. However, I'm not sure where the code to do this would be inserted in my functions
Any help in the right direction to the "protocol" or other ways to write the IV to the ciphertext would be great. Thank you in advance.
static public Tuple<byte[], byte[]> EncryptAES(byte[] toEncryptAES, RSAParameters RSAPublicKey)
{
byte[] encryptedAES = null;
byte[] encryptedRSA = null;
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
AES.Mode = CipherMode.CBC;
AES.GenerateIV();
AES.GenerateKey();
encryptedRSA = RSAEncrypt(AES.Key, RSAPublicKey);
using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
{
ms.Write(AES.IV, 0, AES.KeySize); //DOESNT WORK HERE
//Can't use CS to write it to the stream else it will encrypt along with file
cs.Write(toEncryptAES, 0, toEncryptAES.Length);
cs.Close();
}
encryptedAES = ms.ToArray();
}
}
return new Tuple<byte[], byte[]>(encryptedAES, encryptedRSA);
}
static public byte[] DecryptAES(byte[] toDecryptAES, byte[] AESKeyAndIV, RSAParameters RSAPrivateKey)
{
byte[] AESKey = RSADecrypt(AESKeyAndIV, RSAPrivateKey);
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
AES.Key = AESKey;
ms.Read(AES.IV, 0, AES.KeySize); //Not sure if can read MS here
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
{
//Would I need to move 0 to 256?
cs.Write(toDecryptAES, 0, toDecryptAES.Length);
cs.Close();
}
return ms.ToArray();
}
}
}
You where quite close, write out the IV before you create the CryptoStream
static public Tuple<byte[], byte[]> EncryptAES(byte[] toEncryptAES, RSAParameters RSAPublicKey)
{
byte[] encryptedAES = null;
byte[] encryptedRSA = null;
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
AES.Mode = CipherMode.CBC;
AES.GenerateIV();
AES.GenerateKey();
encryptedRSA = RSAEncrypt(AES.Key, RSAPublicKey);
ms.Write(AES.IV, 0, AES.KeySize); //Move the write here.
using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(toEncryptAES, 0, toEncryptAES.Length);
cs.Close();
}
encryptedAES = ms.ToArray();
}
}
return new Tuple<byte[], byte[]>(encryptedAES, encryptedRSA);
}
For the decrypt, make sure you loop over the read till you have fully read the byte[] for the IV, Stream.Read is not guaranteed to read all the bytes you asked it to read. I usually make a static method ReadFully to ensure all bytes are read.
private static byte[] ReadFully(Stream stream, int length)
{
int offset = 0;
byte[] buffer = new byte[length];
while(offset < length)
{
offset += stream.Read(buffer, offset, length - offset);
}
return buffer;
}
Then just use that method to read in the IV. You also want to use cs.Read not cs.Write to read out the encrypted data and put the stream in to read mode, however it is easier to just use .CopyTo and copy the data to a new MemoryStream.
static public byte[] DecryptAES(byte[] toDecryptAES, byte[] AESKeyAndIV, RSAParameters RSAPrivateKey)
{
byte[] AESKey = RSADecrypt(AESKeyAndIV, RSAPrivateKey);
using (MemoryStream source = new MemoryStream(toDecryptAES))
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
AES.Key = AESKey;
var iv = ReadFully(source, AES.KeySize);
AES.IV = iv;
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(source, AES.CreateDecryptor(), CryptoStreamMode.Read))
{
using(var dest = new MemoryStream())
{
cs.CopyTo(dest);
return dest.ToArray();
}
}
}
}
}
For other readers, note that RSAEncrypt and RSADecrypt are wrappers for calls to the RSACryptoServiceProvider.
There are many answers on the internet regarding encryption, but I have been unable to find exactly what I'm looking for: simple strong encryption using the tools that c# provides to encrypt strings and text files.
My main problem is that I don't know how to save the IV into the beginning of the text file or how to create a random IV. I have an example on crypto stream and I have seen an example on DES, but they use the same IV and key and that is (by what I know) not a good thing to do.
You're right, using the same IV is a bad practice, especially if either the Key or IV are hard coded. I'd recommend using the AesManaged class. It uses the AES algorithm, the current standard. Generating an IV is fairly simple:
var aes = new AesManaged(); //Set your KeySize if you will generate a key too.
aes.GenerateIV();
var iv = aes.IV;
That's a simple way of getting a new initialization vector. If your goal is to encrypt a file, you can store the File, but what will you do with the Key? Hard coding it within your application is generally not a very good way of doing it. If your application will be password based, then you can generate the key from Rfc2898DeriveBytes to get a byte array based on a password. This way, your application never knows what the encryption key is.
Here is an example for writing the IV to a file, then the file contents.
using (AesManaged aes = new AesManaged())
{
//Set the Key here.
aes.GenerateIV();
using (var transform = aes.CreateEncryptor())
{
using (var fileStream = new FileStream("C:\\in.txt", FileMode.Open))
{
using (var saveTo = new FileStream("C:\\out.txt", FileMode.Create))
{
using (var cryptoStream = new CryptoStream(saveTo, transform,CryptoStreamMode.Write))
{
var iv = aes.IV;
cryptoStream.Write(iv, 0, iv.Length);
fileStream.CopyTo(cryptoStream);
}
}
}
}
}
see the example on following link, it will create a string encryption with hash, salt and VI key.
https://github.com/salahuddinuk/Encryption-Decryption/blob/master/EncryptDecrypt/Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace EncryptDecrypt
{
public partial class Form1 : Form
{
static readonly string PasswordHash = "P!!Sw0rd~";
static readonly string SaltKey = "Sa~LT~KEY";
static readonly string VIKey = "#1B2c3D4#e5F6<7H8<.";
public Form1()
{
InitializeComponent();
}
private void btn_Process_Click(object sender, EventArgs e)
{
try
{
lbl_Error.Text = "";
if (chb_Decrypt.Checked == true)
txt_Result.Text = Decrypt(txt_Value.Text);
else
txt_Result.Text = Encrypt(txt_Value.Text);
}
catch (Exception ex)
{
lbl_Error.Text = ex.Message;
}
}
public static string Encrypt(string plainText)
{
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
byte[] keyBytes = new Rfc2898DeriveBytes(PasswordHash, Encoding.ASCII.GetBytes(SaltKey)).GetBytes(256 / 8);
var symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC, Padding = PaddingMode.Zeros };
var encryptor = symmetricKey.CreateEncryptor(keyBytes, Encoding.ASCII.GetBytes(VIKey));
byte[] cipherTextBytes;
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
cipherTextBytes = memoryStream.ToArray();
cryptoStream.Close();
}
memoryStream.Close();
}
return Convert.ToBase64String(cipherTextBytes);
}
public static string Decrypt(string encryptedText)
{
byte[] cipherTextBytes = Convert.FromBase64String(encryptedText);
byte[] keyBytes = new Rfc2898DeriveBytes(PasswordHash, Encoding.ASCII.GetBytes(SaltKey)).GetBytes(256 / 8);
var symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC, Padding = PaddingMode.None };
var decryptor = symmetricKey.CreateDecryptor(keyBytes, Encoding.ASCII.GetBytes(VIKey));
var memoryStream = new MemoryStream(cipherTextBytes);
var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
byte[] plainTextBytes = new byte[cipherTextBytes.Length];
int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount).TrimEnd("\0".ToCharArray());
}
}
}
Nowadays, AesGcm would be an appropriate class and algorithm to use. Examples code for it is easy enough to find, and its API is fairly straightforward.
To generate the IV/nonce, use RandomNumberGenerator.Fill to populate an array of the correct size, which is 12 bytes (96 bits) for AES-GCM. RandomNumberGenerator is the cryptographically-secure one.
As for writing the IV to the file, that is up to you. Are you writing to a file stream? Then start by writing the IV, and then proceed to write the ciphertext. For AES-GCM, we would also write the tag, which will give us not just encryption, but authenticated encryption, i.e. on decryption we can confirm that the ciphertext has not been tampered with.
When reading such a file back in, we read each of the components separately - IV, ciphertext, and tag. Since you know how you wrote them, you know how to read them. For example, x bytes IV, then y bytes tag, then the remaining bytes ciphertext, if that is how you wrote the data to the file.
Pass the components to AesGcm.Decrypt and voila.