日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[信息安全] 1.密码工具箱

發(fā)布時間:2023/12/4 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [信息安全] 1.密码工具箱 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

0. 何謂安全?

對于信息安全性的重要性,我想大家都不會否認(rèn)。那么具體來說應(yīng)該具有哪些特性才能稱之為安全呢?舉個簡單的例子:我給你發(fā)送一條消息“借給我100元”,當(dāng)你收到這條消息并且處理后你的賬戶里面會少出來100塊,我的賬戶會多出來100塊。在這個過程中,你是消息接收方,我是消息發(fā)送方。

  • 作為通信雙方的你我都不希望讓其他人能讀懂這條消息,這是信息的機(jī)密性即消息在傳遞過程中不被其他人解讀

  • 作為通信雙方的你我都不希望消息內(nèi)容變成"借老子1000塊!"(操,借錢還這么牛逼,100塊都不給你,還要1000塊!死去...),這是信息的完整性即可以校驗出信息在傳送過程中是否被篡改。

  • 作為消息接收方的你需要確認(rèn)是不是真正的我給你發(fā)的借錢的消息吧,會不會是個詐騙犯要騙我100塊!這是對信息的認(rèn)證即接收者要可以驗證消息的發(fā)送者確實是自己希望的發(fā)送者

  • 作為消息接收方的你肯定不希望在借給了我100塊之后,我耍無賴失口否認(rèn)說沒借過你錢,這是信息的不可否認(rèn)性即消息發(fā)送者不可以否認(rèn)說這個信息不是我發(fā)送的

  • 總結(jié)來說,在通信過程中,滿足這4個特征:機(jī)密性完整性,認(rèn)證,不可否認(rèn)性,就可以認(rèn)為信息是安全的。那么接下來的幾個小節(jié)來介紹一下有那些工具可以使得我們在傳遞消息的時候具有以上4個特征。

    1. 對稱密碼-對稱密鑰(Symmetric Cryptography)

    對稱密碼加密可以保障信息的機(jī)密性。舉一個簡單的例子,一把鎖,兩把相同的鑰匙,就是對稱密碼;即:使用相同的密鑰來加密和解密。沒有密鑰的其他人是無法解讀信息的真正內(nèi)容是什么的。常見到兩個對稱加密標(biāo)準(zhǔn)有DES和AES。

    DES是一種對稱密鑰加密算法,在1976年被美國聯(lián)邦政府的國家標(biāo)準(zhǔn)局確定為聯(lián)邦資料處理標(biāo)準(zhǔn),隨后在國際上廣泛流傳開來。它基于使用56位密鑰的對稱算法?,F(xiàn)在現(xiàn)在已經(jīng)不是一種安全的加密方法,主要因為它使用的56位密鑰過短。后來又發(fā)展出了3DES(即執(zhí)行三次DES加密)。由于DES已經(jīng)不再安全,后來又推出了新的對稱加密標(biāo)準(zhǔn)AES,采用的算法為Rijndael。算法的具體實現(xiàn)邏輯這里不去解釋,這里關(guān)注的是如何利用它們(即,保障信息的機(jī)密性的手段)。看一下簡單的加密解密的數(shù)學(xué)公式:

  • 加密:encrypted_data = encrypt_function(message, key)

  • 解密:message = decrypt_function(encrypted_data, key)

  • C#使用AES的代碼如下:

    /// <summary>
    /// ?AES加密
    /// </summary>
    /// <param name="key">128bit,192bit,125bit</param>
    /// <returns></returns>
    public static byte[] AESEncrypt(this byte[] value, byte[] key) { ? ?//todo 參數(shù)檢查using (var symmetricAlgorithm = Aes.Create()){symmetricAlgorithm.Key = key;symmetricAlgorithm.Mode = CipherMode.ECB;symmetricAlgorithm.Padding = PaddingMode.PKCS7; ? ?
    ? ?
    //加密using (var encryptor = symmetricAlgorithm.CreateEncryptor()){ ? ? ? ? ? ?return encryptor.TransformFinalBlock(value, 0, value.Length);}} }

    /// <summary>
    /// ?AES解密
    /// </summary>
    /// <param name="key">128bit,192bit,125bit</param>
    /// <returns></returns>
    public static byte[] AESDecrypt(this byte[] value, byte[] key) { ?
    ?
    //todo 參數(shù)檢查using (var symmetricAlgorithm = Aes.Create()){symmetricAlgorithm.Key = key;symmetricAlgorithm.Mode = CipherMode.ECB;symmetricAlgorithm.Padding = PaddingMode.PKCS7; ? ? ? ?

    //解密using (var encryptor = symmetricAlgorithm.CreateDecryptor()){ ? ? ? ? ? ?return encryptor.TransformFinalBlock(value, 0, value.Length);}} }static void Main() { ? ?var value = "lnh".ToBytes(Encoding.UTF8); ? ?//構(gòu)造128bit的key,guid正好是128,權(quán)且當(dāng)作key了。var key = Guid.NewGuid().ToByteArray(); ? ?var encryptedData = value.AESEncrypt(key); ? ?var decryptedData = encryptedData.AESDecrypt(key); ? ?var decryptedDataString = Encoding.UTF8.GetString(decryptedData);Console.WriteLine(); }

    .Net庫已經(jīng)封裝好了一些對稱加密的類,開箱即用:

    1.1 遺留問題

    密鑰配送問題:共享的密鑰如何交到接受消息方的手上呢?雙方可以事先共同約定一個密鑰,但是這種辦法是無法滿足互聯(lián)網(wǎng)規(guī)模的需要的,互聯(lián)網(wǎng)規(guī)模的環(huán)境是假設(shè)通信雙方事先并不知道對方的存在,怎么事先約定呢,行不通吧。

    下面接下來的公鑰密鑰可以解決這個問題。

    2. 公鑰密碼-非對稱密鑰(Asymmetric Cryptography)

    對稱密碼加密可以解決信息的機(jī)密性的問題,但是卻無法提供雙方如何才能得到加密所用密鑰的途徑。我們回到最初的目的想一想,我們想要的機(jī)密性的核心在于別人無法取得信息的真實內(nèi)容,也就是解密;而如何生成這個機(jī)密的信息,其實并不是我們關(guān)注的點,你能生成,他能生成,都沒區(qū)別,只要我控制住只有我才能解密,那么機(jī)密性的問題就解決了。所以解決密鑰配送的問題的關(guān)鍵就在于,把密鑰分成兩部分,一個加密用,一個解密用,它們總是成對出現(xiàn)的。配送的是加密用的密鑰(也叫公鑰),解密用的叫私鑰,這個只有我自己知道,不會在任何地方傳輸,那么也就不存在配送的問題了。

    其實很多計算機(jī)中的問題都是無解的,往往卻又是有解決辦法的,它的解決辦法其實并不是直接的解決這個問題,而是規(guī)避掉這個問題,使得它不在是一個問題的。比如密鑰配送的問題,如果說我們有安全的方式解決密鑰配送的問題,直接使用這個安全的方式配送我們想要傳遞的信息不就是了,我們還繞個彎配送密鑰干什么呢。公鑰密碼其實并未解決密鑰配送的問題,而是使得它不再是個問題,即:公鑰可以公開給任何人,不再需要保密(本質(zhì)上來說,密鑰和待加密的信息同樣重要),而是通過控制解密來達(dá)到我們想要的機(jī)密性,繞過了如何機(jī)密的配送密鑰的問題。

    公鑰密碼就是這么一個簡單的原理:公鑰(=public key)加密,私鑰(=private key)解密,它可以保障信息的機(jī)密性,同時解決密鑰的配送問題。那么這個時候通信雙方的流程就是這樣的:

  • 發(fā)送方向接收方請求一個??public?key? ;

  • 發(fā)送方使用?public?key?加密消息,?public?key?和加密的消息泄露都沒關(guān)系,因為只有?private?key?才能解密;

  • 接收方用?private?key?解密消息。

  • 至于如何產(chǎn)生出來這樣一對?public?key?和?private?key?以及相對于的加密解密算法,這其中涉及到很復(fù)雜的數(shù)學(xué)問題,這里就不展開介紹了(筆者也不懂...)。我們看一下最廣泛使用的公鑰密碼算法RSA在C#里面怎么使用吧:

    /// <summary>
    /// ?RSA加密
    /// </summary>
    /// <param name="publicKey">公鑰</param>
    /// <returns></returns>
    public static byte[] RSAEncrypt(this byte[] value, string publicKey) { ? ?//todo 參數(shù)檢查using (var asymmetricAlgorithm = new RSACryptoServiceProvider()){asymmetricAlgorithm.FromXmlString(publicKey);
    ? ? ? ?
    return asymmetricAlgorithm.Encrypt(value,false);} }

    /// <summary>
    /// ?RSA解密
    /// </summary>
    /// <param name="privateKey">私鑰</param>
    /// <returns></returns>

    public static byte[] RSADecrypt(this byte[] value, string privateKey) { ? ?//todo 參數(shù)檢查using (var asymmetricAlgorithm = new RSACryptoServiceProvider()){asymmetricAlgorithm.FromXmlString(privateKey); ? ?
    ?? ?
    return asymmetricAlgorithm.Decrypt(value,false);} }

    static void Main() { ?
    ?
    string privateKey; ?
    ?
    string publicKey; ?
    ??
    using (var asymmetricAlgorithm = RSA.Create()){privateKey = asymmetricAlgorithm.ToXmlString(true);publicKey = asymmetricAlgorithm.ToXmlString(false);} ?
    ?
    var value = "lnh".ToBytes(Encoding.UTF8); ? ?//公鑰加密var encryptedData = value.RSAEncrypt(publicKey); ? ?//私鑰解密var decryptedData = encryptedData.RSADecrypt(privateKey); ?
    ?
    var decryptedDataString = Encoding.UTF8.GetString(decryptedData);Console.WriteLine(); }

    .Net庫中已經(jīng)提供了公鑰密碼相關(guān)的類,開箱即用:

    2.1 對公鑰密鑰的攻擊

    中間人攻擊:這鐘類型的攻擊發(fā)生在上述流程中的第一步,即發(fā)送方A向接收方B請求?public?key?的時候。這時有一個攔路打劫的家伙M,截獲了這個?publickey?,自己據(jù)為己有。然后M把自己的一個?public?key?給到了A,A是渾然不覺,傻乎乎的用這個假的?public?key?加密了信息,發(fā)送了出去,這時候M攔截到了這個消息,用自己的?private?key?解密了這個消息,然后篡改一番,用真正的?public?key?進(jìn)行加密,發(fā)給了B。這個時候B以為是A發(fā)送的,A也以為自己發(fā)給了B,其實都被M給玩了...文字可能不是很清晰,看圖:

    2.2 遺留問題

    公鑰的認(rèn)證問題:公鑰密鑰可以解決規(guī)避掉的配送問題,但是新問題又來了,這個公鑰真的是你的嗎?針對上述的中間人攻擊,其實我們發(fā)現(xiàn),獲取公鑰的這一方并不能確認(rèn)自己收到的公鑰就是自己真正請求的那一方提供的。這個問題先放一放(后續(xù)會介紹),下面先看看保障信息的完整性方面有那些工具可用。

    3.?密碼散列函數(shù)(Cryptographic hash function)

    密碼散列函數(shù)可以保障的信息完整性,用來校驗要傳遞的信息是否被篡改過。比如通常在下載文件的時候,官方的網(wǎng)站上都會列出來其MD5或者SHA1的值來校驗。它的工作原理和要求大致如下:

  • 輸入一組數(shù)據(jù)message,然后得到一組簡短的數(shù)據(jù)hash,只要是采用相同的算法,輸入message就能得到hash:hash = hash_function (message)

  • 其過程是不可逆的,你不能由hash得出message;

  • 滿足message的微小變化會(比如只改動1字節(jié))會使得hash產(chǎn)生巨大的變化(就好比兩個雙胞胎,各處都很像,但是他們的指紋卻不是相同的);

  • 兩組不同的消息message1和message2,不能得出相同的hash(理論上可以,只是要盡可能的使這個過程困難)。

  • 常用的密碼散列函數(shù)(算法)有Message Digest Algorithm以及Secure Hash Algorithm。

    3.1 MD5(Message Digest Algorithm 5)

    中文明為消息摘要算法第五版,這也說明其實它也有前面幾個版本,比如MD4(這里就不介紹了)。MD5算法是輸入任意長度的數(shù)據(jù)(Message),然后算出固定長度的數(shù)據(jù)?16byte=128bits?,用16進(jìn)制表示這16個byte就是32位。C#使用MD5的代碼如下:

    1 /// <summary>
    2
    /// MD5摘要算法
    3
    /// </summary>
    4
    /// <param name="value"></param>
    5 /// <returns>128 bits,16 byte array</returns>
    6
    public static byte[] ToMD5(this byte[] value)
    7
    {
    8
    if (value == null || value.Length == 0)
    9 ? ?{ ? ?
    10 throw new ArgumentNullException(nameof(value));
    11 ? ?} ? ?
    12 using (var hashAlgorithm = MD5.Create())
    13 ? ?{ ? ?
    14 return hashAlgorithm.ComputeHash(value);
    15 ? ?} ? ?
    16 }

    再一次指出,md5的結(jié)果是固定的?16byte=128bits?,用16進(jìn)制表示是32個字符。網(wǎng)上由很多的16進(jìn)制16個字符的md5,其實這都不是完整的md5,只是截取了32位中的16位而已。

    3.2 SHA ( Secure Hash Algorithm )

    ?從使用者的角度來看,MD5和SHA沒有什么本質(zhì)區(qū)別,差異在于其算法的實現(xiàn)方式,生成的hash的長度,其抗攻擊破解的難度不一樣。此外由于SHA的強(qiáng)度比MD5要大,所以在計算SHA的時候,所消耗的資源(時間,空間都有)也會比MD5要多。即使如此,現(xiàn)在MD5(128bit)和SHA-1(160bit)均已遭到了破解:https://news.cnblogs.com/n/563589/。SHA家族現(xiàn)有的以下成員如下有SHA-1(160)、SHA-2(SHA-224,SHA-256,SHA-384,SHA-512)和SHA-3(SHA3-224,SHA3-256,SHA3-384,SHA3-512)。C#中使用SHA256的代碼如下:

    /// <summary>
    /// SHA256哈希算法
    /// </summary>
    /// <returns>256 bits,32 byte array</returns>
    public static byte[] ToSHA256(this byte[] value) { ? ?if (value == null || value.Length == 0){ ? ? ? ?throw new ArgumentNullException(nameof(value));} ? ?using (var hashAlgorithm = SHA256.Create()){ ? ? ? ?return hashAlgorithm.ComputeHash(value);} }

    .NET的庫已經(jīng)幫我們封裝好了密碼散列函數(shù)相關(guān)的類,開箱即用。

    3.3 密碼散列函數(shù)的實際應(yīng)用

  • 檢查文件是否被修改:上面一開始舉得例子下載文件的例子。

  • 基于口令的加密:通常我們在存儲用戶的密碼的時候,都會采用這種方式(除非你是csdn),一般還會輔助的加上鹽。

  • 消息認(rèn)證碼:后面介紹到到。

  • 數(shù)字簽名:后面會介紹到。

  • 偽隨機(jī)數(shù)生成器:后面會介紹到。

  • 3.4 針對密碼散列函數(shù)的攻擊

  • 強(qiáng)碰撞性攻擊:比如上面提到的Google破解了SHA-1,即使用大量的計算來找出兩個數(shù)據(jù)message不一樣,但是hash值卻一樣的過程,如果找到了這樣的兩塊數(shù)據(jù),那么再使用這個hash作為數(shù)據(jù)的完整性校驗的手段,其實已經(jīng)沒有意義了。解決辦法是升級SHA-2,增大計算出這樣兩塊數(shù)據(jù)的難度。

  • 暴力破解:比如網(wǎng)上很多的MD5的解密,其實原理在于他們有大量的MD5 hash庫,比如?123456?的MD5是?e10adc3949ba59abbe56e057f20f883e?,那么在你給我一個?e10adc3949ba59abbe56e057f20f883e?的時候,我就知道你的原文是?123456?。解決辦法是加鹽,增大這種暴力比對的難度。

  • 針對上面兩種攻擊方式都是在于增加破解難度,使其在現(xiàn)有的計算能力下不能輕易的被攻破,沒有絕對的安全,只是相對上來說是安全的,當(dāng)破解你帶來的收益要低于其破解成本的時候,你才是安全的。

    3.5 遺留問題

    hash被篡改了:比如上面下載文件的時候官方會給出MD5或者SHA1的hash值,這里我們假設(shè)一下,官方提供hash值的渠道被黑掉了,給了你一個篡改過的hash值,然后你下載了一個被篡改過的文件,你是分辨不出來的。其實我們下載文件,然后比對官方給的hash值,這里是假設(shè)官方的hash值是沒有被篡改的。

    那么接下來的消息認(rèn)證碼MAC是可以解決這個問題。

    4. 消息認(rèn)證碼(Message Authentication Code)

    消息認(rèn)證碼(MAC)的作用就是在保障完整性的基礎(chǔ)上,同時提供認(rèn)證(認(rèn)證=消息是來自真正的發(fā)送者的功能,用來解決上述密碼散列函數(shù)遺留的問題??梢院唵蔚倪@樣理解,MAC是在密碼散列函數(shù)+共享密鑰后算出的hash值,由于密鑰是只有通信雙方才知道的,那么就可以認(rèn)為通過MAC得到的hash可以保障信息的完整性以及同時提供認(rèn)證的能力。這里我們假設(shè)雙方不存在密鑰配送的問題(即雙方已經(jīng)持有相同的密鑰,至于是通過什么方式傳遞的,這里先不關(guān)心)。

    使用密碼散列函數(shù)可以實現(xiàn)MAC,這種方式稱為HMAC(Hash Message Authentication Code):https://tools.ietf.org/html/rfc2104?和?https://en.wikipedia.org/wiki/Hash-based_message_authentication_code。計算公式可以簡單的理解為:mac = mac_function (message,key)。C#中使用HMAC的代碼如下:

    /// <summary>
    /// HMACSHA1算法
    /// </summary>
    /// <returns>160 bits,20 byte array</returns>
    public static byte[] ToHMACSHA1(this byte[] value,byte[] key) { ?
    ?
    if (value == null || value.Length == 0){ ? ? ? ?throw new ArgumentNullException(nameof(value));} ? ?if (key == null || key.Length == 0){ ? ? ? ?throw new ArgumentNullException(nameof(key));} ? ?using (var macAlgorithm =new HMACSHA1()){macAlgorithm.Key = key; ? ?
    ? ?
    return macAlgorithm.ComputeHash(value);} }

    static void Main() { ? ?var value = "lnh".ToBytes(); ?
    ?
    var key = "123".ToBytes(); ?
    ?
    var mac = value.ToHMACSHA1(key);Console.WriteLine(); }

    .Net類庫中開箱即用的MAC相關(guān)的類,開箱即用:

    4.1 消息認(rèn)證碼的實際應(yīng)用

  • SWIFT:此SWIFT非蘋果的Swift語言,而是Society for Worldwide Interbank Financial(環(huán)球銀行金融電信協(xié)會)的簡寫。在銀行之間進(jìn)行傳遞交易消息時,會用到MAC來確認(rèn)消息的完整性以及對消息進(jìn)行認(rèn)證。在沒有使用公鑰密碼進(jìn)行密鑰交換之前,消息認(rèn)證碼使用的共享密鑰時靠人力通過11路來完成的。

  • IPsec:增強(qiáng)版Ip協(xié)議,用來認(rèn)證和校驗消息的完整性。

  • SSL/TLS:后續(xù)會介紹到。

  • 4.2 針對消息認(rèn)證碼的攻擊

  • 重放攻擊:比如你給我轉(zhuǎn)賬100元,攜帶了mac的消息,其實我并不用破解你的消息和mac,原封不動拿你的消息重復(fù)給我轉(zhuǎn)賬就是了,你信不信我可以把你賬戶里面所有的錢都變成我的...解決辦法是對消息添加編號和時間戳,使得消息接收方針對這個消息只處理一次。

  • 密鑰推測攻擊:和密碼散列碼的暴力攻擊是類似的,不再細(xì)說。

  • 4.3 遺留問題

    消息不是我發(fā)送的,是你自己偽造的:基于MAC的原理是在于通信雙方共享密鑰,那么消息接收方可以判斷消息是來自真正的發(fā)送者,但是卻無法向第三者證明這一點,為什么呢?因為消息的接收方也有密鑰啊,消息發(fā)送者完全可以說這是消息接收者自己用這個共享密鑰生成的消息,畢竟密鑰雙方都有。

    那么接下來的數(shù)字簽名是可以解決這個問題。

    5. 數(shù)字簽名(Digital Signature)

    ?上面的MAC可以保障信息的完整性,同時具有提供消息認(rèn)證的能力,但是又遺留了一個可以否認(rèn)消息是我發(fā)送的問題。究其原因在于通信雙方使用了同一個密鑰來生成MAC,你說是他生成的,他說是你生成的。那么怎么解決呢,其實也簡單,雙方使用不同的密鑰;消息發(fā)送方使用簽名密鑰生成一個“簽名”(就像簽字畫押按手印一樣的道理,表示我承認(rèn)這些信息是我發(fā)送的),消息接收方使用另外驗證密鑰來驗證這個簽名,這其實就是數(shù)字簽名。

    數(shù)字簽名對簽名密鑰和驗證密鑰進(jìn)行了區(qū)分,驗證密鑰無法生成簽名;此外簽名密鑰只能由簽名人持有,而驗證密鑰則可以由任何想要驗證簽名的人持有。回想一下,這個簽名密鑰和驗證密鑰是不是感覺似曾相識,對了,和上面我們提到的公鑰密碼中的公鑰和私鑰非常類似吧。

    公鑰密碼:密鑰分為加密密鑰和解密密鑰,用加密密鑰無法進(jìn)行解密;解密密鑰只有需要解密的人持有,而加密密鑰則是任何需要加密的人都可以持有。

    實際上,數(shù)字簽名和公鑰密鑰有著非常緊密的聯(lián)系,簡單點來說,數(shù)字簽名是通過把公鑰密碼“反過來用”來實現(xiàn)的


    私鑰 / 簽名密鑰公鑰 / 驗證密鑰
    公鑰密碼接收者解密時使用發(fā)送者加密時使用
    數(shù)字簽名簽名者生成簽名時使用驗證者驗證簽名時使用
    誰持有密鑰個人持有只要需要,任何人都可以持有

    數(shù)字簽名的實現(xiàn)是:簽名人用私鑰加密{一段信息}來生成簽名,驗證者使用公鑰來解密這個簽名,如果可以解密成功,則說明驗證成功。覺得很奇怪是不是?為什么能用公鑰解密就證明簽名驗證通過了呢?其實這是由于私鑰和密鑰是成對出現(xiàn)的(具有嚴(yán)密的數(shù)學(xué)關(guān)系),只有公鑰才能解密與之配對的私鑰加密的信息,那么既然能夠解密,那么這個消息肯定是持有私鑰的這一方生成的。你估計還會想到一個問題,公鑰是公開的呀,你有我由他也有,那么私鑰生成的這個加密的簽名大家都可以解密,根本沒有機(jī)密性啊。是的,這樣理解是完全正確的,私鑰加密的信息是不具備機(jī)密性的;這是因為數(shù)字簽名是用來提供消息的不可否認(rèn)性的,它并不關(guān)心機(jī)密性的問題。

    上面我們說到“簽名人用私鑰加密{一段信息}來生成簽名”。那么問題來了,這{一段信息}是什么信息?關(guān)于這一段信息我們由兩種選擇:1是消息本身,2是消息的hash。

    下圖是對消息本身進(jìn)行簽名的過程:

    下圖是對消息的hash進(jìn)行簽名的過程:

    實際中我們一般采用的是對消息的hash進(jìn)行簽名的方式,因為消息本身可能非常大,加密解密過程會非常消耗資源。再C#中使用RSA來實現(xiàn)數(shù)字簽名:

    /// <summary>
    /// 數(shù)字簽名
    /// </summary>
    /// <returns></returns>
    public static byte[] DigitalSignature(this byte[] value, string privateKey) { ?
    ??
    using (var asymmetricAlgorithm = new RSACryptoServiceProvider()){asymmetricAlgorithm.FromXmlString(privateKey); ?
    ?? ? ?
    return asymmetricAlgorithm.SignData(value, SHA1.Create());} }

    /// <summary>
    /// 數(shù)字簽名驗證
    /// </summary>
    /// <returns></returns>
    public static bool DigitalSignatureVerify(this byte[] value, string publicKey,byte[] digitalSignature) { ? ?using (var asymmetricAlgorithm = new RSACryptoServiceProvider()){asymmetricAlgorithm.FromXmlString(publicKey); ? ? ? ?return asymmetricAlgorithm.VerifyData(value, SHA1.Create(), digitalSignature);} }

    static void Main() { ? ?string privateKey; ? ?string publicKey; ?
    ?
    using (var asymmetricAlgorithm = RSA.Create()){privateKey = asymmetricAlgorithm.ToXmlString(true);publicKey = asymmetricAlgorithm.ToXmlString(false);} ? ?var value = "lnh".ToBytes(Encoding.UTF8); ?
    ?
    //用私鑰生成數(shù)字簽名var digitalSignature = value.DigitalSignature(privateKey); ?
    ??
    //用公鑰驗證數(shù)字簽名var verified = value.DigitalSignatureVerify(publicKey, digitalSignature);Console.WriteLine(); }

    數(shù)字簽名本身的實現(xiàn)是使用了公鑰密鑰相關(guān)的算法。

    6.1 數(shù)字簽名的實際應(yīng)用

  • 公鑰證書:上面在介紹公鑰密碼的時候,遺留的一個公鑰認(rèn)證的問題,即我們怎么才能知道自己拿到的公鑰是不是真正的公鑰,而不是被第三方偽造的呢?可以把公鑰當(dāng)作消息,然后施加數(shù)字簽名,所得到的就是公鑰證書,關(guān)于證書的知識后續(xù)博客會介紹。

  • SSL/TLS:SSL/TLS在認(rèn)證服務(wù)器是否合法的時候會使用服務(wù)器證書,就是上面提到的公鑰證書;于此相對,服務(wù)器在對客戶端進(jìn)行認(rèn)證的時候,也會使用客戶端證書。關(guān)于SSL/TLS后續(xù)博客會介紹。

  • 6.2 針對數(shù)字簽名的攻擊

  • 中間人攻擊:在公鑰密碼這一小節(jié)中提到了中間人攻擊,因為數(shù)字簽名其實就是使用它來實現(xiàn)的,那么對于數(shù)字簽名來說,中間人攻擊也是具有相同的威脅。

  • 對密碼散列函數(shù)的攻擊:數(shù)字簽名使用了密碼散列函數(shù),那么數(shù)字簽名也面臨同樣的威脅。

  • 利用數(shù)字簽名攻擊公鑰密鑰:這塊好復(fù)雜,筆者研究明白再補(bǔ)充( ╯□╰ )。。。

  • 6.3 遺留問題

    數(shù)字簽名可以識別出篡改和偽裝,還可以防止否認(rèn),也就是說數(shù)字簽名可以提供信息安全中的完整性、認(rèn)證不可否認(rèn)性這3點的保障(很強(qiáng)大有木有)。然而這一切都基于一個假設(shè)“公鑰必須是真正的發(fā)送者提供的”,和公鑰密鑰陷入了同一個問題。我們發(fā)現(xiàn)自己陷入了一個死循環(huán):數(shù)字簽名可以用來識別篡改、偽裝以及否認(rèn)的,但是為此我們又需要從一個沒有被偽裝的真正的發(fā)送者那里得到一個沒有被篡改的密鑰......這是一個雞生蛋蛋生雞的問題。

    細(xì)心的讀者或許可以看出來,上面我們的加密、散列、mac,簽名也好,消費的數(shù)據(jù)都是byte[],而byte[]是不方便書寫、打印、復(fù)制和粘貼的,下面看一看byte[]編碼的問題。換換腦子,雞生蛋還是蛋生雞的問題放一放先。

    7. 編碼(Encoding)

    我們知道計算機(jī)的任何數(shù)據(jù)底層都是由0和1這樣的二進(jìn)制表示的,不管你是文本,圖片,音頻或者視頻還是exe等等,都是01這樣的二進(jìn)制。比如我們上面列舉的各種算法,其實它們都是以byte(=8bit)作為輸入的,輸出也是如此。很多場景下,傳輸?shù)臄?shù)據(jù)被限制在ASCII碼表(https://tools.ietf.org/html/rfc20)以內(nèi),比如url中的字符是ASCII中很小的一部分。在https://tools.ietf.org/html/rfc4648中定義了base16,base32,base64這幾種編碼方式,最常用的方式由16進(jìn)制(也叫base16)和base64編碼。

    7.1 16進(jìn)制(base16)

    16進(jìn)制的核心在于把一個byte(=8bit)分割成兩組4個bit。那么這四個bit組合起來最小的數(shù)字是0(2?),最大是16(2?)。編碼后每一組(4個bit)都轉(zhuǎn)成十進(jìn)制,對應(yīng)一個字母(使用1個byte表示),也就是相當(dāng)于對原始的數(shù)據(jù)放大了2倍,其字母表如下:

    舉個簡單的例子如下,比如“”這個原始字符,我把它先用UTF8取得byte數(shù)組,然后把byte數(shù)組轉(zhuǎn)成16進(jìn)制:

    1 public static string ToHexString(this byte[] value) 2 { 3 return BitConverter.ToString(value).Replace("-",""); 4 } 5 6 public static byte[] ToBytes(this string value, Encoding encoding = null) 7 { 8 if (value==null) 9 ? ?{10 throw new ArgumentNullException(nameof(value));11 ? ?}12 if (encoding==null)13 ? ?{14 encoding = Encoding.UTF8;15 ? ?}16 return encoding.GetBytes(value);17 }18 19 static void Main()20 {21 var hex = "".ToBytes().ToHexString();22 //hex=E69D8E23 ? ?Console.WriteLine(hex);24 }

    具體的編碼流程:

    原始數(shù)據(jù)
    (1).轉(zhuǎn)成byte數(shù)組(UTF8)230157142
    (2).二進(jìn)制形式111001101001110110001110
    (3).按照4bit一組分割111001101001110110001110
    (4).對應(yīng)的10進(jìn)制數(shù)值146913814
    (5).對應(yīng)的16進(jìn)制字母E69D8E
    (6).16進(jìn)制編碼E69D8E

    ?其中核心步驟在(2)-(5),下面詳細(xì)解釋以下:

  • (1)把原始數(shù)據(jù)轉(zhuǎn)成byte數(shù)組,我這里用的是UTF8編碼,轉(zhuǎn)成了3個byte(如果你用GB2312,“李”這個字符對應(yīng)的就不是這三個byte了,而是另外的兩個byte:?192?238?);如果你的數(shù)據(jù)原本就一個音頻文件或者其他二進(jìn)制文件,那么你得到的就直接是一個byte的數(shù)組。這一步的目的在于準(zhǔn)備數(shù)據(jù)。還并未進(jìn)入到16進(jìn)制編碼的環(huán)節(jié)。

  • (2)把第一步得到的byte數(shù)組以二進(jìn)制形式展開。

  • (3)依次把(2)按照4個bit為一組進(jìn)行分割。

  • (4)把(3)的每一組都轉(zhuǎn)成10進(jìn)制的數(shù)值。

  • (5)根據(jù)(4)得到的數(shù)值查找16進(jìn)制的編碼表,得到對應(yīng)的字母。

  • (6)把(5)中得到的字母依次組合在一起,就是最終的結(jié)果。

  • 7.2 base64編碼

    base64也可以說是64進(jìn)制,它是用6個bit表示一個字符,也就是2?。其實核心原理和的16進(jìn)制是一模一樣的,但是有點不同的是,當(dāng)一組byte(8bit)拆成4bit一組的的時候,是永遠(yuǎn)都可以成對的拆分的(8÷4=2);但是當(dāng)一組byte想要拆成6bit一組的時候,可能就無法正好拆分了(8÷6=1.333333.....),只有數(shù)據(jù)的bit數(shù)是8和6的最小公約數(shù)24的整數(shù)倍的情況下,才可以正好拆分,簡化點就是byte數(shù)÷3。不能整除的時候,這個時候就需要補(bǔ)上一些0湊夠6位。

    標(biāo)準(zhǔn)的base64的碼表是由:[A-Z]、[a-z]、[0-9]、“+”和“/”構(gòu)成的(26+26+10+2=64),再附加一個對齊用的“=”(個人理解這個“=”完全是多余,就像人的闌尾似的...),一共65個字符。

    除了這個標(biāo)準(zhǔn)的碼表之外,還有一些其他的碼表,主要是因為“/+=”這三個字符再一些特殊的場景下術(shù)語特殊字符,比如在url傳遞的時候,這三個字符都是特殊字符,需要替換掉,比如把“/+”換成“-_”這2個字符。還拿上面的“”舉例子(這次我們用GB2312,故意使它無法整除:李字在GB2312中使用2個byte表示,不能整除3):

    public static string ToBase64String(this byte[] value) { ? ?return Convert.ToBase64String(value); }static void Main() { ? ?var base64 = "".ToBytes(Encoding.GetEncoding("GB2312")).ToBase64String(); ? ?//base64 wO4= ? ?Console.WriteLine(base64); }

    具體的編碼流程如下:

    原始數(shù)據(jù)
    (1).轉(zhuǎn)成byte數(shù)組(GB2312)192238
    (2).二進(jìn)制形式1100000011101110補(bǔ)0補(bǔ)0





    (3).按照6bit一組分割110000001110111000
    (4).對應(yīng)的10進(jìn)制數(shù)值481456
    (5).對應(yīng)的base64字母wO4補(bǔ)=
    (6).base64編碼wO4=

    ?

    ?這個過程就不再詳細(xì)解釋了,和上面的16進(jìn)制是一樣的,不同之處在于對齊補(bǔ)上“=”。

    8. 總結(jié)一下

    以上簡單的介紹了一下信息安全方面的一些特征,以及又哪些工具可以提供這些特征的保障(均是筆者從資料中翻出來自己解讀了以下,如有錯誤之處,歡迎指正!)。具體每個工具只是從使用者的角度簡單的介紹了一下,對實現(xiàn)細(xì)節(jié)并未深入研究,感興趣的需要自己單獨再去深入了解了,這篇博客主要是個入門的科普介紹而已,主要參考資料是《圖解密碼技術(shù)》,以及維基百科的一些解釋(為啥給的是英文鏈接,其實我發(fā)現(xiàn)中文的維基百科的信息比英文的少的不是一點半點的)。還有一本不錯的圖書《編碼 - 隱匿在計算機(jī)軟硬件背后的語言》,個人認(rèn)為是非常棒的一本計算機(jī)科學(xué)的科普讀物。最后還留了一個雞生蛋蛋生雞的問題和公鑰密碼的認(rèn)證問題,且聽下回分解。

    9. 參考 & 引用

    代碼:https://gist.github.com/linianhui/447c23fd3f3834b6533ecd93424a3906

    書籍:

    圖解密碼技術(shù):https://book.douban.com/subject/26822106/

    編碼 - 隱匿在計算機(jī)軟硬件背后的語言 :https://book.douban.com/subject/4822685/

    鏈接:

    對稱密鑰 - DES:https://en.wikipedia.org/wiki/Data_Encryption_Standard

    對稱密鑰 - AES:https://en.wikipedia.org/wiki/Advanced_Encryption_Standard

    公鑰密鑰 - 非對稱密鑰 - Public-key cryptography:https://en.wikipedia.org/wiki/Public-key_cryptography

    公鑰密鑰 - 非對稱密鑰 - RSA:https://en.wikipedia.org/wiki/RSA

    密碼散列函數(shù):https://en.wikipedia.org/wiki/Cryptographic_hash_function

    密碼散列函數(shù) - MD5:https://en.wikipedia.org/wiki/MD5

    密碼散列函數(shù) - SHA-1:https://en.wikipedia.org/wiki/SHA-1

    密碼散列函數(shù) - SHA-2:https://en.wikipedia.org/wiki/SHA-2

    密碼散列函數(shù) - SHA-3:https://en.wikipedia.org/wiki/SHA-3

    消息認(rèn)證碼 - HMAC: Keyed-Hashing for Message Authentication:https://tools.ietf.org/html/rfc2104

    消息認(rèn)證碼 - Message Authentication Code:https://en.wikipedia.org/wiki/Message_authentication_code

    消息認(rèn)證碼 - Hash-based message authentication code :https://en.wikipedia.org/wiki/Hash-based_message_authentication_code

    數(shù)字簽名 -?https://en.wikipedia.org/wiki/Digital_signature

    編碼 - ASCII format for Network Interchange:https://tools.ietf.org/html/rfc20

    編碼 - The Base16, Base32, and Base64 Data Encodings:https://tools.ietf.org/html/rfc4648

    ?

    原文地址:http://www.cnblogs.com/linianhui/p/security-based-toolbox.html


    .NET社區(qū)新聞,深度好文,微信中搜索dotNET跨平臺或掃描二維碼關(guān)注

    總結(jié)

    以上是生活随笔為你收集整理的[信息安全] 1.密码工具箱的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。