This text was translated from: Encrypting & Decrypting a String in C# [duplicate]
This question already has an answer here: This question has an answer here:
- Encrypt and decrypt a string in C#? Encrypt and decrypt strings in C #? 28 answers 28 answers
What is the most modern (best) way of satisfying the following in C#? What is the most modern (best) way to satisfy 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. But the smallest involves salt, keys, confusing surprises like bytes [].
Been Googling and confused at what I'm finding (you can see the list of similar SO Q s to see this is a deceptive question to ask).
#1st floor
Reference resources: https://stackoom.com/question/gfDs/Encrypt and decrypt strings in C-Repeat
#2nd floor
You may be looking for the ProtectedData class, which encrypts data using the user's login credentials.
#3rd floor
The easiest way that I've seen to do encryption is through RSA The easiest way I can see encryption is through RSA
Check out the MSDN on it: http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.aspx View MSDN: 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.
#4th floor
If you need to store a password in memory and would like to have it encrypted you should use SecureString: If you need to store the password in memory and want to encrypt it, you should use SecureString:
http://msdn.microsoft.com/en-us/library/system.security.securestring.aspx 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. For more general purposes, I would use FIPS-approved algorithms such as Advanced Encryption Standard, formerly known as Rijndael.See this page for an implementation example: For implementation examples, see this page:
http://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndael.aspx http://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndael.aspx
#5th floor
Try this class: Try this lesson:
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: 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);
#6th floor
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 on comments and feedback. Update December 23, 2015: Since this answer seems to have received a lot of approval, I've updated it to fix silly errors and roughly improve the code based on comments and feedback.See the end of the post for a list of specific improvements.For a list of specific improvements, see the end of the post.
As other people have said, Cryptography is not simple so it's best to avoid "rolling your own" encryption algorithm. As other s 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. However, you can RijndaelManaged Scroll your own wrapper class, such as encryption classes.
Rijndael is the algorithmic name of the current Advanced Encryption Standard So you're certainly using an algorithm that could be considered as "best practice". Rijndael is currently Advanced Encryption Standard The name of the algorithm, so the algorithm you are sure to use can be considered a "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. RijndaelManaged Classes do often require you to "tamper" with byte arrays, salt s, keys, initialization vectors, and so on, but this is the kind of detail that can be slightly abstracted from the "wrapper" class.
The following class is one I wrote a while before 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. Of course, there is an equivalent way to decrypt encrypted string s with the same password.
Unlike the first version of this code, which uses 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.Since salt and IV must be the same between encryption and decryption of a given string, salt and IV are pre-encrypted to the cipher during encryption and extracted from the cipher again to perform decryption.The result of this is that encrypting the exact same plaintext with the exact same password given and entirely different ciphertext result each time. As a result, the exact same plaintext is encrypted with the exact same password, resulting in completely different ciphertext results 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 on the string-based password you supply. The "advantage" of using it comes from using RijndaelManaged Class performs encryption for you, and uses System.Security.Cryptography Namespace Rfc2898DeriveBytes Function that generates an encryption key using standard and security algorithms (in particular PBKDF2) ) Based on the string-based password you provide.(Note this is an improvement of the first version's use of the older PBKDF1 algorithm). (Note that this is an improvement on using the older PBKDF1 algorithm for the first version.)
Finally, it's important to note that this is still unauthenticated encryption. Finally, it is important to note that this is still unauthenticated encryption.Encryption alone provides only privacy (ie message is unknown to 3rd parties),Whilst authenticated encryption aims to provide both privacy and authenticity (ie recipient knows message was sent by the sender). Encryption only provides privacy (that is, the third party does not know the message), while authenticated encryption is intended to provide privacy and authenticity (that is, the recipient knows the message was sent by the sender).
Without knowing your exact requirements, it's difficult to say if the code here is sufficiently secure for your needs, however,It has been produced to deliver a good balance between relative simplicity of implementation versus "quality". Without knowing your exact requirements, it is difficult to say if the code here is sufficient for your needs, but it was generated to achieve a good balance between relative simplicity and "quality" of implementation.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 For example, if the Receiver of an encrypted string receives the string directly from a trusted Sender, It may not even be necessary Authentication.
If you require something more complex, and which offers authenticated encryption, check out this post for an implementation. If you need something more complex and provide authenticated encryption, check This post To understand the implementation.
Here's the code: This is 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)) { var plainTextBytes = new byte[cipherTextBytes.Length]; var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length); memoryStream.Close(); cryptoStream.Close(); return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount); } } } } } } 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: The above class can very easily use 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 (You can download a simple VS2013 sample solution (including some unit tests) Ad locum ).
UPDATE 23/Dec/2015: The list of specific improvements to the code are: Update December 23, 2015: List of specific improvements to the code is as follows:
- Fixed a silly bug where encoding was different between encrypting and decrypting.Fixed a silly error encoding differently between encryption and decryption.As the mechanism by which salt & IV values are generated has changed, encoding is no longer necessary. Because the mechanism for generating salt and IV values has changed, coding is no longer required.
- 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). Due to salt/IV changes, previous code comments incorrectly indicated that UTF8 encoding a 16-character string produces 32 bytes that are no longer applicable (as encoding is no longer required).
- Usage of the superseded PBKDF1 algorithm has been replaced with usage of the more modern PBKDF2 algorithm. The use of the replaced PBKDF1 algorithm has been replaced by the use of the more modern PBKDF2 algorithm.
- The password derivation is now properly salted whereas previously it was n't salted at all (another silly bug squished). The password derivation is now properly marinated, but it was never marinated before (another silly bug is crushed).