如何在c#中加密和解密字符串?
当前回答
支持mattmanser的回答。下面是一个使用MachineKey类加密/解密URL安全值的示例。
Something to bear in mind, as mentioned before, this will use Machine config settings (https://msdn.microsoft.com/en-us/library/ff649308.aspx). You can set encryption and decryption key/algorithm manually (you might need this specially if your site is running on multiple servers) in web.config file. You can generate keys from IIS (see here: https://blogs.msdn.microsoft.com/vijaysk/2009/05/13/iis-7-tip-10-you-can-generate-machine-keys-from-the-iis-manager/) or can use an online machine key generator like: http://www.developerfusion.com/tools/generatemachinekey/
private static readonly UTF8Encoding Encoder = new UTF8Encoding();
public static string Encrypt(string unencrypted)
{
if (string.IsNullOrEmpty(unencrypted))
return string.Empty;
try
{
var encryptedBytes = MachineKey.Protect(Encoder.GetBytes(unencrypted));
if (encryptedBytes != null && encryptedBytes.Length > 0)
return HttpServerUtility.UrlTokenEncode(encryptedBytes);
}
catch (Exception)
{
return string.Empty;
}
return string.Empty;
}
public static string Decrypt(string encrypted)
{
if (string.IsNullOrEmpty(encrypted))
return string.Empty;
try
{
var bytes = HttpServerUtility.UrlTokenDecode(encrypted);
if (bytes != null && bytes.Length > 0)
{
var decryptedBytes = MachineKey.Unprotect(bytes);
if(decryptedBytes != null && decryptedBytes.Length > 0)
return Encoder.GetString(decryptedBytes);
}
}
catch (Exception)
{
return string.Empty;
}
return string.Empty;
}
其他回答
这是一个简单的Snippet,最初由ASP Snippet编写
using System.Text;
using System.Security.Cryptography;
using System.IO;
private string Encrypt(string clearText)
{
string EncryptionKey = "yourkey";
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;
}
private string Decrypt(string cipherText)
{
string EncryptionKey = "yourkey";
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;
}
您必须使用System.Security.Cryptography来使用命名空间;usehash是bool类型,true或false。字符串变量“key”对于加密和解密应该是相同的
//Encryption
public string EncryptText(string toEncrypt, bool useHashing)
{
try
{
byte[] keyArray;
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);
string key = "String Key Value"; //Based on this key stirng is encrypting
//System.Windows.Forms.MessageBox.Show(key);
//If hashing use get hashcode regards to your key
if (useHashing)
{
MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
//Always release the resources and flush data
//of the Cryptographic service provide. Best Practice
hashmd5.Clear();
}
else
keyArray = UTF8Encoding.UTF8.GetBytes(key);
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
//set the secret key for the tripleDES algorithm
tdes.Key = keyArray;
//mode of operation. there are other 4 modes. We choose ECB(Electronic code Book)
tdes.Mode = CipherMode.ECB;
//padding mode(if any extra byte added)
tdes.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = tdes.CreateEncryptor();
//transform the specified region of bytes array to resultArray
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
//Release resources held by TripleDes Encryptor
tdes.Clear();
//Return the encrypted data into unreadable string format
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
catch (Exception e)
{
throw e;
}
}
//Decryption
public string DecryptText(string cipherString, bool useHashing)
{
try
{
byte[] keyArray;
//get the byte code of the string
byte[] toEncryptArray = Convert.FromBase64String(cipherString);
string key = "String Key Value"; //Based on this key string is decrypted
if (useHashing)
{
//if hashing was used get the hash code with regards to your key
MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
//release any resource held by the MD5CryptoServiceProvider
hashmd5.Clear();
}
else
{
//if hashing was not implemented get the byte code of the key
keyArray = UTF8Encoding.UTF8.GetBytes(key);
}
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
//set the secret key for the tripleDES algorithm
tdes.Key = keyArray;
//mode of operation. there are other 4 modes.
//We choose ECB(Electronic code Book)
tdes.Mode = CipherMode.ECB;
//padding mode(if any extra byte added)
tdes.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = tdes.CreateDecryptor();
byte[] resultArray = cTransform.TransformFinalBlock
(toEncryptArray, 0, toEncryptArray.Length);
//Release resources held by TripleDes Encryptor
tdes.Clear();
//return the Clear decrypted TEXT
return UTF8Encoding.UTF8.GetString(resultArray);
}
catch (Exception ex)
{
throw ex;
}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions; // This is for password validation
using System.Security.Cryptography;
using System.Configuration; // This is where the hash functions reside
namespace BullyTracker.Common
{
public class HashEncryption
{
//public string GenerateHashvalue(string thisPassword)
//{
// MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
// byte[] tmpSource;
// byte[] tmpHash;
// tmpSource = ASCIIEncoding.ASCII.GetBytes(thisPassword); // Turn password into byte array
// tmpHash = md5.ComputeHash(tmpSource);
// StringBuilder sOutput = new StringBuilder(tmpHash.Length);
// for (int i = 0; i < tmpHash.Length; i++)
// {
// sOutput.Append(tmpHash[i].ToString("X2")); // X2 formats to hexadecimal
// }
// return sOutput.ToString();
//}
//public Boolean VerifyHashPassword(string thisPassword, string thisHash)
//{
// Boolean IsValid = false;
// string tmpHash = GenerateHashvalue(thisPassword); // Call the routine on user input
// if (tmpHash == thisHash) IsValid = true; // Compare to previously generated hash
// return IsValid;
//}
public string GenerateHashvalue(string toEncrypt, bool useHashing)
{
byte[] keyArray;
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);
System.Configuration.AppSettingsReader settingsReader = new AppSettingsReader();
// Get the key from config file
string key = (string)settingsReader.GetValue("SecurityKey", typeof(String));
//System.Windows.Forms.MessageBox.Show(key);
if (useHashing)
{
MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
hashmd5.Clear();
}
else
keyArray = UTF8Encoding.UTF8.GetBytes(key);
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
tdes.Key = keyArray;
tdes.Mode = CipherMode.ECB;
tdes.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = tdes.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
tdes.Clear();
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
/// <summary>
/// DeCrypt a string using dual encryption method. Return a DeCrypted clear string
/// </summary>
/// <param name="cipherString">encrypted string</param>
/// <param name="useHashing">Did you use hashing to encrypt this data? pass true is yes</param>
/// <returns></returns>
public string Decrypt(string cipherString, bool useHashing)
{
byte[] keyArray;
byte[] toEncryptArray = Convert.FromBase64String(cipherString);
System.Configuration.AppSettingsReader settingsReader = new AppSettingsReader();
//Get your key from config file to open the lock!
string key = (string)settingsReader.GetValue("SecurityKey", typeof(String));
if (useHashing)
{
MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
hashmd5.Clear();
}
else
keyArray = UTF8Encoding.UTF8.GetBytes(key);
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
tdes.Key = keyArray;
tdes.Mode = CipherMode.ECB;
tdes.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = tdes.CreateDecryptor();
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
tdes.Clear();
return UTF8Encoding.UTF8.GetString(resultArray);
}
}
}
参考c#中加密和解密字符串,我找到了一个很好的解决方案:
static readonly string PasswordHash = "P@@Sw0rd";
static readonly string SaltKey = "S@LT&KEY";
static readonly string VIKey = "@1B2c3D4e5F6g7H8";
对于加密
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());
}
BouncyCastle是一个很棒的。net加密库,它可以作为Nuget包安装到你的项目中。比起目前System.Security.Cryptography库中可用的东西,我更喜欢它。它为你提供了更多可用算法的选择,并为这些算法提供了更多的模式。
这是一个TwoFish实现的例子,它是由Bruce Schneier(我们所有偏执的人的英雄)编写的。这是一个像Rijndael一样的对称算法 (又名AES)。它是AES标准的三个最终入选者之一,是Bruce Schneier编写的另一个著名算法BlowFish的兄弟姐妹。
使用bouncycastle的第一件事是创建一个加密器类,这将使它更容易在库中实现其他块密码。下面的加密器类接受一个泛型参数T,其中T实现了IBlockCipher,并有一个默认构造函数。
UPDATE: Due to popular demand I have decided to implement generating a random IV as well as include an HMAC into this class. Although from a style perspective this goes against the SOLID principle of single responsibility, because of the nature of what this class does I reniged. This class will now take two generic parameters, one for the cipher and one for the digest. It automatically generates the IV using RNGCryptoServiceProvider to provide good RNG entropy, and allows you to use whatever digest algorithm you want from BouncyCastle to generate the MAC.
using System;
using System.Security.Cryptography;
using System.Text;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Macs;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Paddings;
using Org.BouncyCastle.Crypto.Parameters;
public sealed class Encryptor<TBlockCipher, TDigest>
where TBlockCipher : IBlockCipher, new()
where TDigest : IDigest, new()
{
private Encoding encoding;
private IBlockCipher blockCipher;
private BufferedBlockCipher cipher;
private HMac mac;
private byte[] key;
public Encryptor(Encoding encoding, byte[] key, byte[] macKey)
{
this.encoding = encoding;
this.key = key;
this.Init(key, macKey, new Pkcs7Padding());
}
public Encryptor(Encoding encoding, byte[] key, byte[] macKey, IBlockCipherPadding padding)
{
this.encoding = encoding;
this.key = key;
this.Init(key, macKey, padding);
}
private void Init(byte[] key, byte[] macKey, IBlockCipherPadding padding)
{
this.blockCipher = new CbcBlockCipher(new TBlockCipher());
this.cipher = new PaddedBufferedBlockCipher(this.blockCipher, padding);
this.mac = new HMac(new TDigest());
this.mac.Init(new KeyParameter(macKey));
}
public string Encrypt(string plain)
{
return Convert.ToBase64String(EncryptBytes(plain));
}
public byte[] EncryptBytes(string plain)
{
byte[] input = this.encoding.GetBytes(plain);
var iv = this.GenerateIV();
var cipher = this.BouncyCastleCrypto(true, input, new ParametersWithIV(new KeyParameter(key), iv));
byte[] message = CombineArrays(iv, cipher);
this.mac.Reset();
this.mac.BlockUpdate(message, 0, message.Length);
byte[] digest = new byte[this.mac.GetUnderlyingDigest().GetDigestSize()];
this.mac.DoFinal(digest, 0);
var result = CombineArrays(digest, message);
return result;
}
public byte[] DecryptBytes(byte[] bytes)
{
// split the digest into component parts
var digest = new byte[this.mac.GetUnderlyingDigest().GetDigestSize()];
var message = new byte[bytes.Length - digest.Length];
var iv = new byte[this.blockCipher.GetBlockSize()];
var cipher = new byte[message.Length - iv.Length];
Buffer.BlockCopy(bytes, 0, digest, 0, digest.Length);
Buffer.BlockCopy(bytes, digest.Length, message, 0, message.Length);
if (!IsValidHMac(digest, message))
{
throw new CryptoException();
}
Buffer.BlockCopy(message, 0, iv, 0, iv.Length);
Buffer.BlockCopy(message, iv.Length, cipher, 0, cipher.Length);
byte[] result = this.BouncyCastleCrypto(false, cipher, new ParametersWithIV(new KeyParameter(key), iv));
return result;
}
public string Decrypt(byte[] bytes)
{
return this.encoding.GetString(DecryptBytes(bytes));
}
public string Decrypt(string cipher)
{
return this.Decrypt(Convert.FromBase64String(cipher));
}
private bool IsValidHMac(byte[] digest, byte[] message)
{
this.mac.Reset();
this.mac.BlockUpdate(message, 0, message.Length);
byte[] computed = new byte[this.mac.GetUnderlyingDigest().GetDigestSize()];
this.mac.DoFinal(computed, 0);
return AreEqual(digest,computed);
}
private static bool AreEqual(byte [] digest, byte[] computed)
{
if(digest.Length != computed.Length)
{
return false;
}
int result = 0;
for (int i = 0; i < digest.Length; i++)
{
// compute equality of all bytes before returning.
// helps prevent timing attacks:
// https://codahale.com/a-lesson-in-timing-attacks/
result |= digest[i] ^ computed[i];
}
return result == 0;
}
private byte[] BouncyCastleCrypto(bool forEncrypt, byte[] input, ICipherParameters parameters)
{
try
{
cipher.Init(forEncrypt, parameters);
return this.cipher.DoFinal(input);
}
catch (CryptoException)
{
throw;
}
}
private byte[] GenerateIV()
{
using (var provider = new RNGCryptoServiceProvider())
{
// 1st block
byte[] result = new byte[this.blockCipher.GetBlockSize()];
provider.GetBytes(result);
return result;
}
}
private static byte[] CombineArrays(byte[] source1, byte[] source2)
{
byte[] result = new byte[source1.Length + source2.Length];
Buffer.BlockCopy(source1, 0, result, 0, source1.Length);
Buffer.BlockCopy(source2, 0, result, source1.Length, source2.Length);
return result;
}
}
接下来只需在新类上调用加密和解密方法,下面是使用twofish的示例:
var encrypt = new Encryptor<TwofishEngine, Sha1Digest>(Encoding.UTF8, key, hmacKey);
string cipher = encrypt.Encrypt("TEST");
string plainText = encrypt.Decrypt(cipher);
替换像TripleDES这样的分组密码也很容易:
var des = new Encryptor<DesEdeEngine, Sha1Digest>(Encoding.UTF8, key, hmacKey);
string cipher = des.Encrypt("TEST");
string plainText = des.Decrypt(cipher);
最后,如果你想使用AES和SHA256 HMAC,你可以做以下事情:
var aes = new Encryptor<AesEngine, Sha256Digest>(Encoding.UTF8, key, hmacKey);
cipher = aes.Encrypt("TEST");
plainText = aes.Decrypt(cipher);
The hardest part about encryption actually deals with the keys and not the algorithms. You'll have to think about where you store your keys, and if you have to, how you exchange them. These algorithms have all withstood the test of time, and are extremely hard to break. Someone who wants to steal information from you isn't going to spend eternity doing cryptanalysis on your messages, they're going to try to figure out what or where your key is. So #1 choose your keys wisely, #2 store them in a safe place, if you use a web.config and IIS then you can encrypt parts of the the web.config, and finally if you have to exchange keys make sure that your protocol for exchanging the key is secure.
更新2 改变比较方法以减轻定时攻击。点击这里查看更多信息http://codahale.com/a-lesson-in-timing-attacks/。还更新到默认PKCS7填充,并添加了新的构造函数,以允许最终用户选择他们想要使用的填充。感谢@CodesInChaos的建议。