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.
Related
I'm trying to encrypt & decrypt some data using AES. But i'm only getting garbled output. What am I doing wrong?
static void Test()
{
byte[] myFileBytes; // Will contain encrypted data. First the IV, then the ciphertext.
var myPassword = "helloworld";
var dataToEncrypt = "this is a test";
// STEP 1: Encrypt some data:
byte[] key;
using (var sha256 = SHA256.Create())
key = sha256.ComputeHash(Encoding.UTF8.GetBytes(myPassword));
using (var myFileStream = new MemoryStream())
using (var aes = System.Security.Cryptography.Aes.Create())
{
aes.Key = key;
myFileStream.Write(aes.IV); // Use the default created by AES, which is presumably non-pseudo random
using (var cryptoStream = new CryptoStream(myFileStream, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
cryptoStream.Write(Encoding.UTF8.GetBytes(dataToEncrypt));
cryptoStream.Flush();
myFileBytes = myFileStream.ToArray(); // We are done!
} // Disposing CryptoStream disposes the underlying MemoryStream
}
// STEP 2: Decrypt it to verify that it works
using (var aes = System.Security.Cryptography.Aes.Create())
{
using (var myFileStream = new MemoryStream(myFileBytes))
{
var iv = new byte[aes.IV.Length];
myFileStream.Read(iv, 0, iv.Length);
using (var cryptoStream = new CryptoStream(myFileStream, aes.CreateEncryptor(key, iv), CryptoStreamMode.Read))
using (var copyStream = new MemoryStream())
{
cryptoStream.CopyTo(copyStream);
var decrypted = Encoding.UTF8.GetString(copyStream.ToArray());
Debug.Assert(dataToEncrypt == decrypted); // Fails!
}
}
}
}
I would take a look at the example in the documentation and compare to your code.
Notably when decrypting you are using aes.CreateEncryptor(key, iv). It should probably be aes.CreateDecryptor(key, iv).
The example from the docs also inputs the key and IV when calling CreateEncryptor, but I'm not sure if that is required or not.
You should probably not use sha256 to generate the key from a password. The correct way would be a key derivation algorithm. For example Rfc2898DeriveBytes
Decripting with ECC
I have a problem with decription on this file, can some one help me? I i'm using ECC enter image description here
Code is here:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Security.Cryptography;
namespace eccdh_Forme.ECC
{
public class ECCDH
{
public static byte[] Enkripto(byte[] key, string MesazhiSekret)
{
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
key=aes.Key;
byte[] iv = aes.IV;
aes.BlockSize = 128;
aes.Mode = CipherMode.ECB;
aes.Padding = PaddingMode.PKCS7;
// Encrypt the message
using (MemoryStream ciphertext = new MemoryStream())
using (CryptoStream cs = new CryptoStream(ciphertext, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
byte[] plaintextMessage = Encoding.UTF8.GetBytes(MesazhiSekret);
cs.Write(plaintextMessage, 0, plaintextMessage.Length);
cs.Close();
byte[] cipherMesazhi = ciphertext.ToArray();
return cipherMesazhi;
}
}
public static byte[] Dekripto(byte[] encryptedMessage, byte[] bobKey)//e shtuar e re mja pasu vleren
{
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
byte[] message;
bobKey=aes.Key;
byte[] iv = aes.IV;
// Decrypt the message
using (MemoryStream plaintext = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(plaintext, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(encryptedMessage, 0, encryptedMessage.Length);
cs.Close();
message = plaintext.ToArray();
}
}
return message;
}
}
}
The program is stoping the compile wen i try to decript the text on this line of code " cs.Close(); ".
The form decription is this:
There are a number of problems here, but the one mostly likely causing your exception is you are assigning the key backwards. This:
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
byte[] message;
bobKey=aes.Key;
byte[] iv = aes.IV;
You're setting your parameter's value to a random AES key. You probably meant to do this:
aes.Key = bobKey;
Other things:
You seem to be trying to use an initialization vector. I'm not sure why you're capturing it, but in ECB mode there is no initialization vector.
I'm going to assume that this is a learning exercise for yourself to understand how encryption and key exchanges work. That's great! Happy learning, but keep in mind there are a number of security issues here. The main one being that you're using ECB, and no MAC. Before you run off to put this in a production system, if that is the intention, I would consider using a much more high-level approach so the key exchange is transparent to you.
I have a WPF applications that contains a user form. I have a password field I need to decript it, I just have an encrypt method for this:
public static string Encode(string value)
{
var hash = System.Security.Cryptography.SHA1.Create();
var encoder = new System.Text.ASCIIEncoding();
var combined = encoder.GetBytes(value ?? "");
return BitConverter.ToString(hash.ComputeHash(combined)).ToLower().Replace("-", "");
}
How to create a Decode method for this?
The key in this situation is that you don't want to decrypt the password. What you want to do is to encrypt the password entered by the user using the same function and comparing the result to what is stored in the database for the user's account.
Hashing is the right thing to do, but you should also hash the value that you are storing in the database and compare the two hashes, you should not, if at all possible, be storing passwords, even if they are encrypted.
You should store the one-way hash in the database instead of a reversible encryption. What the user's actual password happens to be is not your concern, only that the hash of the user supplied password when salted matches the hash in your database. You might, however, encrypt it for transport to be decrypted at the server and then hashed for storage in the database.
Retrieve salt and hashed password from database.
Salt candidate password and hash it.
Compare values.
SHA1 is a hash function which means it is basically one-way function, you cannot get the original content back.
you should use cryptographic functions if you need to get the original value back.
there basically two classes of encryption algorithms - symmetric and asymmetric cryptographic functions.
symetric is for example AES
asymetric would be Public/private key encrytion such as RSA
take a look at this sample: http://www.codeproject.com/Articles/10877/Public-Key-RSA-Encryption-in-C-NET
You can't decrypt SHA1 hash because it's a one way hash. Hashing is not a reversible operation.
Below a helper class that both encrypt and decrypte a string
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace EncryptStringSample
{
public static class StringCipher
{
// This constant string is used as a "salt" value for the PasswordDeriveBytes function calls.
// This size of the IV (in bytes) must = (keysize / 8). Default keysize is 256, so the IV must be
// 32 bytes long. Using a 16 character string here gives us 32 bytes when converted to a byte array.
private static readonly byte[] initVectorBytes = Encoding.ASCII.GetBytes("tu89geji340t89u2");
// This constant is used to determine the keysize of the encryption algorithm.
private const int keysize = 256;
public static string Encrypt(string plainText, string passPhrase)
{
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
using (PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null))
{
byte[] keyBytes = password.GetBytes(keysize / 8);
using (RijndaelManaged symmetricKey = new RijndaelManaged())
{
symmetricKey.Mode = CipherMode.CBC;
using (ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes))
{
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] cipherTextBytes = memoryStream.ToArray();
return Convert.ToBase64String(cipherTextBytes);
}
}
}
}
}
}
public static string Decrypt(string cipherText, string passPhrase)
{
byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
using(PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null))
{
byte[] keyBytes = password.GetBytes(keysize / 8);
using(RijndaelManaged symmetricKey = new RijndaelManaged())
{
symmetricKey.Mode = CipherMode.CBC;
using(ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes))
{
using(MemoryStream memoryStream = new MemoryStream(cipherTextBytes))
{
using(CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
byte[] plainTextBytes = new byte[cipherTextBytes.Length];
int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}
}
}
}
}
}
}
}
The above class can used quite simply with code similar to the following:
using System;
using System.Linq;
namespace EncryptStringSample
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Please enter a password to use:");
string password = Console.ReadLine();
Console.WriteLine("Please enter a string to encrypt:");
string plaintext = Console.ReadLine();
Console.WriteLine("");
Console.WriteLine("Your encrypted string is:");
string encryptedstring = StringCipher.Encrypt(plaintext, password);
Console.WriteLine(encryptedstring);
Console.WriteLine("");
Console.WriteLine("Your decrypted string is:");
string decryptedstring = StringCipher.Decrypt(encryptedstring, password);
Console.WriteLine(decryptedstring);
Console.WriteLine("");
Console.ReadLine();
}
}
}
Here's another way to decrypt and encrypt using RSA
Replace your_rsa_key with your RSA key.
var provider = new System.Security.Cryptography.RSACryptoServiceProvider();
provider.ImportParameters(your_rsa_key);
var encryptedBytes = provider.Encrypt(
System.Text.Encoding.UTF8.GetBytes("Hello World!"), true);
string decryptedTest = System.Text.Encoding.UTF8.GetString(
provider.Decrypt(encryptedBytes, true));
Here's a good link on how RSA works with a clear exmaple
This question already has answers here:
Encrypt and decrypt a string in C#? [closed]
(29 answers)
Closed 6 years ago.
What is the most modern (best) way of satisfying the following in C#?
string encryptedString = SomeStaticClass.Encrypt(sourceString);
string decryptedString = SomeStaticClass.Decrypt(encryptedString);
BUT with a minimum of fuss involving salts, keys, mucking about with byte[], etc.
Been Googling and confused at what I'm finding (you can see the list of similar SO Qs to see this is a deceptive question to ask).
UPDATE 23/Dec/2015: Since this answer seems to be getting a lot of upvotes, I've updated it to fix silly bugs and to generally improve the code based upon comments and feedback. See the end of the post for a list of specific improvements.
As other people have said, Cryptography is not simple so it's best to avoid "rolling your own" encryption algorithm.
You can, however, "roll your own" wrapper class around something like the built-in RijndaelManaged cryptography class.
Rijndael is the algorithmic name of the current Advanced Encryption Standard, so you're certainly using an algorithm that could be considered "best practice".
The RijndaelManaged class does indeed normally require you to "muck about" with byte arrays, salts, keys, initialization vectors etc. but this is precisely the kind of detail that can be somewhat abstracted away within your "wrapper" class.
The following class is one I wrote a while ago to perform exactly the kind of thing you're after, a simple single method call to allow some string-based plaintext to be encrypted with a string-based password, with the resulting encrypted string also being represented as a string. Of course, there's an equivalent method to decrypt the encrypted string with the same password.
Unlike the first version of this code, which used the exact same salt and IV values every time, this newer version will generate random salt and IV values each time. Since salt and IV must be the same between the encryption and decryption of a given string, the salt and IV is prepended to the cipher text upon encryption and extracted from it again in order to perform the decryption. The result of this is that encrypting the exact same plaintext with the exact same password gives and entirely different ciphertext result each time.
The "strength" of using this comes from using the RijndaelManaged class to perform the encryption for you, along with using the Rfc2898DeriveBytes function of the System.Security.Cryptography namespace which will generate your encryption key using a standard and secure algorithm (specifically, PBKDF2) based upon the string-based password you supply. (Note this is an improvement of the first version's use of the older PBKDF1 algorithm).
Finally, it's important to note that this is still unauthenticated encryption. Encryption alone provides only privacy (i.e. message is unknown to 3rd parties), whilst authenticated encryption aims to provide both privacy and authenticity (i.e. recipient knows message was sent by the sender).
Without knowing your exact requirements, it's difficult to say whether the code here is sufficiently secure for your needs, however, it has been produced to deliver a good balance between relative simplicity of implementation vs "quality". For example, if your "receiver" of an encrypted string is receiving the string directly from a trusted "sender", then authentication may not even be necessary.
If you require something more complex, and which offers authenticated encryption, check out this post for an implementation.
Here's the code:
using System;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using System.Linq;
namespace EncryptStringSample
{
public static class StringCipher
{
// This constant is used to determine the keysize of the encryption algorithm in bits.
// We divide this by 8 within the code below to get the equivalent number of bytes.
private const int Keysize = 256;
// This constant determines the number of iterations for the password bytes generation function.
private const int DerivationIterations = 1000;
public static string Encrypt(string plainText, string passPhrase)
{
// Salt and IV is randomly generated each time, but is preprended to encrypted cipher text
// so that the same Salt and IV values can be used when decrypting.
var saltStringBytes = Generate256BitsOfRandomEntropy();
var ivStringBytes = Generate256BitsOfRandomEntropy();
var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var symmetricKey = new RijndaelManaged())
{
symmetricKey.BlockSize = 256;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes))
{
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
// Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes.
var cipherTextBytes = saltStringBytes;
cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray();
cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray();
memoryStream.Close();
cryptoStream.Close();
return Convert.ToBase64String(cipherTextBytes);
}
}
}
}
}
}
public static string Decrypt(string cipherText, string passPhrase)
{
// Get the complete stream of bytes that represent:
// [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText]
var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
// Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes.
var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
// Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes.
var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray();
// Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.
var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray();
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var symmetricKey = new RijndaelManaged())
{
symmetricKey.BlockSize = 256;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes))
{
using (var memoryStream = new MemoryStream(cipherTextBytes))
{
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
using (var streamReader = new StreamReader(cryptoStream, Encoding.UTF8))
{
return streamReader.ReadToEnd();
}
}
}
}
}
}
private static byte[] Generate256BitsOfRandomEntropy()
{
var randomBytes = new byte[32]; // 32 Bytes will give us 256 bits.
using (var rngCsp = new RNGCryptoServiceProvider())
{
// Fill the array with cryptographically secure random bytes.
rngCsp.GetBytes(randomBytes);
}
return randomBytes;
}
}
}
The above class can be used quite simply with code similar to the following:
using System;
namespace EncryptStringSample
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Please enter a password to use:");
string password = Console.ReadLine();
Console.WriteLine("Please enter a string to encrypt:");
string plaintext = Console.ReadLine();
Console.WriteLine("");
Console.WriteLine("Your encrypted string is:");
string encryptedstring = StringCipher.Encrypt(plaintext, password);
Console.WriteLine(encryptedstring);
Console.WriteLine("");
Console.WriteLine("Your decrypted string is:");
string decryptedstring = StringCipher.Decrypt(encryptedstring, password);
Console.WriteLine(decryptedstring);
Console.WriteLine("");
Console.WriteLine("Press any key to exit...");
Console.ReadLine();
}
}
}
(You can download a simple VS2013 sample solution (which includes a few unit tests) here).
UPDATE 23/Dec/2015:
The list of specific improvements to the code are:
Fixed a silly bug where encoding was different between encrypting and
decrypting. As the mechanism by which salt & IV values are generated has changed, encoding is no longer necessary.
Due to the salt/IV change, the previous code comment that incorrectly indicated that UTF8 encoding a 16 character string produces 32 bytes is no longer applicable (as encoding is no longer necessary).
Usage of the superseded PBKDF1 algorithm has been replaced with usage of the more modern PBKDF2 algorithm.
The password derivation is now properly salted whereas previously it wasn't salted at all (another silly bug squished).
using System.IO;
using System.Text;
using System.Security.Cryptography;
public static class EncryptionHelper
{
public static string Encrypt(string clearText)
{
string EncryptionKey = "abc123";
byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
using (Aes encryptor = Aes.Create())
{
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
encryptor.Key = pdb.GetBytes(32);
encryptor.IV = pdb.GetBytes(16);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
}
clearText = Convert.ToBase64String(ms.ToArray());
}
}
return clearText;
}
public static string Decrypt(string cipherText)
{
string EncryptionKey = "abc123";
cipherText = cipherText.Replace(" ", "+");
byte[] cipherBytes = Convert.FromBase64String(cipherText);
using (Aes encryptor = Aes.Create())
{
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
encryptor.Key = pdb.GetBytes(32);
encryptor.IV = pdb.GetBytes(16);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(cipherBytes, 0, cipherBytes.Length);
cs.Close();
}
cipherText = Encoding.Unicode.GetString(ms.ToArray());
}
}
return cipherText;
}
}
If you are targeting ASP.NET Core that does not support RijndaelManaged yet, you can use IDataProtectionProvider.
First, configure your application to use data protection:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection();
}
// ...
}
Then you'll be able to inject IDataProtectionProvider instance and use it to encrypt/decrypt data:
public class MyService : IService
{
private const string Purpose = "my protection purpose";
private readonly IDataProtectionProvider _provider;
public MyService(IDataProtectionProvider provider)
{
_provider = provider;
}
public string Encrypt(string plainText)
{
var protector = _provider.CreateProtector(Purpose);
return protector.Protect(plainText);
}
public string Decrypt(string cipherText)
{
var protector = _provider.CreateProtector(Purpose);
return protector.Unprotect(cipherText);
}
}
See this article for more details.
Try this class:
public class DataEncryptor
{
TripleDESCryptoServiceProvider symm;
#region Factory
public DataEncryptor()
{
this.symm = new TripleDESCryptoServiceProvider();
this.symm.Padding = PaddingMode.PKCS7;
}
public DataEncryptor(TripleDESCryptoServiceProvider keys)
{
this.symm = keys;
}
public DataEncryptor(byte[] key, byte[] iv)
{
this.symm = new TripleDESCryptoServiceProvider();
this.symm.Padding = PaddingMode.PKCS7;
this.symm.Key = key;
this.symm.IV = iv;
}
#endregion
#region Properties
public TripleDESCryptoServiceProvider Algorithm
{
get { return symm; }
set { symm = value; }
}
public byte[] Key
{
get { return symm.Key; }
set { symm.Key = value; }
}
public byte[] IV
{
get { return symm.IV; }
set { symm.IV = value; }
}
#endregion
#region Crypto
public byte[] Encrypt(byte[] data) { return Encrypt(data, data.Length); }
public byte[] Encrypt(byte[] data, int length)
{
try
{
// Create a MemoryStream.
var ms = new MemoryStream();
// Create a CryptoStream using the MemoryStream
// and the passed key and initialization vector (IV).
var cs = new CryptoStream(ms,
symm.CreateEncryptor(symm.Key, symm.IV),
CryptoStreamMode.Write);
// Write the byte array to the crypto stream and flush it.
cs.Write(data, 0, length);
cs.FlushFinalBlock();
// Get an array of bytes from the
// MemoryStream that holds the
// encrypted data.
byte[] ret = ms.ToArray();
// Close the streams.
cs.Close();
ms.Close();
// Return the encrypted buffer.
return ret;
}
catch (CryptographicException ex)
{
Console.WriteLine("A cryptographic error occured: {0}", ex.Message);
}
return null;
}
public string EncryptString(string text)
{
return Convert.ToBase64String(Encrypt(Encoding.UTF8.GetBytes(text)));
}
public byte[] Decrypt(byte[] data) { return Decrypt(data, data.Length); }
public byte[] Decrypt(byte[] data, int length)
{
try
{
// Create a new MemoryStream using the passed
// array of encrypted data.
MemoryStream ms = new MemoryStream(data);
// Create a CryptoStream using the MemoryStream
// and the passed key and initialization vector (IV).
CryptoStream cs = new CryptoStream(ms,
symm.CreateDecryptor(symm.Key, symm.IV),
CryptoStreamMode.Read);
// Create buffer to hold the decrypted data.
byte[] result = new byte[length];
// Read the decrypted data out of the crypto stream
// and place it into the temporary buffer.
cs.Read(result, 0, result.Length);
return result;
}
catch (CryptographicException ex)
{
Console.WriteLine("A cryptographic error occured: {0}", ex.Message);
}
return null;
}
public string DecryptString(string data)
{
return Encoding.UTF8.GetString(Decrypt(Convert.FromBase64String(data))).TrimEnd('\0');
}
#endregion
}
and use it like this:
string message="A very secret message here.";
DataEncryptor keys=new DataEncryptor();
string encr=keys.EncryptString(message);
// later
string actual=keys.DecryptString(encr);
If you need to store a password in memory and would like to have it encrypted you should use SecureString:
http://msdn.microsoft.com/en-us/library/system.security.securestring.aspx
For more general uses I would use a FIPS approved algorithm such as Advanced Encryption Standard, formerly known as Rijndael. See this page for an implementation example:
http://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndael.aspx
You may be looking for the ProtectedData class, which encrypts data using the user's logon credentials.
The easiest way that I've seen to do encryption is through RSA
Check out the MSDN on it: http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.aspx
It does involve using bytes, but when it comes down to it you kind of do want encryption and decryption to be tough to figure out otherwise it will be easy to hack.
I have an existing data format that has portions of it encrypted in what appears to be AES in CFB mode. The plaintext data length and the encrypted data length are the same.
In C#, pretty much every angle I've taken seems to expect the encrypted length to be a multiple of the block size... so I get an exception trying to decrypt the data.
In researching solutions, I've used Crypto++ and wrote a quick C++ app that successfully decrypts the data, so I'm pretty sure I'm using the right algorithm, key and IV. This works fine, but I'd like to keep everything inside C# if at all possible. Any suggestions?
Working C++ code below:
//define key
unsigned char key[16];
//populate key
//...
//define iv
unsigned char iv[16];
//populate iv
//...
std::ifstream inFile;
//open file
inFile.open("file.aes",ios::binary );
//get file size
inFile.seekg(0,ios::end);
int fileSize = (int) inFile.tellg();
inFile.seekg(offset, ios::beg);
//read/close file
char* inBytes = new char[fileSize];
inFile.read(inBytes,fileSize);
inFile.close();
//configure decryption
CFB_Mode<AES>::Decryption cfbDecryption(key, 16, iv);
//populate output bytes
char* outBytes = new char[fileSize];
cfbDecryption.ProcessData((byte*) outBytes,(byte*) inBytes,fileSize);
//open/write/close output file
std::ofstream outFile;
outFile.open("out.dec");
outFile.write(outBytes,fileSize);
outFile.close();
delete[] inBytes;
Here is an example showing how to use the RijndaelManaged class to achieve 8-bit feedback CFB encryption. AesManaged does not support CFB because, I believe, the official NIST AES does not support it. By noting that AES is just Rijndael restricted to the 128 bit blocksize and the 128, 192, and 256 bit keysizes you can use the RijndaelManaged classes to get your CFB functionality. NOTE: I'm not a C# or .NET expert so improvements are welcome.
using System;
using System.Text;
using System.Security.Cryptography;
using System.IO;
namespace AesCFB8Mode
{
class AESCFB8Example
{
static void Example()
{
//
// Encrypt a small sample of data
//
String Plain = "The quick brown fox";
byte[] plainBytes = Encoding.UTF8.GetBytes(Plain);
Console.WriteLine("plaintext length is " + plainBytes.Length);
Console.WriteLine("Plaintext is " + BitConverter.ToString(plainBytes));
byte [] savedKey = new byte[16];
byte [] savedIV = new byte[16];
byte[] cipherBytes;
using (RijndaelManaged Aes128 = new RijndaelManaged())
{
//
// Specify a blocksize of 128, and a key size of 128, which make this
// instance of RijndaelManaged an instance of AES 128.
//
Aes128.BlockSize = 128;
Aes128.KeySize = 128;
//
// Specify CFB8 mode
//
Aes128.Mode = CipherMode.CFB;
Aes128.FeedbackSize = 8;
Aes128.Padding = PaddingMode.None;
//
// Generate and save random key and IV.
//
Aes128.GenerateKey();
Aes128.GenerateIV();
Aes128.Key.CopyTo(savedKey, 0);
Aes128.IV.CopyTo(savedIV, 0);
using (var encryptor = Aes128.CreateEncryptor())
using (var msEncrypt = new MemoryStream())
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
using (var bw = new BinaryWriter(csEncrypt, Encoding.UTF8))
{
bw.Write(plainBytes);
bw.Close();
cipherBytes = msEncrypt.ToArray();
Console.WriteLine("Cipher length is " + cipherBytes.Length);
Console.WriteLine("Cipher text is " + BitConverter.ToString(cipherBytes));
}
}
//
// Now decrypt the cipher back to plaintext
//
using (RijndaelManaged Aes128 = new RijndaelManaged())
{
Aes128.BlockSize = 128;
Aes128.KeySize = 128;
Aes128.Mode = CipherMode.CFB;
Aes128.FeedbackSize = 8;
Aes128.Padding = PaddingMode.None;
Aes128.Key = savedKey;
Aes128.IV = savedIV;
using (var decryptor = Aes128.CreateDecryptor())
using (var msEncrypt = new MemoryStream(cipherBytes))
using (var csEncrypt = new CryptoStream(msEncrypt, decryptor, CryptoStreamMode.Read))
using (var br = new BinaryReader(csEncrypt, Encoding.UTF8))
{
//csEncrypt.FlushFinalBlock();
plainBytes = br.ReadBytes(cipherBytes.Length);
Console.WriteLine("Decrypted plain length is " + plainBytes.Length);
Console.WriteLine("Decrypted plain text bytes is " + BitConverter.ToString(plainBytes));
Console.WriteLine("Decrypted plain text is " + Encoding.UTF8.GetString(plainBytes));
}
}
}
static void Main(string[] args)
{
Example();
}
}
}
I revisited trying to use cryptlib and it solved my problem... code is below:
using cryptlib;
byte[] key = new byte[16] {...key bytes here...};
byte[] iv = new byte[16] {...iv bytes here...};
byte[] enc; //ciphertext bytes (i populated them from a filestream)
crypt.Init();
int cryptContext = crypt.CreateContext(crypt.UNUSED, crypt.ALGO_AES);
crypt.SetAttribute(cryptContext, crypt.CTXINFO_MODE, crypt.MODE_CFB);
crypt.SetAttributeString(cryptContext, crypt.CTXINFO_KEY, key, 0, 16);
crypt.SetAttributeString(cryptContext, crypt.CTXINFO_IV, iv, 0, 16);
crypt.Decrypt(cryptContext, enc); //ciphertext bytes replaced with plaintext bytes
crypt.DestroyContext(cryptContext);