如何在c#中加密和解密字符串?
当前回答
下面是一个简单的例子,在c#中使用AES CBC模式加密字符串,并使用随机IV和HMAC和密码派生密钥,以显示基本的移动部分:
private byte[] EncryptBytes(byte[] key, byte[] plaintext)
{
using (var cipher = new RijndaelManaged { Key = key })
{
using (var encryptor = cipher.CreateEncryptor())
{
var ciphertext = encryptor.TransformFinalBlock(plaintext, 0, plaintext.Length);
// IV is prepended to ciphertext
return cipher.IV.Concat(ciphertext).ToArray();
}
}
}
private byte[] DecryptBytes(byte[] key, byte[] packed)
{
using (var cipher = new RijndaelManaged { Key = key })
{
int ivSize = cipher.BlockSize / 8;
cipher.IV = packed.Take(ivSize).ToArray();
using (var encryptor = cipher.CreateDecryptor())
{
return encryptor.TransformFinalBlock(packed, ivSize, packed.Length - ivSize);
}
}
}
private byte[] AddMac(byte[] key, byte[] data)
{
using (var hmac = new HMACSHA256(key))
{
var macBytes = hmac.ComputeHash(data);
// HMAC is appended to data
return data.Concat(macBytes).ToArray();
}
}
private bool BadMac(byte[] found, byte[] computed)
{
int mismatch = 0;
// Aim for consistent timing regardless of inputs
for (int i = 0; i < found.Length; i++)
{
mismatch += found[i] == computed[i] ? 0 : 1;
}
return mismatch != 0;
}
private byte[] RemoveMac(byte[] key, byte[] data)
{
using (var hmac = new HMACSHA256(key))
{
int macSize = hmac.HashSize / 8;
var packed = data.Take(data.Length - macSize).ToArray();
var foundMac = data.Skip(packed.Length).ToArray();
var computedMac = hmac.ComputeHash(packed);
if (this.BadMac(foundMac, computedMac))
{
throw new Exception("Bad MAC");
}
return packed;
}
}
private List<byte[]> DeriveTwoKeys(string password)
{
var salt = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
var kdf = new Rfc2898DeriveBytes(password, salt, 10000);
var bytes = kdf.GetBytes(32); // Two keys 128 bits each
return new List<byte[]> { bytes.Take(16).ToArray(), bytes.Skip(16).ToArray() };
}
public byte[] EncryptString(string password, String message)
{
var keys = this.DeriveTwoKeys(password);
var plaintext = Encoding.UTF8.GetBytes(message);
var packed = this.EncryptBytes(keys[0], plaintext);
return this.AddMac(keys[1], packed);
}
public String DecryptString(string password, byte[] secret)
{
var keys = this.DeriveTwoKeys(password);
var packed = this.RemoveMac(keys[1], secret);
var plaintext = this.DecryptBytes(keys[0], packed);
return Encoding.UTF8.GetString(plaintext);
}
public void Example()
{
var password = "correcthorsebatterystaple";
var secret = this.EncryptString(password, "Hello World");
Console.WriteLine("secret: " + BitConverter.ToString(secret));
var recovered = this.DecryptString(password, secret);
Console.WriteLine(recovered);
}
其他回答
加密
public string EncryptString(string inputString)
{
MemoryStream memStream = null;
try
{
byte[] key = { };
byte[] IV = { 12, 21, 43, 17, 57, 35, 67, 27 };
string encryptKey = "aXb2uy4z"; // MUST be 8 characters
key = Encoding.UTF8.GetBytes(encryptKey);
byte[] byteInput = Encoding.UTF8.GetBytes(inputString);
DESCryptoServiceProvider provider = new DESCryptoServiceProvider();
memStream = new MemoryStream();
ICryptoTransform transform = provider.CreateEncryptor(key, IV);
CryptoStream cryptoStream = new CryptoStream(memStream, transform, CryptoStreamMode.Write);
cryptoStream.Write(byteInput, 0, byteInput.Length);
cryptoStream.FlushFinalBlock();
}
catch (Exception ex)
{
Response.Write(ex.Message);
}
return Convert.ToBase64String(memStream.ToArray());
}
解密:
public string DecryptString(string inputString)
{
MemoryStream memStream = null;
try
{
byte[] key = { };
byte[] IV = { 12, 21, 43, 17, 57, 35, 67, 27 };
string encryptKey = "aXb2uy4z"; // MUST be 8 characters
key = Encoding.UTF8.GetBytes(encryptKey);
byte[] byteInput = new byte[inputString.Length];
byteInput = Convert.FromBase64String(inputString);
DESCryptoServiceProvider provider = new DESCryptoServiceProvider();
memStream = new MemoryStream();
ICryptoTransform transform = provider.CreateDecryptor(key, IV);
CryptoStream cryptoStream = new CryptoStream(memStream, transform, CryptoStreamMode.Write);
cryptoStream.Write(byteInput, 0, byteInput.Length);
cryptoStream.FlushFinalBlock();
}
catch (Exception ex)
{
Response.Write(ex.Message);
}
Encoding encoding1 = Encoding.UTF8;
return encoding1.GetString(memStream.ToArray());
}
免责声明:此解决方案只能用于未公开的静态数据(例如配置文件或DB)。只有在这种情况下,快速和肮脏的解决方案才能被认为比@jbtule的解决方案更好,因为它的维护更低。
原来的帖子: 我发现jbtule的答案对于一个快速和肮脏的安全AES字符串加密有点复杂,Brett的答案有一个错误,初始化向量是一个固定的值,使它容易受到填充攻击,所以我修复了Brett的代码,并添加了一个随机IV,添加到chitered字符串,创建一个不同的加密值,每个加密相同的值:
加密:
public static string Encrypt(string clearText)
{
byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
using (Aes encryptor = Aes.Create())
{
byte[] IV = new byte[15];
rand.NextBytes(IV);
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, IV);
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(IV) + Convert.ToBase64String(ms.ToArray());
}
}
return clearText;
}
解密:
public static string Decrypt(string cipherText)
{
byte[] IV = Convert.FromBase64String(cipherText.Substring(0, 20));
cipherText = cipherText.Substring(20).Replace(" ", "+");
byte[] cipherBytes = Convert.FromBase64String(cipherText);
using (Aes encryptor = Aes.Create())
{
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, IV);
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;
}
将EncryptionKey替换为您的密钥。 在我的实现中,密钥被保存在配置文件(web.config\app.config)中,因为您不应该将其硬编码保存。配置文件也应该加密,这样密钥就不会被保存为明文。
protected static string _Key = "";
protected static string EncryptionKey
{
get
{
if (String.IsNullOrEmpty(_Key))
{
_Key = ConfigurationManager.AppSettings["AESKey"].ToString();
}
return _Key;
}
}
如果您正在使用ASP。你现在可以使用。Net 4.0以后的内置功能了。
System.Web.Security.MachineKey
. net 4.5有MachineKey.Protect()和MachineKey.Unprotect()。
. net 4.0有MachineKey.Encode()和MachineKey.Decode()。你应该将MachineKeyProtection设置为“All”。
ASP之外。Net这个类似乎在每次应用程序重新启动时都会生成一个新键,所以不起作用。在ILSpy中,如果缺少适当的app.settings,它就会生成自己的默认值。你可以在ASP.Net之外设置。
我还没找到非asp的。系统外的净等值。网络名称空间。
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);
}
}
}
下面是如何使用Bouncy castle包进行AES-GCM加密/解密的示例。
当我在谷歌上搜索从GOlang crypto/aes api解密数据的可能性时,我发现了这个示例:
const (
gcmBlockSize = 16 // this is key size
gcmTagSize = 16 // this is mac
gcmStandardNonceSize = 12 // this is nonce
)
func encrypt(data []byte, passphrase string) []byte {
block, _ := aes.NewCipher([]byte(createHash(passphrase)))
gcm, err := cipher.NewGCM(block)
if err != nil {
panic(err.Error())
}
nonce := make([]byte, gcm.NonceSize())
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
panic(err.Error())
}
ciphertext := gcm.Seal(nonce, nonce, data, nil)
return ciphertext
}
. net sample就像一个带有key(256位),mac(128位)和nonce(96位)的咒语。