在C#中加密和解密字符串?

如何在C#中加密和解密字符串?

797349 次浏览

这是一个使用RSA的示例。

重要提示:您可以使用RSA加密加密的数据大小有限制,KeySize - MinimumPadding例如256字节(假设2048位密钥)-42字节(最小OEAP填充)=214字节(最大明文大小)

用RSA密钥替换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));

有关更多信息,请访问MSDN-RSACryptoServiceProvider服务提供商

编辑2013-10月:虽然我已经编辑了这个答案来解决缺点,但请参阅jbtule的答案以获得更强大,更明智的解决方案。

https://stackoverflow.com/a/10366194/188474

原答复:

这是一个从"RijndaelManagedClass"留档MCTS培训包派生的工作示例。

2012年4月编辑:这个答案是根据jbtule的建议编辑的,以等待IV,如下所示:

http://msdn.microsoft.com/en-us/library/system.security.cryptography.aesmanaged%28v=vs.95%29.aspx

祝你好运!

public class Crypto
{


//While an app specific salt is not the best practice for
//password based encryption, it's probably safe enough as long as
//it is truly uncommon. Also too much work to alter this answer otherwise.
private static byte[] _salt = __To_Do__("Add a app specific salt here");


/// <summary>
/// Encrypt the given string using AES.  The string can be decrypted using
/// DecryptStringAES().  The sharedSecret parameters must match.
/// </summary>
/// <param name="plainText">The text to encrypt.</param>
/// <param name="sharedSecret">A password used to generate a key for encryption.</param>
public static string EncryptStringAES(string plainText, string sharedSecret)
{
if (string.IsNullOrEmpty(plainText))
throw new ArgumentNullException("plainText");
if (string.IsNullOrEmpty(sharedSecret))
throw new ArgumentNullException("sharedSecret");


string outStr = null;                       // Encrypted string to return
RijndaelManaged aesAlg = null;              // RijndaelManaged object used to encrypt the data.


try
{
// generate the key from the shared secret and the salt
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(sharedSecret, _salt);


// Create a RijndaelManaged object
aesAlg = new RijndaelManaged();
aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);


// Create a decryptor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);


// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
// prepend the IV
msEncrypt.Write(BitConverter.GetBytes(aesAlg.IV.Length), 0, sizeof(int));
msEncrypt.Write(aesAlg.IV, 0, aesAlg.IV.Length);
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
}
outStr = Convert.ToBase64String(msEncrypt.ToArray());
}
}
finally
{
// Clear the RijndaelManaged object.
if (aesAlg != null)
aesAlg.Clear();
}


// Return the encrypted bytes from the memory stream.
return outStr;
}


/// <summary>
/// Decrypt the given string.  Assumes the string was encrypted using
/// EncryptStringAES(), using an identical sharedSecret.
/// </summary>
/// <param name="cipherText">The text to decrypt.</param>
/// <param name="sharedSecret">A password used to generate a key for decryption.</param>
public static string DecryptStringAES(string cipherText, string sharedSecret)
{
if (string.IsNullOrEmpty(cipherText))
throw new ArgumentNullException("cipherText");
if (string.IsNullOrEmpty(sharedSecret))
throw new ArgumentNullException("sharedSecret");


// Declare the RijndaelManaged object
// used to decrypt the data.
RijndaelManaged aesAlg = null;


// Declare the string used to hold
// the decrypted text.
string plaintext = null;


try
{
// generate the key from the shared secret and the salt
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(sharedSecret, _salt);


// Create the streams used for decryption.
byte[] bytes = Convert.FromBase64String(cipherText);
using (MemoryStream msDecrypt = new MemoryStream(bytes))
{
// Create a RijndaelManaged object
// with the specified key and IV.
aesAlg = new RijndaelManaged();
aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);
// Get the initialization vector from the encrypted stream
aesAlg.IV = ReadByteArray(msDecrypt);
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))


// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}
finally
{
// Clear the RijndaelManaged object.
if (aesAlg != null)
aesAlg.Clear();
}


return plaintext;
}


private static byte[] ReadByteArray(Stream s)
{
byte[] rawLength = new byte[sizeof(int)];
if (s.Read(rawLength, 0, rawLength.Length) != rawLength.Length)
{
throw new SystemException("Stream did not contain properly formatted byte array");
}


byte[] buffer = new byte[BitConverter.ToInt32(rawLength, 0)];
if (s.Read(buffer, 0, buffer.Length) != buffer.Length)
{
throw new SystemException("Did not read byte array properly");
}


return buffer;
}
}
using System;
using System.Data;
using System.Configuration;
using System.Text;
using System.Security.Cryptography;


namespace Encription
{
class CryptorEngine
{
public static string Encrypt(string ToEncrypt, bool useHasing)
{
byte[] keyArray;
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(ToEncrypt);
//System.Configuration.AppSettingsReader settingsReader = new     AppSettingsReader();
string Key = "Bhagwati";
if (useHasing)
{
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);
}
public static string Decrypt(string cypherString, bool useHasing)
{
byte[] keyArray;
byte[] toDecryptArray = Convert.FromBase64String(cypherString);
//byte[] toEncryptArray = Convert.FromBase64String(cypherString);
//System.Configuration.AppSettingsReader settingReader = new     AppSettingsReader();
string key = "Bhagwati";
if (useHasing)
{
MD5CryptoServiceProvider hashmd = new MD5CryptoServiceProvider();
keyArray = hashmd.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
hashmd.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();
try
{
byte[] resultArray = cTransform.TransformFinalBlock(toDecryptArray, 0,         toDecryptArray.Length);


tDes.Clear();
return UTF8Encoding.UTF8.GetString(resultArray,0,resultArray.Length);
}
catch (Exception ex)
{
throw ex;
}
}
}
}

字符串的对称认证加密的现代示例。

对称加密的一般最佳实践是使用带有关联数据的身份验证加密(AEAD),但这不是标准. net加密库的一部分。因此,第一个示例使用AES256,然后使用HMAC256,一个两步然后加密MAC,这需要更多开销和更多密钥。

第二个示例使用AES256-GCM的简单实践,使用开源Bouncy Castle(通过nuget)。

这两个示例都有一个main函数,它接受秘密消息字符串、密钥和可选的非秘密有效载荷,并返回和验证加密字符串(可选地附加非秘密数据)。理想情况下,您可以将这些与随机生成的256位密钥一起使用(参见NewKey())。

这两个示例还有一个使用字符串密码生成密钥的辅助方法。提供这些辅助方法是为了方便与其他示例匹配,但是它们是远没有那么安全,因为密码的强度将是远弱于256位密钥

更新: 添加了byte[]重载,由于StackOverflow答案限制,只有要点具有4个空格缩进和api文档的完整格式。


. NET内置加密(AES)-Then-MAC(HMAC)[要点]

/*
* This work (Modern Encryption of a String C#, by James Tuley),
* identified by James Tuley, is free of known copyright restrictions.
* https://gist.github.com/4336842
* http://creativecommons.org/publicdomain/mark/1.0/
*/


using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;


namespace Encryption
{
public static class AESThenHMAC
{
private static readonly RandomNumberGenerator Random = RandomNumberGenerator.Create();


//Preconfigured Encryption Parameters
public static readonly int BlockBitSize = 128;
public static readonly int KeyBitSize = 256;


//Preconfigured Password Key Derivation Parameters
public static readonly int SaltBitSize = 64;
public static readonly int Iterations = 10000;
public static readonly int MinPasswordLength = 12;


/// <summary>
/// Helper that generates a random key on each call.
/// </summary>
/// <returns></returns>
public static byte[] NewKey()
{
var key = new byte[KeyBitSize / 8];
Random.GetBytes(key);
return key;
}


/// <summary>
/// Simple Encryption (AES) then Authentication (HMAC) for a UTF8 Message.
/// </summary>
/// <param name="secretMessage">The secret message.</param>
/// <param name="cryptKey">The crypt key.</param>
/// <param name="authKey">The auth key.</param>
/// <param name="nonSecretPayload">(Optional) Non-Secret Payload.</param>
/// <returns>
/// Encrypted Message
/// </returns>
/// <exception cref="System.ArgumentException">Secret Message Required!;secretMessage</exception>
/// <remarks>
/// Adds overhead of (Optional-Payload + BlockSize(16) + Message-Padded-To-Blocksize +  HMac-Tag(32)) * 1.33 Base64
/// </remarks>
public static string SimpleEncrypt(string secretMessage, byte[] cryptKey, byte[] authKey,
byte[] nonSecretPayload = null)
{
if (string.IsNullOrEmpty(secretMessage))
throw new ArgumentException("Secret Message Required!", "secretMessage");


var plainText = Encoding.UTF8.GetBytes(secretMessage);
var cipherText = SimpleEncrypt(plainText, cryptKey, authKey, nonSecretPayload);
return Convert.ToBase64String(cipherText);
}


/// <summary>
/// Simple Authentication (HMAC) then Decryption (AES) for a secrets UTF8 Message.
/// </summary>
/// <param name="encryptedMessage">The encrypted message.</param>
/// <param name="cryptKey">The crypt key.</param>
/// <param name="authKey">The auth key.</param>
/// <param name="nonSecretPayloadLength">Length of the non secret payload.</param>
/// <returns>
/// Decrypted Message
/// </returns>
/// <exception cref="System.ArgumentException">Encrypted Message Required!;encryptedMessage</exception>
public static string SimpleDecrypt(string encryptedMessage, byte[] cryptKey, byte[] authKey,
int nonSecretPayloadLength = 0)
{
if (string.IsNullOrWhiteSpace(encryptedMessage))
throw new ArgumentException("Encrypted Message Required!", "encryptedMessage");


var cipherText = Convert.FromBase64String(encryptedMessage);
var plainText = SimpleDecrypt(cipherText, cryptKey, authKey, nonSecretPayloadLength);
return plainText == null ? null : Encoding.UTF8.GetString(plainText);
}


/// <summary>
/// Simple Encryption (AES) then Authentication (HMAC) of a UTF8 message
/// using Keys derived from a Password (PBKDF2).
/// </summary>
/// <param name="secretMessage">The secret message.</param>
/// <param name="password">The password.</param>
/// <param name="nonSecretPayload">The non secret payload.</param>
/// <returns>
/// Encrypted Message
/// </returns>
/// <exception cref="System.ArgumentException">password</exception>
/// <remarks>
/// Significantly less secure than using random binary keys.
/// Adds additional non secret payload for key generation parameters.
/// </remarks>
public static string SimpleEncryptWithPassword(string secretMessage, string password,
byte[] nonSecretPayload = null)
{
if (string.IsNullOrEmpty(secretMessage))
throw new ArgumentException("Secret Message Required!", "secretMessage");


var plainText = Encoding.UTF8.GetBytes(secretMessage);
var cipherText = SimpleEncryptWithPassword(plainText, password, nonSecretPayload);
return Convert.ToBase64String(cipherText);
}


/// <summary>
/// Simple Authentication (HMAC) and then Descryption (AES) of a UTF8 Message
/// using keys derived from a password (PBKDF2).
/// </summary>
/// <param name="encryptedMessage">The encrypted message.</param>
/// <param name="password">The password.</param>
/// <param name="nonSecretPayloadLength">Length of the non secret payload.</param>
/// <returns>
/// Decrypted Message
/// </returns>
/// <exception cref="System.ArgumentException">Encrypted Message Required!;encryptedMessage</exception>
/// <remarks>
/// Significantly less secure than using random binary keys.
/// </remarks>
public static string SimpleDecryptWithPassword(string encryptedMessage, string password,
int nonSecretPayloadLength = 0)
{
if (string.IsNullOrWhiteSpace(encryptedMessage))
throw new ArgumentException("Encrypted Message Required!", "encryptedMessage");


var cipherText = Convert.FromBase64String(encryptedMessage);
var plainText = SimpleDecryptWithPassword(cipherText, password, nonSecretPayloadLength);
return plainText == null ? null : Encoding.UTF8.GetString(plainText);
}


public static byte[] SimpleEncrypt(byte[] secretMessage, byte[] cryptKey, byte[] authKey, byte[] nonSecretPayload = null)
{
//User Error Checks
if (cryptKey == null || cryptKey.Length != KeyBitSize / 8)
throw new ArgumentException(String.Format("Key needs to be {0} bit!", KeyBitSize), "cryptKey");


if (authKey == null || authKey.Length != KeyBitSize / 8)
throw new ArgumentException(String.Format("Key needs to be {0} bit!", KeyBitSize), "authKey");


if (secretMessage == null || secretMessage.Length < 1)
throw new ArgumentException("Secret Message Required!", "secretMessage");


//non-secret payload optional
nonSecretPayload = nonSecretPayload ?? new byte[] { };


byte[] cipherText;
byte[] iv;


using (var aes = new AesManaged
{
KeySize = KeyBitSize,
BlockSize = BlockBitSize,
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7
})
{


//Use random IV
aes.GenerateIV();
iv = aes.IV;


using (var encrypter = aes.CreateEncryptor(cryptKey, iv))
using (var cipherStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(cipherStream, encrypter, CryptoStreamMode.Write))
using (var binaryWriter = new BinaryWriter(cryptoStream))
{
//Encrypt Data
binaryWriter.Write(secretMessage);
}


cipherText = cipherStream.ToArray();
}


}


//Assemble encrypted message and add authentication
using (var hmac = new HMACSHA256(authKey))
using (var encryptedStream = new MemoryStream())
{
using (var binaryWriter = new BinaryWriter(encryptedStream))
{
//Prepend non-secret payload if any
binaryWriter.Write(nonSecretPayload);
//Prepend IV
binaryWriter.Write(iv);
//Write Ciphertext
binaryWriter.Write(cipherText);
binaryWriter.Flush();


//Authenticate all data
var tag = hmac.ComputeHash(encryptedStream.ToArray());
//Postpend tag
binaryWriter.Write(tag);
}
return encryptedStream.ToArray();
}


}


public static byte[] SimpleDecrypt(byte[] encryptedMessage, byte[] cryptKey, byte[] authKey, int nonSecretPayloadLength = 0)
{


//Basic Usage Error Checks
if (cryptKey == null || cryptKey.Length != KeyBitSize / 8)
throw new ArgumentException(String.Format("CryptKey needs to be {0} bit!", KeyBitSize), "cryptKey");


if (authKey == null || authKey.Length != KeyBitSize / 8)
throw new ArgumentException(String.Format("AuthKey needs to be {0} bit!", KeyBitSize), "authKey");


if (encryptedMessage == null || encryptedMessage.Length == 0)
throw new ArgumentException("Encrypted Message Required!", "encryptedMessage");


using (var hmac = new HMACSHA256(authKey))
{
var sentTag = new byte[hmac.HashSize / 8];
//Calculate Tag
var calcTag = hmac.ComputeHash(encryptedMessage, 0, encryptedMessage.Length - sentTag.Length);
var ivLength = (BlockBitSize / 8);


//if message length is to small just return null
if (encryptedMessage.Length < sentTag.Length + nonSecretPayloadLength + ivLength)
return null;


//Grab Sent Tag
Array.Copy(encryptedMessage, encryptedMessage.Length - sentTag.Length, sentTag, 0, sentTag.Length);


//Compare Tag with constant time comparison
var compare = 0;
for (var i = 0; i < sentTag.Length; i++)
compare |= sentTag[i] ^ calcTag[i];


//if message doesn't authenticate return null
if (compare != 0)
return null;


using (var aes = new AesManaged
{
KeySize = KeyBitSize,
BlockSize = BlockBitSize,
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7
})
{


//Grab IV from message
var iv = new byte[ivLength];
Array.Copy(encryptedMessage, nonSecretPayloadLength, iv, 0, iv.Length);


using (var decrypter = aes.CreateDecryptor(cryptKey, iv))
using (var plainTextStream = new MemoryStream())
{
using (var decrypterStream = new CryptoStream(plainTextStream, decrypter, CryptoStreamMode.Write))
using (var binaryWriter = new BinaryWriter(decrypterStream))
{
//Decrypt Cipher Text from Message
binaryWriter.Write(
encryptedMessage,
nonSecretPayloadLength + iv.Length,
encryptedMessage.Length - nonSecretPayloadLength - iv.Length - sentTag.Length
);
}
//Return Plain Text
return plainTextStream.ToArray();
}
}
}
}


public static byte[] SimpleEncryptWithPassword(byte[] secretMessage, string password, byte[] nonSecretPayload = null)
{
nonSecretPayload = nonSecretPayload ?? new byte[] {};


//User Error Checks
if (string.IsNullOrWhiteSpace(password) || password.Length < MinPasswordLength)
throw new ArgumentException(String.Format("Must have a password of at least {0} characters!", MinPasswordLength), "password");


if (secretMessage == null || secretMessage.Length ==0)
throw new ArgumentException("Secret Message Required!", "secretMessage");


var payload = new byte[((SaltBitSize / 8) * 2) + nonSecretPayload.Length];


Array.Copy(nonSecretPayload, payload, nonSecretPayload.Length);
int payloadIndex = nonSecretPayload.Length;


byte[] cryptKey;
byte[] authKey;
//Use Random Salt to prevent pre-generated weak password attacks.
using (var generator = new Rfc2898DeriveBytes(password, SaltBitSize / 8, Iterations))
{
var salt = generator.Salt;


//Generate Keys
cryptKey = generator.GetBytes(KeyBitSize / 8);


//Create Non Secret Payload
Array.Copy(salt, 0, payload, payloadIndex, salt.Length);
payloadIndex += salt.Length;
}


//Deriving separate key, might be less efficient than using HKDF,
//but now compatible with RNEncryptor which had a very similar wireformat and requires less code than HKDF.
using (var generator = new Rfc2898DeriveBytes(password, SaltBitSize / 8, Iterations))
{
var salt = generator.Salt;


//Generate Keys
authKey = generator.GetBytes(KeyBitSize / 8);


//Create Rest of Non Secret Payload
Array.Copy(salt, 0, payload, payloadIndex, salt.Length);
}


return SimpleEncrypt(secretMessage, cryptKey, authKey, payload);
}


public static byte[] SimpleDecryptWithPassword(byte[] encryptedMessage, string password, int nonSecretPayloadLength = 0)
{
//User Error Checks
if (string.IsNullOrWhiteSpace(password) || password.Length < MinPasswordLength)
throw new ArgumentException(String.Format("Must have a password of at least {0} characters!", MinPasswordLength), "password");


if (encryptedMessage == null || encryptedMessage.Length == 0)
throw new ArgumentException("Encrypted Message Required!", "encryptedMessage");


var cryptSalt = new byte[SaltBitSize / 8];
var authSalt = new byte[SaltBitSize / 8];


//Grab Salt from Non-Secret Payload
Array.Copy(encryptedMessage, nonSecretPayloadLength, cryptSalt, 0, cryptSalt.Length);
Array.Copy(encryptedMessage, nonSecretPayloadLength + cryptSalt.Length, authSalt, 0, authSalt.Length);


byte[] cryptKey;
byte[] authKey;


//Generate crypt key
using (var generator = new Rfc2898DeriveBytes(password, cryptSalt, Iterations))
{
cryptKey = generator.GetBytes(KeyBitSize / 8);
}
//Generate auth key
using (var generator = new Rfc2898DeriveBytes(password, authSalt, Iterations))
{
authKey = generator.GetBytes(KeyBitSize / 8);
}


return SimpleDecrypt(encryptedMessage, cryptKey, authKey, cryptSalt.Length + authSalt.Length + nonSecretPayloadLength);
}
}
}

Bouncy Castle AES-GCM[要点]

/*
* This work (Modern Encryption of a String C#, by James Tuley),
* identified by James Tuley, is free of known copyright restrictions.
* https://gist.github.com/4336842
* http://creativecommons.org/publicdomain/mark/1.0/
*/


using System;
using System.IO;
using System.Text;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
namespace Encryption
{


public static class AESGCM
{
private static readonly SecureRandom Random = new SecureRandom();


//Preconfigured Encryption Parameters
public static readonly int NonceBitSize = 128;
public static readonly int MacBitSize = 128;
public static readonly int KeyBitSize = 256;


//Preconfigured Password Key Derivation Parameters
public static readonly int SaltBitSize = 128;
public static readonly int Iterations = 10000;
public static readonly int MinPasswordLength = 12;




/// <summary>
/// Helper that generates a random new key on each call.
/// </summary>
/// <returns></returns>
public static byte[] NewKey()
{
var key = new byte[KeyBitSize / 8];
Random.NextBytes(key);
return key;
}


/// <summary>
/// Simple Encryption And Authentication (AES-GCM) of a UTF8 string.
/// </summary>
/// <param name="secretMessage">The secret message.</param>
/// <param name="key">The key.</param>
/// <param name="nonSecretPayload">Optional non-secret payload.</param>
/// <returns>
/// Encrypted Message
/// </returns>
/// <exception cref="System.ArgumentException">Secret Message Required!;secretMessage</exception>
/// <remarks>
/// Adds overhead of (Optional-Payload + BlockSize(16) + Message +  HMac-Tag(16)) * 1.33 Base64
/// </remarks>
public static string SimpleEncrypt(string secretMessage, byte[] key, byte[] nonSecretPayload = null)
{
if (string.IsNullOrEmpty(secretMessage))
throw new ArgumentException("Secret Message Required!", "secretMessage");


var plainText = Encoding.UTF8.GetBytes(secretMessage);
var cipherText = SimpleEncrypt(plainText, key, nonSecretPayload);
return Convert.ToBase64String(cipherText);
}




/// <summary>
/// Simple Decryption & Authentication (AES-GCM) of a UTF8 Message
/// </summary>
/// <param name="encryptedMessage">The encrypted message.</param>
/// <param name="key">The key.</param>
/// <param name="nonSecretPayloadLength">Length of the optional non-secret payload.</param>
/// <returns>Decrypted Message</returns>
public static string SimpleDecrypt(string encryptedMessage, byte[] key, int nonSecretPayloadLength = 0)
{
if (string.IsNullOrEmpty(encryptedMessage))
throw new ArgumentException("Encrypted Message Required!", "encryptedMessage");


var cipherText = Convert.FromBase64String(encryptedMessage);
var plainText = SimpleDecrypt(cipherText, key, nonSecretPayloadLength);
return plainText == null ? null : Encoding.UTF8.GetString(plainText);
}


/// <summary>
/// Simple Encryption And Authentication (AES-GCM) of a UTF8 String
/// using key derived from a password (PBKDF2).
/// </summary>
/// <param name="secretMessage">The secret message.</param>
/// <param name="password">The password.</param>
/// <param name="nonSecretPayload">The non secret payload.</param>
/// <returns>
/// Encrypted Message
/// </returns>
/// <remarks>
/// Significantly less secure than using random binary keys.
/// Adds additional non secret payload for key generation parameters.
/// </remarks>
public static string SimpleEncryptWithPassword(string secretMessage, string password,
byte[] nonSecretPayload = null)
{
if (string.IsNullOrEmpty(secretMessage))
throw new ArgumentException("Secret Message Required!", "secretMessage");


var plainText = Encoding.UTF8.GetBytes(secretMessage);
var cipherText = SimpleEncryptWithPassword(plainText, password, nonSecretPayload);
return Convert.ToBase64String(cipherText);
}




/// <summary>
/// Simple Decryption and Authentication (AES-GCM) of a UTF8 message
/// using a key derived from a password (PBKDF2)
/// </summary>
/// <param name="encryptedMessage">The encrypted message.</param>
/// <param name="password">The password.</param>
/// <param name="nonSecretPayloadLength">Length of the non secret payload.</param>
/// <returns>
/// Decrypted Message
/// </returns>
/// <exception cref="System.ArgumentException">Encrypted Message Required!;encryptedMessage</exception>
/// <remarks>
/// Significantly less secure than using random binary keys.
/// </remarks>
public static string SimpleDecryptWithPassword(string encryptedMessage, string password,
int nonSecretPayloadLength = 0)
{
if (string.IsNullOrWhiteSpace(encryptedMessage))
throw new ArgumentException("Encrypted Message Required!", "encryptedMessage");


var cipherText = Convert.FromBase64String(encryptedMessage);
var plainText = SimpleDecryptWithPassword(cipherText, password, nonSecretPayloadLength);
return plainText == null ? null : Encoding.UTF8.GetString(plainText);
}


public static byte[] SimpleEncrypt(byte[] secretMessage, byte[] key, byte[] nonSecretPayload = null)
{
//User Error Checks
if (key == null || key.Length != KeyBitSize / 8)
throw new ArgumentException(String.Format("Key needs to be {0} bit!", KeyBitSize), "key");


if (secretMessage == null || secretMessage.Length == 0)
throw new ArgumentException("Secret Message Required!", "secretMessage");


//Non-secret Payload Optional
nonSecretPayload = nonSecretPayload ?? new byte[] { };


//Using random nonce large enough not to repeat
var nonce = new byte[NonceBitSize / 8];
Random.NextBytes(nonce, 0, nonce.Length);


var cipher = new GcmBlockCipher(new AesFastEngine());
var parameters = new AeadParameters(new KeyParameter(key), MacBitSize, nonce, nonSecretPayload);
cipher.Init(true, parameters);


//Generate Cipher Text With Auth Tag
var cipherText = new byte[cipher.GetOutputSize(secretMessage.Length)];
var len = cipher.ProcessBytes(secretMessage, 0, secretMessage.Length, cipherText, 0);
cipher.DoFinal(cipherText, len);


//Assemble Message
using (var combinedStream = new MemoryStream())
{
using (var binaryWriter = new BinaryWriter(combinedStream))
{
//Prepend Authenticated Payload
binaryWriter.Write(nonSecretPayload);
//Prepend Nonce
binaryWriter.Write(nonce);
//Write Cipher Text
binaryWriter.Write(cipherText);
}
return combinedStream.ToArray();
}
}


public static byte[] SimpleDecrypt(byte[] encryptedMessage, byte[] key, int nonSecretPayloadLength = 0)
{
//User Error Checks
if (key == null || key.Length != KeyBitSize / 8)
throw new ArgumentException(String.Format("Key needs to be {0} bit!", KeyBitSize), "key");


if (encryptedMessage == null || encryptedMessage.Length == 0)
throw new ArgumentException("Encrypted Message Required!", "encryptedMessage");


using (var cipherStream = new MemoryStream(encryptedMessage))
using (var cipherReader = new BinaryReader(cipherStream))
{
//Grab Payload
var nonSecretPayload = cipherReader.ReadBytes(nonSecretPayloadLength);


//Grab Nonce
var nonce = cipherReader.ReadBytes(NonceBitSize / 8);


var cipher = new GcmBlockCipher(new AesFastEngine());
var parameters = new AeadParameters(new KeyParameter(key), MacBitSize, nonce, nonSecretPayload);
cipher.Init(false, parameters);


//Decrypt Cipher Text
var cipherText = cipherReader.ReadBytes(encryptedMessage.Length - nonSecretPayloadLength - nonce.Length);
var plainText = new byte[cipher.GetOutputSize(cipherText.Length)];


try
{
var len = cipher.ProcessBytes(cipherText, 0, cipherText.Length, plainText, 0);
cipher.DoFinal(plainText, len);


}
catch (InvalidCipherTextException)
{
//Return null if it doesn't authenticate
return null;
}


return plainText;
}


}


public static byte[] SimpleEncryptWithPassword(byte[] secretMessage, string password, byte[] nonSecretPayload = null)
{
nonSecretPayload = nonSecretPayload ?? new byte[] {};


//User Error Checks
if (string.IsNullOrWhiteSpace(password) || password.Length < MinPasswordLength)
throw new ArgumentException(String.Format("Must have a password of at least {0} characters!", MinPasswordLength), "password");


if (secretMessage == null || secretMessage.Length == 0)
throw new ArgumentException("Secret Message Required!", "secretMessage");


var generator = new Pkcs5S2ParametersGenerator();


//Use Random Salt to minimize pre-generated weak password attacks.
var salt = new byte[SaltBitSize / 8];
Random.NextBytes(salt);


generator.Init(
PbeParametersGenerator.Pkcs5PasswordToBytes(password.ToCharArray()),
salt,
Iterations);


//Generate Key
var key = (KeyParameter)generator.GenerateDerivedMacParameters(KeyBitSize);


//Create Full Non Secret Payload
var payload = new byte[salt.Length + nonSecretPayload.Length];
Array.Copy(nonSecretPayload, payload, nonSecretPayload.Length);
Array.Copy(salt,0, payload,nonSecretPayload.Length, salt.Length);


return SimpleEncrypt(secretMessage, key.GetKey(), payload);
}


public static byte[] SimpleDecryptWithPassword(byte[] encryptedMessage, string password, int nonSecretPayloadLength = 0)
{
//User Error Checks
if (string.IsNullOrWhiteSpace(password) || password.Length < MinPasswordLength)
throw new ArgumentException(String.Format("Must have a password of at least {0} characters!", MinPasswordLength), "password");


if (encryptedMessage == null || encryptedMessage.Length == 0)
throw new ArgumentException("Encrypted Message Required!", "encryptedMessage");


var generator = new Pkcs5S2ParametersGenerator();


//Grab Salt from Payload
var salt = new byte[SaltBitSize / 8];
Array.Copy(encryptedMessage, nonSecretPayloadLength, salt, 0, salt.Length);


generator.Init(
PbeParametersGenerator.Pkcs5PasswordToBytes(password.ToCharArray()),
salt,
Iterations);


//Generate Key
var key = (KeyParameter)generator.GenerateDerivedMacParameters(KeyBitSize);


return SimpleDecrypt(encryptedMessage, key.GetKey(), salt.Length + nonSecretPayloadLength);
}
}
}

我想给你我的贡献,用我的代码为AESRfc2898DeriveBytes这里留档)algorhytm,用C#(. NET Framework 4)编写,并完全适用于有限的平台,如Windows Phone 7.0+的. NET Compact Framework(并非所有平台都支持. NET Framework的每个脚本方法!)。

我希望这可以帮助任何人!

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;


public static class Crypto
{
private static readonly byte[] IVa = new byte[] { 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x11, 0x11, 0x12, 0x13, 0x14, 0x0e, 0x16, 0x17 };




public static string Encrypt(this string text, string salt)
{
try
{
using (Aes aes = new AesManaged())
{
Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(Encoding.UTF8.GetString(IVa, 0, IVa.Length), Encoding.UTF8.GetBytes(salt));
aes.Key = deriveBytes.GetBytes(128 / 8);
aes.IV = aes.Key;
using (MemoryStream encryptionStream = new MemoryStream())
{
using (CryptoStream encrypt = new CryptoStream(encryptionStream, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
byte[] cleanText = Encoding.UTF8.GetBytes(text);
encrypt.Write(cleanText, 0, cleanText.Length);
encrypt.FlushFinalBlock();
}


byte[] encryptedData = encryptionStream.ToArray();
string encryptedText = Convert.ToBase64String(encryptedData);




return encryptedText;
}
}
}
catch
{
return String.Empty;
}
}


public static string Decrypt(this string text, string salt)
{
try
{
using (Aes aes = new AesManaged())
{
Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(Encoding.UTF8.GetString(IVa, 0, IVa.Length), Encoding.UTF8.GetBytes(salt));
aes.Key = deriveBytes.GetBytes(128 / 8);
aes.IV = aes.Key;


using (MemoryStream decryptionStream = new MemoryStream())
{
using (CryptoStream decrypt = new CryptoStream(decryptionStream, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
byte[] encryptedData = Convert.FromBase64String(text);




decrypt.Write(encryptedData, 0, encryptedData.Length);
decrypt.Flush();
}


byte[] decryptedData = decryptionStream.ToArray();
string decryptedText = Encoding.UTF8.GetString(decryptedData, 0, decryptedData.Length);




return decryptedText;
}
}
}
catch
{
return String.Empty;
}
}
}
}

BouncyCastle是一个很棒的. NET加密库,它可以作为Nuget包安装到您的项目中。我喜欢它比System. Security. Cryptograph库中目前可用的要多得多。它在可用算法方面为您提供了更多选项,并为这些算法提供了更多模式。

这是两条鱼实现的一个示例,由Bruce Schneier(我们所有偏执的人的英雄)编写。它是一个像Rijndael一样的对称算法 (又名AES)。它是AES标准的三个决赛选手之一,也是Bruce Schneier编写的另一个著名算法BlowFish的兄弟姐妹。

bouncyCastle的第一件事是创建一个加密函数类,这将使在库中实现其他分组密码变得更容易。以下加密函数类接受一个泛型参数T,其中T实现IBlockCipher并具有默认构造函数。

更新:由于大众的需求,我决定实现生成一个随机IV,并在这个类中包含一个HMAC。虽然从风格的角度来看,这违背了单一责任的SOLID原则,因为这个类的性质,我重新命名了。这个类现在将采用两个泛型参数,一个用于密码,一个用于摘要。它使用RNGCryptoServiceProvider自动生成IV,以提供良好的RNG熵,并允许您使用BouncyCastle中想要的任何摘要算法来生成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);

加密最难的部分实际上是处理密钥而不是算法。你必须考虑你将密钥存储在哪里,如果必须,你如何交换它们。这些算法都经受住了时间的考验,并且极难破解。想要窃取你信息的人不会永远对你的消息进行密码分析,他们会试图找出你的密钥是什么或在哪里。所以#1明智地选择密钥,#2将它们存储在安全的地方,如果您使用web.config和IIS,那么您可以加密部分web.config,最后如果您必须交换密钥,请确保您的交换密钥协议是安全的。

更新2 更改了比较方法以减轻定时攻击。在此处查看更多信息http://codahale.com/a-lesson-in-timing-attacks/。还更新为默认为PKCS7填充,并添加了新的构造函数,允许最终用户选择他们想要使用的填充。感谢@CodesInChaos的建议。

如果您使用的是ASP. Net,您现在可以使用. 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之外设置它。

我无法在System. Web命名空间之外找到非ASP. Net等价物。

这是Brett放在这里的类。然而,我做了一个轻微的编辑,因为我在将其用于URL字符串加密和解密时收到错误“Base-64字符数组的长度无效”。

public class CryptoURL
{
private static byte[] _salt = Encoding.ASCII.GetBytes("Catto_Salt_Enter_Any_Value99");


/// <summary>
/// Encrypt the given string using AES.  The string can be decrypted using
/// DecryptStringAES().  The sharedSecret parameters must match.
/// The SharedSecret for the Password Reset that is used is in the next line
///  string sharedSecret = "OneUpSharedSecret9";
/// </summary>
/// <param name="plainText">The text to encrypt.</param>
/// <param name="sharedSecret">A password used to generate a key for encryption.</param>
public static string EncryptString(string plainText, string sharedSecret)
{
if (string.IsNullOrEmpty(plainText))
throw new ArgumentNullException("plainText");
if (string.IsNullOrEmpty(sharedSecret))
throw new ArgumentNullException("sharedSecret");


string outStr = null;                       // Encrypted string to return
RijndaelManaged aesAlg = null;              // RijndaelManaged object used to encrypt the data.


try
{
// generate the key from the shared secret and the salt
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(sharedSecret, _salt);


// Create a RijndaelManaged object
aesAlg = new RijndaelManaged();
aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);


// Create a decryptor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);


// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
// prepend the IV
msEncrypt.Write(BitConverter.GetBytes(aesAlg.IV.Length), 0, sizeof(int));
msEncrypt.Write(aesAlg.IV, 0, aesAlg.IV.Length);
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
}


outStr = HttpServerUtility.UrlTokenEncode(msEncrypt.ToArray());
//outStr = Convert.ToBase64String(msEncrypt.ToArray());
// you may need to add a reference. right click reference in solution explorer => "add Reference" => .NET tab => select "System.Web"
}
}
finally
{
// Clear the RijndaelManaged object.
if (aesAlg != null)
aesAlg.Clear();
}


// Return the encrypted bytes from the memory stream.
return outStr;
}


/// <summary>
/// Decrypt the given string.  Assumes the string was encrypted using
/// EncryptStringAES(), using an identical sharedSecret.
/// </summary>
/// <param name="cipherText">The text to decrypt.</param>
/// <param name="sharedSecret">A password used to generate a key for decryption.</param>
public static string DecryptString(string cipherText, string sharedSecret)
{
if (string.IsNullOrEmpty(cipherText))
throw new ArgumentNullException("cipherText");
if (string.IsNullOrEmpty(sharedSecret))
throw new ArgumentNullException("sharedSecret");


// Declare the RijndaelManaged object
// used to decrypt the data.
RijndaelManaged aesAlg = null;


// Declare the string used to hold
// the decrypted text.
string plaintext = null;


byte[] inputByteArray;


try
{
// generate the key from the shared secret and the salt
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(sharedSecret, _salt);


// Create the streams used for decryption.
//byte[] bytes = Convert.FromBase64String(cipherText);
inputByteArray = HttpServerUtility.UrlTokenDecode(cipherText);


using (MemoryStream msDecrypt = new MemoryStream(inputByteArray))
{
// Create a RijndaelManaged object
// with the specified key and IV.
aesAlg = new RijndaelManaged();
aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);
// Get the initialization vector from the encrypted stream
aesAlg.IV = ReadByteArray(msDecrypt);
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))


// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}
catch (System.Exception ex)
{
return "ERROR";
//throw ex;


}
finally
{
// Clear the RijndaelManaged object.
if (aesAlg != null)
aesAlg.Clear();
}


return plaintext;
}


static string ConvertStringArrayToString(string[] array)
{
//
// Concatenate all the elements into a StringBuilder.
//
StringBuilder builder = new StringBuilder();
foreach (string value in array)
{
builder.Append(value);
builder.Append('.');
}
return builder.ToString();
}


private static byte[] ReadByteArray(Stream s)
{
byte[] rawLength = new byte[sizeof(int)];
if (s.Read(rawLength, 0, rawLength.Length) != rawLength.Length)
{
throw new SystemException("Stream did not contain properly formatted byte array");
}


byte[] buffer = new byte[BitConverter.ToInt32(rawLength, 0)];
if (s.Read(buffer, 0, buffer.Length) != buffer.Length)
{
throw new SystemException("Did not read byte array properly");
}


return buffer;
}


}
            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);
}




}


}

为了简单起见,我为自己做了这个我用于非加密目的的函数:用你的密码替换“你的密码”…

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.IO;


namespace My
{
public class strCrypto
{
// 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 const string initVector = "r5dm5fgm24mfhfku";
private const string passPhrase = "yourpassphrase"; // email password encryption password


// This constant is used to determine the keysize of the encryption algorithm.
private const int keysize = 256;


public static string encryptString(string plainText)
{
//if the plaintext  is empty or null string just return an empty string
if (plainText == "" || plainText == null )
{
return "";
}


byte[] initVectorBytes = Encoding.UTF8.GetBytes(initVector);
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null);
byte[] keyBytes = password.GetBytes(keysize / 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();
return Convert.ToBase64String(cipherTextBytes);
}


public static string decryptString(string cipherText)
{
//if the ciphertext is empty or null string just return an empty string
if (cipherText == "" || cipherText == null )
{
return "";
}


byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null);
byte[] keyBytes = password.GetBytes(keysize / 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();
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}




}

}

这是一个使用AES CBC模式使用随机IV和HMAC以及密码派生密钥在C#中加密字符串的简单示例,以显示基本的移动部分:

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);
}

在我的回答中复制了一个类似的问题:C#的简单双向加密

基于多个答案和评论。

  • 加密文本前面的随机初始化向量(@jbtule)
  • 使用TransformFinalBlock()而不是MemoryStream(@RenniePet)
  • 没有预先填写的密钥,以避免任何人复制和粘贴灾难
  • 正确处理和使用模式

代码:

/// <summary>
/// Simple encryption/decryption using a random initialization vector
/// and prepending it to the crypto text.
/// </summary>
/// <remarks>Based on multiple answers in https://stackoverflow.com/questions/165808/simple-two-way-encryption-for-c-sharp </remarks>
public class SimpleAes : IDisposable
{
/// <summary>
///     Initialization vector length in bytes.
/// </summary>
private const int IvBytes = 16;


/// <summary>
///     Must be exactly 16, 24 or 32 characters long.
/// </summary>
private static readonly byte[] Key = Convert.FromBase64String("FILL ME WITH 16, 24 OR 32 CHARS");


private readonly UTF8Encoding _encoder;
private readonly ICryptoTransform _encryptor;
private readonly RijndaelManaged _rijndael;


public SimpleAes()
{
_rijndael = new RijndaelManaged {Key = Key};
_rijndael.GenerateIV();
_encryptor = _rijndael.CreateEncryptor();
_encoder = new UTF8Encoding();
}


public string Decrypt(string encrypted)
{
return _encoder.GetString(Decrypt(Convert.FromBase64String(encrypted)));
}


public void Dispose()
{
_rijndael.Dispose();
_encryptor.Dispose();
}


public string Encrypt(string unencrypted)
{
return Convert.ToBase64String(Encrypt(_encoder.GetBytes(unencrypted)));
}


private byte[] Decrypt(byte[] buffer)
{
// IV is prepended to cryptotext
byte[] iv = buffer.Take(IvBytes).ToArray();
using (ICryptoTransform decryptor = _rijndael.CreateDecryptor(_rijndael.Key, iv))
{
return decryptor.TransformFinalBlock(buffer, IvBytes, buffer.Length - IvBytes);
}
}


private byte[] Encrypt(byte[] buffer)
{
// Prepend cryptotext with IV
byte[] inputBuffer = _rijndael.IV.Concat(buffer).ToArray();
return _encryptor.TransformFinalBlock(inputBuffer, IvBytes, buffer.Length);
}
}

您必须使用System. Security. Cryptograph使用命名空间;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;
}
}

这是一个简单的Snippet,最初由ASP Snipets编写

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;
}

加密

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());
}

安全散列数据的一个好算法是BCrypt

除了加入盐以防止彩虹桌攻击外, bcrypt是一个自适应函数:随着时间的推移,迭代计数可以是 增加使它变慢,所以它仍然能抵抗蛮力 搜索攻击,即使增加计算能力。

有一个不错的. NET实现BCrypt也可以使用作为NuGet包

免责声明:此解决方案应仅用于未公开的静态数据(例如配置文件或数据库)。只有在这种情况下,快速脏处理的解决方案才能被认为比@jbtule的解决方案更好,因为维护更低。

原文: 我发现jbtule的答案对于快速和肮脏的安全AES字符串加密有点复杂,布雷特的答案有一个bug初始化向量是一个固定值,使其容易受到填充攻击,所以我修复了Brett的代码并添加了一个随机IV,添加到芯片字符串中,创建一个不同的加密值,每个加密值相同:

加密:

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;
}
}

AES算法:

public static class CryptographyProvider
{
public static string EncryptString(string plainText, out string Key)
{
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");


using (Aes _aesAlg = Aes.Create())
{
Key = Convert.ToBase64String(_aesAlg.Key);
ICryptoTransform _encryptor = _aesAlg.CreateEncryptor(_aesAlg.Key, _aesAlg.IV);


using (MemoryStream _memoryStream = new MemoryStream())
{
_memoryStream.Write(_aesAlg.IV, 0, 16);
using (CryptoStream _cryptoStream = new CryptoStream(_memoryStream, _encryptor, CryptoStreamMode.Write))
{
using (StreamWriter _streamWriter = new StreamWriter(_cryptoStream))
{
_streamWriter.Write(plainText);
}
return Convert.ToBase64String(_memoryStream.ToArray());
}
}
}
}
public static string DecryptString(string cipherText, string Key)
{


if (string.IsNullOrEmpty(cipherText))
throw new ArgumentNullException("cipherText");
if (string.IsNullOrEmpty(Key))
throw new ArgumentNullException("Key");


string plaintext = null;


byte[] _initialVector = new byte[16];
byte[] _Key = Convert.FromBase64String(Key);
byte[] _cipherTextBytesArray = Convert.FromBase64String(cipherText);
byte[] _originalString = new byte[_cipherTextBytesArray.Length - 16];


Array.Copy(_cipherTextBytesArray, 0, _initialVector, 0, _initialVector.Length);
Array.Copy(_cipherTextBytesArray, 16, _originalString, 0, _cipherTextBytesArray.Length - 16);


using (Aes _aesAlg = Aes.Create())
{
_aesAlg.Key = _Key;
_aesAlg.IV = _initialVector;
ICryptoTransform decryptor = _aesAlg.CreateDecryptor(_aesAlg.Key, _aesAlg.IV);


using (MemoryStream _memoryStream = new MemoryStream(_originalString))
{
using (CryptoStream _cryptoStream = new CryptoStream(_memoryStream, decryptor, CryptoStreamMode.Read))
{
using (StreamReader _streamReader = new StreamReader(_cryptoStream))
{
plaintext = _streamReader.ReadToEnd();
}
}
}
}
return plaintext;
}
}

支持马特曼瑟的回答。这是一个使用MachineKey类加密/解密URL安全值的示例。

需要记住的是,如前所述,这将使用机器配置设置(https://msdn.microsoft.com/en-us/library/ff649308.aspx)。您可以在web.config文件中手动设置加密和解密密钥/算法(如果您的站点在多个服务器上运行,您可能需要此功能)。您可以从IIS生成密钥(参见此处:https://blogs.msdn.microsoft.com/vijaysk/2009/05/13/iis-7-tip-10-you-can-generate-machine-keys-from-the-iis-manager/),也可以使用在线机器密钥生成器,例如: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;
}

加密是编程中很常见的事情。我认为最好安装一个包来为你完成任务。也许像一个简单的开源NuGet项目 简单Aes加密

密钥在配置文件中,因此在正式生产环境中很容易更改,我没有看到任何缺点。

<MessageEncryption>
<EncryptionKey KeySize="256" Key="3q2+796tvu/erb7v3q2+796tvu/erb7v3q2+796tvu8="/>
</MessageEncryption>

用于AES-GCM加密的BouncyCastle的替代方案是锂钠网。它包装了libNa C库。一个很好的优点是它在CPU中使用AES-NI扩展进行非常快速的加密。缺点是如果CPU没有扩展,它根本无法工作。没有软件后备。

参考在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());
}
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;


public class Program
{
public static void Main()
{
var key = Encoding.UTF8.GetBytes("SUkbqO2ycDo7QwpR25kfgmC7f8CoyrZy");
var data = Encoding.UTF8.GetBytes("testData");


//Encrypt data
var encrypted = CryptoHelper.EncryptData(data,key);


//Decrypt data
var decrypted = CryptoHelper.DecryptData(encrypted,key);


//Display result
Console.WriteLine(Encoding.UTF8.GetString(decrypted));
}
}


public static class CryptoHelper
{
public static byte[] EncryptData(byte[] data, byte[] key)
{
using (var aesAlg = Aes.Create())
{
aesAlg.Mode = CipherMode.CBC;
using (var encryptor = aesAlg.CreateEncryptor(key, aesAlg.IV))
{
using (var msEncrypt = new MemoryStream())
{
msEncrypt.Write(aesAlg.IV, 0, aesAlg.IV.Length);


using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
csEncrypt.Write(data, 0, data.Length);


return msEncrypt.ToArray();
}
}
}


}


public static byte[] DecryptData(byte[] encrypted, byte[] key)
{
var iv = new byte[16];
Buffer.BlockCopy(encrypted, 0, iv, 0, iv.Length);
using (var aesAlg = Aes.Create())
{
aesAlg.Mode = CipherMode.CBC;
using (var decryptor = aesAlg.CreateDecryptor(key, iv))
{
using (var msDecrypt = new MemoryStream(encrypted, iv.Length, encrypted.Length - iv.Length))
{
using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (var resultStream = new MemoryStream())
{
csDecrypt.CopyTo(resultStream);
return resultStream.ToArray();
}
}
}
}
}
}
}

这是样品如何使用Bouncy城堡包完成AES-GCM加密/解密。

我在谷歌搜索从GOlangcrypto/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示例与key(256位)、mac(128位)和nonce(96位)一起工作。

以下代码是Ghazal的回答到类似的问题的改进版本。

public class EncryptionHelper
{
private Aes aesEncryptor;


public EncryptionHelper()
{
}


private void BuildAesEncryptor(string key)
{
aesEncryptor = Aes.Create();
var pdb = new Rfc2898DeriveBytes(key, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
aesEncryptor.Key = pdb.GetBytes(32);
aesEncryptor.IV = pdb.GetBytes(16);
}


public string EncryptString(string clearText, string key)
{
BuildAesEncryptor(key);
var clearBytes = Encoding.Unicode.GetBytes(clearText);
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, aesEncryptor.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
}
var encryptedText = Convert.ToBase64String(ms.ToArray());
return encryptedText;
}
}


public string DecryptString(string cipherText, string key)
{
BuildAesEncryptor(key);
cipherText = cipherText.Replace(" ", "+");
var cipherBytes = Convert.FromBase64String(cipherText);
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, aesEncryptor.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(cipherBytes, 0, cipherBytes.Length);
}
var clearText = Encoding.Unicode.GetString(ms.ToArray());
return clearText;
}
}
}

以下示例演示如何加密和解密示例数据:

    // 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 = 128;


// 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 = GenerateBitsOfRandomEntropy(16);
var ivStringBytes = GenerateBitsOfRandomEntropy(16);
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 = 128;
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 = 128;
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[] GenerateBitsOfRandomEntropy(int size)
{
// 32 Bytes will give us 256 bits.
// 16 Bytes will give us 128 bits.
var randomBytes = new byte[size];
using (var rngCsp = new RNGCryptoServiceProvider())
{
// Fill the array with cryptographically secure random bytes.
rngCsp.GetBytes(randomBytes);
}
return randomBytes;
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Security.Cryptography;
using System.IO;
using System.Text;


/// <summary>
/// Summary description for Encryption
/// </summary>
public class Encryption
{
public TripleDES CreateDES(string key)
{
MD5 md5 = new MD5CryptoServiceProvider();
TripleDES des = new TripleDESCryptoServiceProvider();
des.Key = md5.ComputeHash(Encoding.Unicode.GetBytes(key));
des.IV = new byte[des.BlockSize / 8];
return des;
}
public  byte[] Encryptiondata(string PlainText)
{
TripleDES des = CreateDES("DreamMLMKey");
ICryptoTransform ct = des.CreateEncryptor();
byte[] input = Encoding.Unicode.GetBytes(PlainText);
return ct.TransformFinalBlock(input, 0, input.Length);
}


public string Decryptiondata(string CypherText)
{
string stringToDecrypt = CypherText.Replace(" ", "+");
int len = stringToDecrypt.Length;
byte[] inputByteArray = Convert.FromBase64String(stringToDecrypt);


byte[] b = Convert.FromBase64String(CypherText);
TripleDES des = CreateDES("DreamMLMKey");
ICryptoTransform ct = des.CreateDecryptor();
byte[] output = ct.TransformFinalBlock(b, 0, b.Length);
return Encoding.Unicode.GetString(output);
}
public string Decryptiondataurl(string CypherText)
{
string newcyperttext=CypherText.Replace(' ', '+');
byte[] b = Convert.FromBase64String(newcyperttext);
TripleDES des = CreateDES("DreamMLMKey");
ICryptoTransform ct = des.CreateDecryptor();
byte[] output = ct.TransformFinalBlock(b, 0, b.Length);
return Encoding.Unicode.GetString(output);
}




#region  encryption & Decription
public  string Encrypt(string input, string key)
{
byte[] inputArray = UTF8Encoding.UTF8.GetBytes(input);
TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider();
tripleDES.Key = UTF8Encoding.UTF8.GetBytes(key);
tripleDES.Mode = CipherMode.ECB;
tripleDES.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = tripleDES.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(inputArray, 0, inputArray.Length);
tripleDES.Clear();
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
public  string Decrypt(string input, string key)
{
byte[] inputArray = Convert.FromBase64String(input);
TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider();
tripleDES.Key = UTF8Encoding.UTF8.GetBytes(key);
tripleDES.Mode = CipherMode.ECB;
tripleDES.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = tripleDES.CreateDecryptor();
byte[] resultArray = cTransform.TransformFinalBlock(inputArray, 0, inputArray.Length);
tripleDES.Clear();
return UTF8Encoding.UTF8.GetString(resultArray);
}


public string encrypt(string encryptString)
{
string EncryptionKey = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
byte[] clearBytes = Encoding.Unicode.GetBytes(encryptString);
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();
}
encryptString = Convert.ToBase64String(ms.ToArray());
}
}
return encryptString;
}


public string Decrypt(string cipherText)
{
string EncryptionKey = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
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;
}


#endregion
}

很好的例子如何使用PGPCore和BouncyCastle来做到这一点,非常简单的解决方案:https://blog.bitscry.com/2018/07/05/pgp-encryption-and-decryption-in-c/

我尝试了不同的解决方案,但这对我最有效,有些有错误,但这对我来说是完美的。

using (PGP pgp = new PGP())
{
// Generate keys
pgp.GenerateKey(@"C:\TEMP\keys\public.asc", @"C:\TEMP\keys\private.asc", "email@email.com", "password");
// Encrypt file
pgp.EncryptFile(@"C:\TEMP\keys\content.txt", @"C:\TEMP\keys\content__encrypted.pgp", @"C:\TEMP\keys\public.asc", true, true);
// Encrypt and sign file
pgp.EncryptFileAndSign(@"C:\TEMP\keys\content.txt", @"C:\TEMP\keys\content__encrypted_signed.pgp", @"C:\TEMP\keys\public.asc", @"C:\TEMP\keys\private.asc", "password", true, true);
// Decrypt file
pgp.DecryptFile(@"C:\TEMP\keys\content__encrypted.pgp", @"C:\TEMP\keys\content__decrypted.txt", @"C:\TEMP\keys\private.asc", "password");
// Decrypt signed file
pgp.DecryptFile(@"C:\TEMP\keys\content__encrypted_signed.pgp", @"C:\TEMP\keys\content__decrypted_signed.txt", @"C:\TEMP\keys\private.asc", "password");


// Encrypt stream
using (FileStream inputFileStream = new FileStream(@"C:\TEMP\keys\content.txt", FileMode.Open))
using (Stream outputFileStream = File.Create(@"C:\TEMP\keys\content__encrypted2.pgp"))
using (Stream publicKeyStream = new FileStream(@"C:\TEMP\keys\public.asc", FileMode.Open))
pgp.EncryptStream(inputFileStream, outputFileStream, publicKeyStream, true, true);


// Decrypt stream
using (FileStream inputFileStream = new FileStream(@"C:\TEMP\keys\content__encrypted2.pgp", FileMode.Open))
using (Stream outputFileStream = File.Create(@"C:\TEMP\keys\content__decrypted2.txt"))
using (Stream privateKeyStream = new FileStream(@"C:\TEMP\keys\private.asc", FileMode.Open))
pgp.DecryptStream(inputFileStream, outputFileStream, privateKeyStream, "password");
}

我有一个名为X509Crypto的开源项目,它利用证书来加密和解密字符串。它非常容易使用。以下是如何使用它的示例:

1.使用X509Crypto命令行接口(CLI)来生成一个新的加密证书和密钥对

>x509crypto.exe
X509Crypto> makecert -context user -keysize medium -alias myvault


Certificate with thumbprint B31FE7E7AE5229F8186782742CF579197FA859FD was added to X509Alias "myvault" in the user X509Context


X509Crypto>

2.使用加密 CLI命令为您的新X509Alias添加一个秘密

X509Crypto> encrypt -text -alias myvault -context user -secret apikey -in "80EAF03248965AC2B78090"


Secret apikey has been added to X509Alias myvault in the user X509Context


X509Crypto>

3.引用程序中的秘密

一旦您建立了X509别名并添加了您的秘密,在安装了Org. X509Crypto nuget包的程序中检索它们是微不足道的:

using Org.X509Crypto;


namespace SampleApp
{
class Program
{
static void Main(string[] args)
{
var Alias = new X509Alias(@"myvault", X509Context.UserReadOnly);
var apiKey = Alias.RecoverSecret(@"apikey");
}
}
}