第十四章 调试及安全性(In .net4.5) 之 对称及非对称加密

时间:2022-06-17 06:19:19

1. 概述

  本章内容包括:对称及非对称加密算法、.net中的加密类、使用哈希操作、创建和管理签名认证、代码访问权限 和 加密字符串。

2. 主要内容

  2.1 使用对称和非对称加密

    ① 对称加密:使用同一个密钥来加密和解密数据,密钥的安全传输是一个很重要的问题。

    ② 非对称加密:使用两个关联的密钥(公钥和私钥),公钥公开,私钥保密。用公钥加密的信息可以用私钥解密,反之亦然。

    ③ 对称加密 速度快,适用大数据量情况。使用两种加密算法的组合方式,可以实现大数据的加密传输。

    *密钥之外的另一种加密方式是 initialization vector(IV), 以一定的初始值随机打乱要加密的数据。

  2.2 在.net平台中加解密

    ① Advanced Encryption Standard(AES) 是一种对称加密算法。.net平台中对应的实现是 AesManaged 类。

public static void EncryptSomeText()
{
string original = "My secret data"; using(SymmatricAlgorithm symmatricAlgorithm =
new AesManaged())
{
byte[] encrypted = Encrypt(symmatricAlgorithm, original);
string roundtrip = Decrypt(symmatricAlgorithm, encrypted); Console.WriteLine("Original: {0}", original);
Console.WriteLine("Round trip: {0}", roundtrip);
}
} static byte[] Encrypt(SymmatricAlgorithm aesAlg, string plainText)
{
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.key, aesAlg.IV); using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = 
            new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
        {
            using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
            {
                swEncrypt.Write(plainText);
            }
            return msEncrypt.ToArray();
}
}
} static byte[] Decrypt(SymmatricAlgorithm aesAlg, byte[] cipherText)
{
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.key, aesAlg.IV); using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = 
            new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
        {
            using (StreamReader swDecrypt = new StreamReader(csDecrypt))
            {
                return srDecrypt.ReadToEnd();
            }
}
}
}

    ② .net平台当然也支持非对称加密。相关的类是:RSACryptoServiceProvider 和 DSACryptoServiceProvider。

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
string publicKeyXML = rsa.ToXmlString(false);
string privateKeyXML = rsa.ToXmlString(true);
UnicodeEncoding byteConvertor = new UnicodeEncoding();
byte[] dataToEncrypt = byteConvertor.GetBytes("My secrypt data"); byte[] encryptedData;
using(RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.FromXmlString(publicKeyXml);
encryptedData = rsa.Encrypt(dataToEncrypt, false);
} byte[] decryptedData;
using(RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.FromXmlString(privateKeyXml);
decryptedData = rsa.Decrypt(encryptedData, false);
} string decryptedString = ByteConveror.GetString(decryptData);
Console.WriteLine(decryptedString); //

    ③ .net平台提供了一个key container来保存非对称密钥。

string containerName = "SecretContainer";
CspParameters csp = new CspParameters() { KeyContainerName = contrainerName };
byte[] encryptedData;
using(RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(csp))
{
encryptedData = rsa.Encrypt(dataToEncrypt, false);
}

  2.3 使用哈希值

    哈希操作是将一个大数据量的数据映射到一个定长的小数据量数据上。比如将所有名字信息都映射到指定的数字。这样就可以实现高效的信息检索。

class Set<T>
{
private List<T>[] buckets = new List<T>[]; public void Insert(T item)
{
int bucket = GetBucket(item.GetHashCode());
if (Contains(item, bucket))
return;
if (buckets[bucket] == null)
buckets[bucket] = new List<T>();
buckets[bucket].Add(item);
}
public bool Contains(T item)
{
return Contains(item, GetBucket(item.GetHashCode()));
} private int GetBucket(int hashCode)
{
unchecked
{
return (int)((uint)hashCode % (uint)buckets.Length);
}
} private bool Contains(T item, int bucket)
{
if (buckets[bucket] != null)
foreach(T member in buckets[bucket])
if (member.Equals(item))
return true;
return false;
}
}

    哈希值还可以用于检查数据是否被篡改。

UnicodeEncoding byteConverter = new UnicodeEncoding();
SHA256 sha256 = SHA256.Create(); string data = “A paragraph of text”;
byte[] hashA = sha256.ComputeHash(byteConverter.GetBytes(data)); data = “A paragraph of changed text”;
byte[] hashB = sha256.ComputeHash(byteConverter.GetBytes(data)); data = “A paragraph of text”;
byte[] hashC = sha256.ComputeHash(byteConverter.GetBytes(data)); Console.WriteLine(hashA.SequenceEqual(hashB)); // Displays: false
Console.WriteLine(hashA.SequenceEqual(hashC)); // Displays: true

  2.4 创建和管理签名认证

    makecert -n “CN=WouterDeKort” -sr currentuser -ss testCertStore

public static void SignAndVerify()
{
   string textToSign = “Test paragraph”;
    byte[] signature = Sign(textToSign, “cn=WouterDeKort”);
    // Uncomment this line to make the verification step fail
    // signature[0] = 0;
    Console.WriteLine(Verify(textToSign, signature));
} static byte[] Sign(string text, string certSubject)
{
    X509Certificate2 cert = GetCertificate();
    var csp = (RSACryptoServiceProvider)cert.PrivateKey;
    byte[] hash = HashData(text);
    return csp.SignHash(hash, CryptoConfig.MapNameToOID(“SHA1”));
} static bool Verify(string text, byte[] signature)
{
    X509Certificate2 cert = GetCertificate();
    var csp = (RSACryptoServiceProvider)cert.PublicKey.Key;
    byte[] hash = HashData(text);
    return csp.VerifyHash(hash, 
        CryptoConfig.MapNameToOID(“SHA1”), 
        signature);
} private static byte[] HashData(string text)
{
    HashAlgorithm hashAlgorithm = new SHA1Managed();
    UnicodeEncoding encoding = new UnicodeEncoding();
    byte[] data = encoding.GetBytes(text);
    byte[] hash = hashAlgorithm .ComputeHash(data);
    return hash;
} private static X509Certificate2 GetCertificate()
{
    X509Store my = new X509Store(“testCertStore”, 
        StoreLocation.CurrentUser);
    my.Open(OpenFlags.ReadOnly);     var certificate = my.Certificates[];     return certificate;
}

  2.5 使用代码访问授权

    使用 code access security(CAS),应用程序可以被限制访问指定类型的资源,执行指定类型的操作。

    ① Declarative CAS

[FileIOPermission(SecurityAction.Demand,
    AllLocalFiles = FileIOPermissionAccess.Read)]
public void DeclarativeCAS()
{
    // Method body
}

    ② Imperative CAS

FileIOPermission f = new FileIOPermission(PermissionState.None);
f.AllLocalFiles = FileIOPermissionAccess.Read;
try
{
    f.Demand();
}
catch (SecurityException s)
{
    Console.WriteLine(s.Message);
}

  2.6 使用加密字符串

    传统的string类型无法保证字符串信息的保密性。

    使用System.Security.SecureString的优势:

    ① 内容是加密的。 ② 保存到指定的内存区域,不会被垃圾回收器四处移动。

    ③ 内容可变,可以标记为只读类型。 ④ 实现了IDisposable接口,可以确保在用完后被移除。

    为了降低初始化时字符串信息的安全风险:

using (SecureString ss = new SecureString())
{
    Console.Write(“Please enter password: “);
    while (true)
    {
        ConsoleKeyInfo cki = Console.ReadKey(true);
        if (cki.Key == ConsoleKey.Enter) break;         ss.AppendChar(cki.KeyChar);
        Console.Write(“*”);
    }
ss.MakeReadOnly();
}

    从SecureString中获取字符串做常规使用

public static void ConvertToUnsecureString(SecureString securePassword)
{
    IntPtr unmanagedString = IntPtr.Zero;
   try
    {
        unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(securePassword);
        Console.WriteLine(Marshal.PtrToStringUni(unmanagedString));
    }
    finally
    {
        Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
    }
}

3. 总结

  ① 对称加密算法使用同一个key来加密和解密数据。

  ② 不对称加密算法使用关联的公钥和私钥来加解密数据。

  ③ 哈希操作是将大数据量的数据转化为较小的哈希码的过程。

  ④ 数字签名技术可用于验证作者的授权信息。

  ⑤ CAS用于限制程序对资源的访问和对具体操作的执行。

  ⑥ System.Security.SecureString用于更好的在内存中保存敏感数据。