原文:shuwoom.com/?p=643python
哈希算法又稱爲哈希函數、散列算法、散列函數,它能從任何數據長度生成一個固定長度的消息摘要(以下圖)。對於某個特定的消息而言,這個消息摘要(或哈希值)能夠看作是這個消息的指紋,且該消息是惟一表示。哈希函數是數字簽名和驗證的核心部分。算法
哈希碰撞也就是說存在不一樣的消息(輸入),使得哈希函數的輸出,也就是散列值同樣,這種機率很是很是低。如下面的md5爲例,兩個輸入有細微差異,可是哈希值是同樣的:編程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
# coding: utf-8
import
hashlib
# 兩段HEX字節串,注意它們有細微差異
a
=
bytearray.fromhex(
"0e306561559aa787d00bc6f70bbdfe3404cf03659e704f8534c00ffb659c4c8740cc942feb2da115a3f4155cbb8607497386656d7d1f34a42059d78f5a8dd1ef"
)
b
=
bytearray.fromhex(
"0e306561559aa787d00bc6f70bbdfe3404cf03659e744f8534c00ffb659c4c8740cc942feb2da115a3f415dcbb8607497386656d7d1f34a42059d78f5a8dd1ef"
)
# 輸出MD5,它們的結果一致
print
(hashlib.md5(a).hexdigest())
print
(hashlib.md5(b).hexdigest())
### a和b輸出結果都爲:
cee9a457e790cf20d4bdaa6d69f01e41
cee9a457e790cf20d4bdaa6d69f01e41
|
以CRC32爲例,它的摘要長度爲32bit,也就是說存在2^32種可能。現在互聯網頁面總數在2008年的時候就已經超過1萬億,若是採用CRC32的摘要,那麼發生哈希碰撞的就不少。而MD5的摘要長度爲128bit,也就是有2^128種可能,可是目前已經證實MD5算法是不安全的。一樣的SHA1算法(160bit)也被證實是不安全的,推薦使用SHA256算法才比較安全。安全
目前比較流行的哈希算法有MD五、SHA-1和SHA-2微信
MD4已經被證實時不夠安全的,不推薦使用網絡
MD5是MD4的改進版本,輸出是128bit。一樣,MD5也被證實了不具有強抗碰撞性,也是不夠安全的函數
SHA是一個哈希函數族,SHA-1算法的哈希值長度爲160bit,抗窮舉性比MD5和MD4更好。可是SHA-1已經被證實不具有「強抗碰撞性」(谷歌已經攻破SHA-1),ui
SHA-2google
SHA-22四、SHA-25六、SHA-384,和 SHA-512 算法統稱爲SHA-2,算法原理跟SHA-1相似。加密
總結來講,MD5和SHA-1已經不夠安全,推薦至少使用SHA-256算法。
哈希算法的應用主要體如今如下3個方面:
非對稱加密算法也稱爲公鑰加密算法,其分爲3個部分,分別是:公鑰、私鑰和加密解密算法。
非對稱加密每每須要密碼學安全僞隨機數生成器來產生一對祕鑰(公鑰和私鑰),這二者是成對的,公鑰是能夠公開的,而私鑰則是用戶本身保留。用私鑰加密的數據只有公鑰才能夠解密(反過來,用公鑰加密的數據,只有私鑰能夠解密)。公鑰和私鑰之間的這種數學關係,使得私鑰能夠用於生成特定消息的簽名。而這個簽名能夠在不暴露私鑰的前提下經過公鑰進行驗證。
也就是說我對一段消息用私鑰進行簽名(也就是加密),而後把這個數據連同簽名和個人公鑰發送給對方,對方就能夠經過公鑰對簽名進行驗證(解密)對比數據從而驗證數據的有效性。
在比特幣系統中,公鑰生成的錢包地址用於接收比特幣,而私鑰則用於比特幣支付時的交易簽名。
在支付比特幣時,比特幣的全部者須要在交易中提交本身的公鑰和該交易的簽名。而比特幣網絡中全部節點能夠經過所提交的公鑰和簽名進行驗證,從而確認支付者對交易的比特幣的全部權。
以下圖所示,加密過程是單向的,公鑰加密後的密文只能用對應的私鑰解密。
其中使用最普遍的是RSA算法(由發明者Rivest、Shmir和Adleman姓氏首字母縮寫而來)是著名的公開祕鑰加密算法,ElGamal是另外一種經常使用的非對稱加密算法。
非對稱加密算法的應用很是普遍,下面列舉常見的幾種
生成密鑰對
1
2
3
4
5
6
7
8
|
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,咱們能夠看到一長串的字符串。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
genisus_public.pem:
-
-
-
-
-
BEGIN RSA PUBLIC KEY
-
-
-
-
-
MIGJAoGBAJIiGuUOlhKFQEHIr5YXa9uajM
+
sI5FEZ
/
8RJdR5EOC4Wo
+
9bZfyrvnu
PRBtK7PJzUXHdXCaNohPzA5IuiEpkoELPyWfCozQF9FAgK2Gyf1rBeC7e2lUvuwI
h5IXhRjC2Rom6wiJRWXn
/
W0
/
EezrXl8YlYmrRR1Boa9OB1RFJvJXAgMBAAE
=
-
-
-
-
-
END RSA PUBLIC KEY
-
-
-
-
-
genisus_private.pem:
-
-
-
-
-
BEGIN RSA PRIVATE KEY
-
-
-
-
-
MIICYAIBAAKBgQCSIhrlDpYShUBByK
+
WF2vbmozPrCORRGf
/
ESXUeRDguFqPvW2X
8q757j0QbSuzyc1Fx3VwmjaIT8wOSLohKZKBCz8lnwqM0BfRQICthsn9awXgu3tp
VL7sCIeSF4UYwtkaJusIiUVl5
/
1tPxHs615fGJWJq0UdQaGvTgdURSbyVwIDAQAB
AoGAOiw7ep3A3iSPfOCQDXbLaANxNKa5DfYmVCKWZavALUUWQAxPmWJxh2rwgh6D
fDHEdpe9R5MMTF0
/
xRvsQGQvZU2sNNhA2ebVOB4mMCPcURYWCbJXjT14IC7rfwPp
YnkpiCHxP
+
HBS2xjMyf63vk7tKR
/
zCfzm9tsDAKqKuFUYPECRQCrQpiuYxp2Znch
szwR15q0HUpU8
/
HdCQlKdBK2fa4M2Y1xPqNjpOlQ2B8zCS3aOQ
/
9nhbVaRy0LqFD
sUjPPJsTqbaSyQI9ANpwsv1MHkpYGlYSrCItFS1oRoD
/
foxByVdVORCtarA0z9xe
Am8kEi9HcnZf2jsYvqHAeQsTtuPw0PvMHwJEXL0
+
csilztHj1zL452yKkNh
/
pQtI
wPogttmuPHZIZxrz9gwGbHIkCixOkNN6qf5Wg281TDGUYpoRp9d75wUZsQcpH8kC
PE0rvYBREO5w27UG2bslNDMbgLT4DkwcvbXVzNhAe82OitSufauoEaiUVDLPwDha
kJZyehDYwSccH6ilPwJFAIhBzCQ61A2zfEJlgKeuX3OJGq1pywpnv
+
vFyqnDc4T6
oEW9kfnrAI
+
6x4L4jyyHOWMNfkAPajtkQ
+
YwxZqUmKL8ixr0
-
-
-
-
-
END RSA PRIVATE KEY
-
-
-
-
-
|
加密、解密
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# 導入密鑰
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)
|
數字簽名,就是隻有信息的發送者才能產生的別人沒法僞造的一段數字串,這段數字串同時也是對信息的發送者發送信息真實性的一個有效證實。它是進行身份鑑別和網上安全交易的通用技術。
數字簽名應用了前2節所說到的非對稱加密技術(公鑰加密算法)和哈希算法。
數字簽名技術的應用很普遍,例如我的安全郵件證書、訪問安全https站點、網上籤約、電子交易等。
首先生成一對祕鑰(公鑰和私鑰)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
# 明文
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/bf1d7eee28d0https://zh.wikipedia.org/wiki/%E6%95%A3%E5%88%97%E5%87%BD%E6%95%B8http://www.infoq.com/cn/news/2017/02/google-first-sha1-collisionhttp://blog.jobbole.com/106733/https://baike.baidu.com/item/%E6%95%B0%E5%AD%97%E7%AD%BE%E5%90%8Dhttps://blog.csdn.net/u011630575/article/details/53241027