C# 加密总结 一些常见的加密方法
一 散列数据 代码如下:
private static string CalculateSHA512Hash( string input) { byte [] inputBytes = Encoding.UTF8.GetBytes(input); SHA512Managed sha512 = new SHA512Managed(); byte [] outputBytes = sha512.ComputeHash(inputBytes); return Convert.ToBase64String(outputBytes); } |
原始散列对于彩虹表来说也存在漏洞,在彩虹表中,表内的每一条记录都是一串明文对应一种加密算法生成的一串密文。加盐就是指在密码中加入一个盐,这样可以提高密码散列的安全性。修改后的代码如下:
private static string CalculateSHA512Hash( string input, string salt) { byte [] saltBytes = Convert.FromBase64String(salt); byte [] inputBytes = Encoding.UTF8.GetBytes(input); byte [] inputWithSaltBytes = new byte [saltBytes.Length + inputBytes.Length]; Array.Copy(inputBytes, 0, inputWithSaltBytes, 0, inputBytes.Length); Array.Copy(saltBytes, 0, inputWithSaltBytes, inputBytes.Length, saltBytes.Length); SHA512Managed sha512 = new SHA512Managed(); byte [] outputBytes = sha512.ComputeHash(inputWithSaltBytes); return Convert.ToBase64String(outputBytes); } private static string GetSalt( int minSaltSize, int maxSaltSize) { Random random = new Random(); int saltSize = random.Next(minSaltSize, maxSaltSize); byte [] saltBytes = new byte [saltSize]; RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); rng.GetNonZeroBytes(saltBytes); return Convert.ToBase64String(saltBytes); } |
二 对称加密
private static string Encrypt( string input, byte [] key, byte [] iv) { byte [] inputBytes = Encoding.UTF8.GetBytes(input); RijndaelManaged rijndael = new RijndaelManaged(); ICryptoTransform transform = rijndael.CreateEncryptor(key, iv); byte [] encrytData = null ; using (MemoryStream outputStream = new MemoryStream()) { using (CryptoStream inputStream = new CryptoStream(outputStream, transform, CryptoStreamMode.Write)) { inputStream.Write(inputBytes, 0, inputBytes.Length); inputStream.FlushFinalBlock(); encrytData = outputStream.ToArray(); } } return Convert.ToBase64String(encrytData); } private static string Decrypt( string input, byte [] key, byte [] iv) { byte [] inputBytes=Convert.FromBase64String(input); RijndaelManaged rijndael = new RijndaelManaged(); ICryptoTransform transform = rijndael.CreateDecryptor(key, iv); byte [] decryptByte; using (MemoryStream outputStream= new MemoryStream()) { using (CryptoStream inputStream= new CryptoStream(outputStream,transform,CryptoStreamMode.Write)) { inputStream.Write(inputBytes, 0, inputBytes.Length); inputStream.FlushFinalBlock(); decryptByte = outputStream.ToArray(); } } return Encoding.UTF8.GetString(decryptByte); } private static void GetKeyAndIVFromPasswordAndSalt( string password, byte [] salt, SymmetricAlgorithm symmetricAlgorithm, ref byte [] key, ref byte [] iv) { Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, salt); key = rfc2898DeriveBytes.GetBytes(symmetricAlgorithm.KeySize / 8); iv = rfc2898DeriveBytes.GetBytes(symmetricAlgorithm.BlockSize / 8); } private static string GetSalt( int minSaltSize, int maxSaltSize) { Random random = new Random(); int saltSize = random.Next(minSaltSize, maxSaltSize); byte [] saltBytes = new byte [saltSize]; RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); rng.GetNonZeroBytes(saltBytes); return Convert.ToBase64String(saltBytes); } |
调用方式:
byte[] salt = Convert.FromBase64String(GetSalt(9, 18));
string password = "Password";
byte[] key=new byte[0];
byte[] iv = new byte[0];
GetKeyAndIVFromPasswordAndSalt(password,salt, new RijndaelManaged(), ref key, ref iv);
string input = "Wrox Press";
string encrytText = Encrypt(input, key, iv);
Console.WriteLine(encrytText);
string decryptText=Decrypt(encrytText,key,iv);
Console.WriteLine(decryptText);
只是简单的加密和解密数据是不够的,我们还需要确保数据不被改变,我们可以创建一个消息认证代码来生成一个加密的散列。
private static string GenerateMac( string input, byte [] key) { HMACSHA512 hmac = new HMACSHA512(key); byte [] data= hmac.ComputeHash(Convert.FromBase64String(input)); return Convert.ToBase64String(data); } static bool IsMacValid( string input, byte [] key, string savedMac) { string recalculateMac = GenerateMac(input, key); return recalculateMac.Equals(savedMac); } |
例如我们对数据库中LicenseNumber加密,那么我们就必须修改表结构,修改后如图:
非对称加密:
private static string Encrypt( string input, string publickey) { RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(1024); rsa.FromXmlString(publickey); byte [] encryptData = rsa.Encrypt(Encoding.UTF8.GetBytes(input), true ); return Convert.ToBase64String(encryptData); } private static string Decrypt( string input, string privatekey) { RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(1024); rsa.FromXmlString(privatekey); byte [] dencryptData = rsa.Decrypt(Convert.FromBase64String(input), true ); return Encoding.UTF8.GetString(dencryptData); } private static void GetkeyXml( out string publicKey, out string privateKey) { RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(1024); publicKey = rsa.ToXmlString( false ); privateKey = rsa.ToXmlString( true ); } |
证书加密:
static byte [] SignData( byte [] clearText, X509Certificate2 signingCertificate) { ContentInfo contentInfo = new ContentInfo(clearText); CmsSigner signer = new CmsSigner(signingCertificate); SignedCms signedCms = new SignedCms(contentInfo); signedCms.ComputeSignature(signer); return signedCms.Encode(); } static byte [] ValidateSignatureAndExtractContent( byte [] signedCmsAsBytes, ICollection< string > signingSubjects) { SignedCms signedCms = new SignedCms(); signedCms.Decode(signedCmsAsBytes); signedCms.CheckSignature( true ); foreach (SignerInfo signerInfo in signedCms.SignerInfos) { X509Certificate2 signingCertificate = signerInfo.Certificate; signingSubjects.Add(signingCertificate.Subject); } return signedCms.ContentInfo.Content; } static byte [] EncryptWithCertificate( byte [] clearText, X509Certificate2 certificate) { ContentInfo contentInfo = new ContentInfo(clearText); EnvelopedCms envelopedCms = new EnvelopedCms(contentInfo); CmsRecipient recipient = new CmsRecipient(certificate); envelopedCms.Encrypt(recipient); return envelopedCms.Encode(); } static byte [] DecryptWithCertificate( byte [] cipherText) { EnvelopedCms envelopedCms = new EnvelopedCms(); envelopedCms.Decode(cipherText); envelopedCms.Decrypt(); return envelopedCms.ContentInfo.Content; } static X509Certificate2 LoadCertificateFromFile( string filename) { X509Certificate2 certificate = new X509Certificate2(); certificate.Import(ReadBinaryFile(filename)); return certificate; } static byte [] ReadBinaryFile( string filename) { FileStream f = new FileStream(filename, FileMode.Open, FileAccess.Read); int size = ( int )f.Length; byte [] data = new byte [size]; size = f.Read(data, 0, size); f.Close(); return data; } private static X509Certificate2 GetCertificateBySubjectName( string subjectName) { X509Store myStore = new X509Store(StoreName.My, StoreLocation.LocalMachine); myStore.Open(OpenFlags.ReadOnly); X509Certificate2Collection certificateCollection = myStore.Certificates.Find(X509FindType.FindBySubjectName, subjectName, true ); X509Certificate2 myCertificate = certificateCollection[0]; if (myStore != null ) myStore.Close(); return myCertificate; } |
调用方式:
string input = "Wrox Press";
byte[] clearTextAsBytes = Encoding.UTF8.GetBytes(input);
X509Certificate2 serverPublicKeyCertificate = LoadCertificateFromFile("IISExpress.cer");
X509Certificate2 signingCertificate = GetCertificateBySubjectName("test");
byte[] signedClearText = SignData(clearTextAsBytes, signingCertificate);
byte[] encryptedAndSignedData = EncryptWithCertificate(signedClearText, serverPublicKeyCertificate);
byte[] encodedUnencryptedCms = DecryptWithCertificate(encryptedAndSignedData);
List<string> signingSubjects = new List<string>();
byte[] receivedClearText = ValidateSignatureAndExtractContent(encodedUnencryptedCms, signingSubjects);
string unecnryptedString = Encoding.UTF8.GetString(receivedClearText);
Console.ReadLine();
我的计算机是win8,这里并没有用什么企业级证书,作为测试,我是用win8中IIS来创建自签名证书,然后用mmc来管理证书(http://softbbs.zol.com.cn/1/20_1370.html),所以以上的GetCertificateBySubjectName方法需要修改如下:
private static X509Certificate2 GetCertificateBySubjectName(string subjectName)
{
X509Store myStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
myStore.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certificateCollection = myStore.Certificates.Find(X509FindType.FindBySubjectName, subjectName, true);
X509Certificate2 myCertificate;
if (certificateCollection.Count > 0)
{
myCertificate = certificateCollection[0];
}
else
{
X509Certificate2[] array = new X509Certificate2[myStore.Certificates.Count];
myStore.Certificates.CopyTo(array, 0);
myCertificate = array.FirstOrDefault(x => x.FriendlyName.Equals(subjectName));
}
if (myStore != null)
myStore.Close();
return myCertificate;
}