编码算法
ASCII
字母
A
的编码是十六进制的0x41
,字母B
是0x42
ASCII编码最多只能有128个字符,要想对更多的文字进行编码,就需要用Unicode。而中文的中使用Unicode编码就是
0x4e2d
,使用UTF-8则需要3个字节编码x
UTF-8
# Unicode,以&#(&#X为Unicode 16进制) # 今偷 # UTF-8,以\u开头 e = '\u89e3\u6790\u5305\u5f02\u5e38' # 显示为中文 print("\u89e3\u6790\u5305\u5f02\u5e38") # 解析包异常 # 显示为中文 result = e.encode("utf-8").decode()
URL编码
URL编码是浏览器发送数据给服务器时使用的编码,它通常附加在URL的参数部分,
例如:https://www.baidu.com/s?wd=%E4%B8%AD%E6%96%87
之所以需要URL编码,是因为出于兼容性考虑,很多服务器只识别ASCII字符。但如果URL中包含中文、日文这些非ASCII字符怎么办?不要紧,URL编码有一套规则:
如果字符是
A
`Z`,`a`z
,0
~9
以及-
、_
、.
、*
,则保持不变;如果是其他字符,先转换为UTF-8编码,然后对每个字节以
%XX
表示。
# URL编码,以%开头 import json from urllib import parse ss = "http://www.baidu.com" print(parse.quote(ss)) # 编码:http%3A//www.baidu.com # print(parse.unquote()) 解码
Base64编码
base64 编码,以=结尾
URL编码是对字符进行编码,表示成
%xx
的形式,而Base64编码是对二进制数据进行编码,表示成文本格式
哈希算法
哈希算法(Hash)又称摘要算法(Digest),它的作用是:对任意一组输入数据进行计算,得到一个固定长度的输出摘要
哈希算法最重要的特点就是:
相同的输入一定得到相同的输出;
不同的输入大概率得到不同的输出。
常用的哈希算法有:
算法 | 输出长度(位) | 输出长度(字节) |
---|---|---|
MD5 | 128 bits | 16 bytes |
SHA-1 | 160 bits | 20 bytes |
RipeMD-160 | 160 bits | 20 bytes |
SHA-256 | 256 bits | 32 bytes |
SHA-512 | 512 bits | 64 bytes |
根据碰撞概率,哈希算法的输出长度越长,就越难产生碰撞,也就越安全。
使用哈希口令时,还要注意防止彩虹表攻击
什么是彩虹表呢?上面讲到了,如果只拿到MD5,从MD5反推明文口令,只能使用暴力穷举的方法
可以采取措施来抵御彩虹表攻击,方法是对每个口令额外添加随机数,这个方法称之为加盐(salt)
HAMC算法
Hmac算法就是一种基于密钥的消息认证码算法,它的全称是Hash-based Message Authentication Code,是一种更安全的消息摘要算法。
我们回顾一下哈希算法:
digest = hash(input)
正是因为相同的输入会产生相同的输出,我们加盐的目的就在于,使得输入有所变化:
digest = hash(salt + input)
这个salt可以看作是一个额外的“认证码”,同样的输入,不同的认证码,会产生不同的输出。因此,要验证输出的哈希,必须同时提供“认证码”
Hmac算法总是和某种哈希算法配合起来用的。例如,我们使用MD5算法,对应的就是HmacMD5算法,它相当于“加盐”的MD5:
HmacMD5 ≈ md5(secure_random_key, input)
因此,HmacMD5可以看作带有一个安全的key的MD5。使用HmacMD5而不是用MD5加salt,有如下好处:
-
HmacMD5使用的key长度是64字节,更安全;
-
Hmac是标准算法,同样适用于SHA-1等其他哈希算法;
-
Hmac输出和原有的哈希算法长度一致。
总结:Hmac算法是一种标准的基于密钥的哈希算法,可以配合MD5、SHA-1等哈希算法,计算的摘要长度和原摘要算法长度相同,Hmac本质上就是把key混入摘要的算法。验证此哈希时,除了原始的输入数据,还要提供key
对称加密
对称加密算法就是传统的用一个密码进行加密和解密
常用的对称加密算法有:
算法 | 密钥长度 | 工作模式 | 填充模式 |
---|---|---|---|
DES | 56/64 | ECB/CBC/PCBC/CTR/… | NoPadding/PKCS5Padding/… |
AES | 128/192/256 | ECB/CBC/PCBC/CTR/… | NoPadding/PKCS5Padding/PKCS7Padding/… |
IDEA | 128 | ECB | PKCS5Padding/PKCS7Padding/… |
密钥长度直接决定加密强度,而工作模式和填充模式可以看成是对称加密算法的参数和格式选择
AES:
ECB模式是最简单的AES加密模式,它只需要一个固定长度的密钥,固定的明文会生成固定的密文,这种一对一的加密方式会导致安全性降低,更好的方式是通过CBC模式,它需要一个随机数作为IV参数,这样对于同一份明文,每次生成的密文都不同
非对称加密算法
非对称加密就是加密和解密使用的不是相同的密钥:只有同一个公钥-私钥对才能正常加解密
非对称加密的典型算法就是RSA算法,它是由Ron Rivest,Adi Shamir,Leonard Adleman这三个哥们一起发明的,所以用他们仨的姓的首字母缩写表示。
因为非对称加密的缺点就是运算速度非常慢,比对称加密要慢很多
非对称加密实际上应用在第一步,即加密“AES口令”。这也是我们在浏览器中常用的HTTPS协议的做法,即浏览器和服务器先通过RSA交换AES口令,接下来双方通信实际上采用的是速度较快的AES对称加密,而不是缓慢的RSA非对称加密
签名算法
如果使用私钥加密,公钥解密是否可行呢?实际上是完全可行的。
不过我们再仔细想一想,私钥是保密的,而公钥是公开的,用私钥加密,那相当于所有人都可以用公钥解密。这个加密有什么意义?
数字签名: 私钥加密得到的密文实际上就是数字签名,要验证这个签名是否正确,只能用私钥持有者的公钥进行解密验证。使用数字签名的目的是为了确认某个信息确实是由某个发送方发送的,任何人都不可能伪造消息,并且,发送方也不能抵赖。
在实际应用的时候,签名实际上并不是针对原始消息,而是针对原始消息的哈希进行签名
常用数字签名算法有
-
MD5withRSA
-
SHA1withRSA
-
SHA256withRSA
它们实际上就是指定某种哈希算法进行RSA签名的方式。
DSA签名
除了RSA可以签名外,还可以使用DSA算法进行签名。DSA是Digital Signature Algorithm的缩写,它使用ElGamal数字签名算法。
DSA只能配合SHA使用,常用的算法有:
-
SHA1withDSA
-
SHA256withDSA
-
SHA512withDSA
和RSA数字签名相比,DSA的优点是更快。
ECDSA签名
椭圆曲线签名算法ECDSA:Elliptic Curve Digital Signature Algorithm也是一种常用的签名算法,它的特点是可以从私钥推出公钥。比特币的签名算法就采用了ECDSA算法,使用标准椭圆曲线secp256k1。BouncyCastle提供了ECDSA的完整实现
数字证书
我们知道,摘要算法用来确保数据没有被篡改,非对称加密算法可以对数据进行加解密,签名算法可以确保数据完整性和抗否认性,把这些算法集合到一起,并搞一套完善的标准,这就是数字证书。
因此,数字证书就是集合了多种密码学算法,用于实现数据加解密、身份认证、签名等多种功能的一种安全标准。
数字证书可以防止中间人攻击,因为它采用链式签名认证,即通过根证书(Root CA)去签名下一级证书,这样层层签名,直到最终的用户证书。而Root CA证书内置于操作系统中,所以,任何经过CA认证的数字证书都可以对其本身进行校验,确保证书本身不是伪造的
我们在上网时常用的HTTPS协议就是数字证书的应用。浏览器会自动验证证书的有效性
参考:加密与安全