一、哈希算法
(1)概念
哈希算法又称为哈希函数、散列算法、散列函数,它能从任何数据长度生成一个固定长度的消息摘要(如下图)。对于某个特定的消息而言,这个消息摘要(或哈希值)可以看做是这个消息的指纹,且该消息是唯一表示。哈希函数是数字签名和验证的核心部分。
(2)哈希算法的特性
- 单向性
哈希函数必须具有单向性,也就是说给定一个输入,通过哈希函数可以得到一个散列值,但是反过来,给定一个散列值,是无法获得输入的。换句话说,就是给定一个散列值(指纹),我们不可能找到对应的消息。 - 冲突避免
很难找到两个不同的消息,使得产生的哈希值一致(发生冲突)。 - 输入敏感
原始数据任何微小的变动都会导致哈希值完全不一样 - 正向快速
给定消息和哈希算法,在有限时间和有效资源内计算出哈希值
(3)哈希碰撞
哈希碰撞也就是说存在不同的消息(输入),使得哈希函数的输出,也就是散列值一样,这种概率非常非常低。以下面的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算法才比较安全。
(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编程实现
生成密钥对
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)
|
三、数字签名
(1)概念
数字签名,就是只有信息的发送者才能产生的别人无法伪造的一段数字串,这段数字串同时也是对信息的发送者发送信息真实性的一个有效证明。它是进行身份鉴别和网上安全交易的通用技术。
数字签名应用了前2节所说到的非对称加密技术(公钥加密算法)和哈希算法。
(2)功能
- 数字签名主要有三个作用:
- 保证信息传输的完整性(完整性)
- 发送者身份认证(鉴权)
- 防止交易中发生抵赖(不可抵赖性)
数字签名是加密过程,数字签名验证是解密过程。
(3)签名和验证
- 发送者签名过程
数字签名是发送方首先通过一个哈希算法将获取信息的一个摘要
然后通过秘钥对这个摘要进行签名
最后把签名和原文一起发送给接收者 - 接收者验证过程
数字签名验证,接收者收到发送者发送的签名和原文后,首先进行分离
采用跟发送者一样的哈希算法提取原文的摘要
然后用发送者的公钥对签名进行解密获得解密后的摘要
两者对比,如果一致,则说明收到的信息是完整的,在传输过程中没有被修改过。
这里,读者细心想会发现,如果一个黑客,将发送者的私钥和接收者手上拥有的发送者的公钥都替换成黑客自己的私钥和公钥。那这个时候接收者,在验证的时候是无法发现问题的,因为签名用的私钥是黑客的私钥,验证用的公钥也是黑客的公钥,两者是成对的。这就变成了对公钥是否合法的验证,那么要解决这个问题就涉及到数字证书的概念(如下图所示)。这个读者可以看我另外写的一篇文章《数字证书是什么》,这里就不展开讲。
(4)应用
数字签名技术的应用很广泛,例如个人安全邮件证书、访问安全https站点、网上签约、电子交易等。
(5)python编程实现
首先生成一对秘钥(公钥和私钥)
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/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