区块链的密码学基础
原文:shuwoom.com/?p=643
一、哈希算法
(1)概念
哈希算法又稱為哈希函數、散列算法、散列函數,它能從任何數據長度生成一個固定長度的消息摘要(如下圖)。對于某個特定的消息而言,這個消息摘要(或哈希值)可以看做是這個消息的指紋,且該消息是唯一表示。哈希函數是數字簽名和驗證的核心部分。
(2)哈希算法的特性
- 單向性
哈希函數必須具有單向性,也就是說給定一個輸入,通過哈希函數可以得到一個散列值,但是反過來,給定一個散列值,是無法獲得輸入的。換句話說,就是給定一個散列值(指紋),我們不可能找到對應的消息。 - 沖突避免
很難找到兩個不同的消息,使得產生的哈希值一致(發生沖突)。 - 輸入敏感
原始數據任何微小的變動都會導致哈希值完全不一樣 - 正向快速
給定消息和哈希算法,在有限時間和有效資源內計算出哈希值
(3)哈希碰撞
哈希碰撞也就是說存在不同的消息(輸入),使得哈希函數的輸出,也就是散列值一樣,這種概率非常非常低。以下面的md5為例,兩個輸入有細微差別,但是哈希值是一樣的:
| 123456789101112131415 | # coding: utf-8import hashlib # 兩段HEX字節串,注意它們有細微差別a = bytearray.fromhex("0e306561559aa787d00bc6f70bbdfe3404cf03659e704f8534c00ffb659c4c8740cc942feb2da115a3f4155cbb8607497386656d7d1f34a42059d78f5a8dd1ef") b = bytearray.fromhex("0e306561559aa787d00bc6f70bbdfe3404cf03659e744f8534c00ffb659c4c8740cc942feb2da115a3f415dcbb8607497386656d7d1f34a42059d78f5a8dd1ef") # 輸出MD5,它們的結果一致print(hashlib.md5(a).hexdigest())print(hashlib.md5(b).hexdigest()) ### a和b輸出結果都為:cee9a457e790cf20d4bdaa6d69f01e41cee9a457e790cf20d4bdaa6d69f01e41 |
以CRC32為例,它的摘要長度為32bit,也就是說存在2^32種可能。如今互聯網頁面總數在2008年的時候就已經超過1萬億,如果采用CRC32的摘要,那么發生哈希碰撞的就很多。而MD5的摘要長度為128bit,也就是有2^128種可能,但是目前已經證明MD5算法是不安全的。同樣的SHA1算法(160bit)也被證明是不安全的,推薦使用SHA256算法才比較安全。
(4)常見哈希算法
目前比較流行的哈希算法有MD5、SHA-1和SHA-2
- MD4
MD4已經被證明時不夠安全的,不推薦使用
- MD5
MD5是MD4的改進版本,輸出是128bit。同樣,MD5也被證明了不具備強抗碰撞性,也是不夠安全的
- SHA-1
SHA是一個哈希函數族,SHA-1算法的哈希值長度為160bit,抗窮舉性比MD5和MD4更好。但是SHA-1已經被證明不具備“強抗碰撞性”(谷歌已經攻破SHA-1),
SHA-2
SHA-224、SHA-256、SHA-384,和 SHA-512 算法統稱為SHA-2,算法原理跟SHA-1類似。
總結來說,MD5和SHA-1已經不夠安全,推薦至少使用SHA-256算法。
(5)應用
哈希算法的應用主要體現在以下3個方面:
- 文件校驗
- 數字簽名
- 鑒權協議(安全通信)
二、非對稱加密技術
(1)概念
非對稱加密算法也稱為公鑰加密算法,其分為3個部分,分別是:公鑰、私鑰和加密解密算法。
非對稱加密往往需要密碼學安全偽隨機數生成器來產生一對秘鑰(公鑰和私鑰),這兩者是成對的,公鑰是可以公開的,而私鑰則是用戶自己保留。用私鑰加密的數據只有公鑰才可以解密(反過來,用公鑰加密的數據,只有私鑰可以解密)。公鑰和私鑰之間的這種數學關系,使得私鑰可以用于生成特定消息的簽名。而這個簽名可以在不暴露私鑰的前提下通過公鑰進行驗證。
也就是說我對一段消息用私鑰進行簽名(也就是加密),然后把這個數據連同簽名和我的公鑰發送給對方,對方就可以通過公鑰對簽名進行驗證(解密)對比數據從而驗證數據的有效性。
在比特幣系統中,公鑰生成的錢包地址用于接收比特幣,而私鑰則用于比特幣支付時的交易簽名。
在支付比特幣時,比特幣的所有者需要在交易中提交自己的公鑰和該交易的簽名。而比特幣網絡中所有節點可以通過所提交的公鑰和簽名進行驗證,從而確認支付者對交易的比特幣的所有權。
(2)加密、解密過程
- 加密過程:通過加密算法和公鑰對明文進行加密,得到密文
- 解密過程:通過解密算法(這里加密、解密算法要一樣)和秘鑰進行解密,得到明文。
如下圖所示,加密過程是單向的,公鑰加密后的密文只能用對應的私鑰解密。
(3)常見非對稱加密算法
- RSA
- ElGamal
- 背包算法
- Rabin(RSA的特例)
- 迪菲-赫爾曼密鑰交換協議中的公鑰加密算法
- 橢圓曲線加密算法(英語:Elliptic Curve Cryptography, ECC)
其中使用最廣泛的是RSA算法(由發明者Rivest、Shmir和Adleman姓氏首字母縮寫而來)是著名的公開秘鑰加密算法,ElGamal是另一種常用的非對稱加密算法。
(4)應用
非對稱加密算法的應用非常廣泛,下面列舉常見的幾種
- 數字簽名
- 數字證書
- 加密通信HTTPS
(5)python編程實現
生成密鑰對
| 12345678 | def create_genisus_keypair(): # 第一個節點的密鑰對 pubkey, privkey = rsa.newkeys(1024) with open('genisus_public.pem', 'w+') as f: f.write(pubkey.save_pkcs1().decode()) with open('genisus_private.pem', 'w+') as f: f.write(privkey.save_pkcs1().decode()) |
直接打開genisus_public.pem和genisus_private.pem,我們可以看到一長串的字符串。
| 12345678910111213141516171819202122 | genisus_public.pem:-----BEGIN RSA PUBLIC KEY-----MIGJAoGBAJIiGuUOlhKFQEHIr5YXa9uajM+sI5FEZ/8RJdR5EOC4Wo+9bZfyrvnuPRBtK7PJzUXHdXCaNohPzA5IuiEpkoELPyWfCozQF9FAgK2Gyf1rBeC7e2lUvuwIh5IXhRjC2Rom6wiJRWXn/W0/EezrXl8YlYmrRR1Boa9OB1RFJvJXAgMBAAE=-----END RSA PUBLIC KEY-----genisus_private.pem:-----BEGIN RSA PRIVATE KEY-----MIICYAIBAAKBgQCSIhrlDpYShUBByK+WF2vbmozPrCORRGf/ESXUeRDguFqPvW2X8q757j0QbSuzyc1Fx3VwmjaIT8wOSLohKZKBCz8lnwqM0BfRQICthsn9awXgu3tpVL7sCIeSF4UYwtkaJusIiUVl5/1tPxHs615fGJWJq0UdQaGvTgdURSbyVwIDAQABAoGAOiw7ep3A3iSPfOCQDXbLaANxNKa5DfYmVCKWZavALUUWQAxPmWJxh2rwgh6DfDHEdpe9R5MMTF0/xRvsQGQvZU2sNNhA2ebVOB4mMCPcURYWCbJXjT14IC7rfwPpYnkpiCHxP+HBS2xjMyf63vk7tKR/zCfzm9tsDAKqKuFUYPECRQCrQpiuYxp2ZnchszwR15q0HUpU8/HdCQlKdBK2fa4M2Y1xPqNjpOlQ2B8zCS3aOQ/9nhbVaRy0LqFDsUjPPJsTqbaSyQI9ANpwsv1MHkpYGlYSrCItFS1oRoD/foxByVdVORCtarA0z9xeAm8kEi9HcnZf2jsYvqHAeQsTtuPw0PvMHwJEXL0+csilztHj1zL452yKkNh/pQtIwPogttmuPHZIZxrz9gwGbHIkCixOkNN6qf5Wg281TDGUYpoRp9d75wUZsQcpH8kCPE0rvYBREO5w27UG2bslNDMbgLT4DkwcvbXVzNhAe82OitSufauoEaiUVDLPwDhakJZyehDYwSccH6ilPwJFAIhBzCQ61A2zfEJlgKeuX3OJGq1pywpnv+vFyqnDc4T6oEW9kfnrAI+6x4L4jyyHOWMNfkAPajtkQ+YwxZqUmKL8ixr0-----END RSA PRIVATE KEY----- |
加密、解密
| 12345678910111213141516 | # 導入密鑰with open('genisus_private.pem', 'r') as f: privkey = rsa.PrivateKey.load_pkcs1(f.read().encode()) with open('genisus_public.pem', 'r') as f: pubkey = rsa.PublicKey.load_pkcs1(f.read().encode()) # 明文message = 'hello world' # 公鑰加密crypto = rsa.encrypt(message.encode(), pubkey) # 私鑰解密message = rsa.decrypt(crypto, privkey).decode()print(message) |
三、數字簽名
(1)概念
數字簽名,就是只有信息的發送者才能產生的別人無法偽造的一段數字串,這段數字串同時也是對信息的發送者發送信息真實性的一個有效證明。它是進行身份鑒別和網上安全交易的通用技術。
數字簽名應用了前2節所說到的非對稱加密技術(公鑰加密算法)和哈希算法。
(2)功能
- 數字簽名主要有三個作用:
- 保證信息傳輸的完整性(完整性)
- 發送者身份認證(鑒權)
- 防止交易中發生抵賴(不可抵賴性)
數字簽名是加密過程,數字簽名驗證是解密過程。
(3)簽名和驗證
- 發送者簽名過程
數字簽名是發送方首先通過一個哈希算法將獲取信息的一個摘要
然后通過秘鑰對這個摘要進行簽名
最后把簽名和原文一起發送給接收者 - 接收者驗證過程
數字簽名驗證,接收者收到發送者發送的簽名和原文后,首先進行分離
采用跟發送者一樣的哈希算法提取原文的摘要
然后用發送者的公鑰對簽名進行解密獲得解密后的摘要
兩者對比,如果一致,則說明收到的信息是完整的,在傳輸過程中沒有被修改過。
這里,讀者細心想會發現,如果一個黑客,將發送者的私鑰和接收者手上擁有的發送者的公鑰都替換成黑客自己的私鑰和公鑰。那這個時候接收者,在驗證的時候是無法發現問題的,因為簽名用的私鑰是黑客的私鑰,驗證用的公鑰也是黑客的公鑰,兩者是成對的。這就變成了對公鑰是否合法的驗證,那么要解決這個問題就涉及到數字證書的概念(如下圖所示)。這個讀者可以看我另外寫的一篇文章《數字證書是什么》,這里就不展開講。
(4)應用
數字簽名技術的應用很廣泛,例如個人安全郵件證書、訪問安全https站點、網上簽約、電子交易等。
(5)python編程實現
首先生成一對秘鑰(公鑰和私鑰)
| 1234567891011121314151617 | # 明文message = 'hello world' # 導入密鑰with open('genisus_private.pem', 'r') as f: privkey = rsa.PrivateKey.load_pkcs1(f.read().encode()) with open('genisus_public.pem', 'r') as f: pubkey = rsa.PublicKey.load_pkcs1(f.read().encode())# 私鑰簽名signature = rsa.sign(message.encode(), privkey, 'SHA-1') # 公鑰驗證try: rsa.verify(message.encode(), signature, pubkey)except rsa.pkcs1.VerificationError: print 'invalid' |
關注我的微信公眾號(shuwoom的博客),每周定期推送文章:
參考:
https://www.jianshu.com/p/bf1d7eee28d0
https://zh.wikipedia.org/wiki/%E6%95%A3%E5%88%97%E5%87%BD%E6%95%B8
http://www.infoq.com/cn/news/2017/02/google-first-sha1-collision
http://blog.jobbole.com/106733/
https://baike.baidu.com/item/%E6%95%B0%E5%AD%97%E7%AD%BE%E5%90%8D
https://blog.csdn.net/u011630575/article/details/53241027
總結
- 上一篇: 如何学习Python数据爬虫?
- 下一篇: API设计中防重放攻击