常看见的加密算法

一、HASH系列

特征:数字字母组成,全部大写/小写

md5

  • 不可逆,32位
Python 实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import hashlib


def md5_test1():
md5 = hashlib.new('md5', 'I love python!'.encode('utf-8'))
print(md5.hexdigest())


def md5_test2():
md5 = hashlib.md5()
md5.update('I love '.encode('utf-8'))
md5.update('python!'.encode('utf-8'))
print(md5.hexdigest())


if __name__ == '__main__':
md5_test1() # 21169ee3acd4a24e1fcb4322cfd9a2b8
md5_test2() # 21169ee3acd4a24e1fcb4322cfd9a2b8

sha1/256

  • 不可逆,40位
Python 实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import hashlib


def sha1_test1():
sha1 = hashlib.new('sha1', 'I love python!'.encode('utf-8'))
print(sha1.hexdigest())


def sha1_test2():
sha1 = hashlib.sha1()
sha1.update('I love python!'.encode('utf-8'))
print(sha1.hexdigest())


if __name__ == '__main__':
sha1_test1() # 23c02b203bd2e2ca19da911f1d270a06d86719fb
sha1_test2() # 23c02b203bd2e2ca19da911f1d270a06d86719fb

hmac

  • 给定一个密钥,对明文加密,做两次“散列”,得到的结果还是32为字符串
python 实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import hmac

def hmac_test1():
message = b'I love python!'
key = b'secret'
md5 = hmac.new(key, message, digestmod='MD5')
print(md5.hexdigest())


def hmac_test2():
key = 'secret'.encode('utf8')
sha1 = hmac.new(key, digestmod='sha1')
sha1.update('I love '.encode('utf8'))
sha1.update('Python!'.encode('utf8'))
print(sha1.hexdigest())


if __name__ == '__main__':
hmac_test1() # 9c503a1f852edcc3526ea56976c38edf
hmac_test2() # 2d8449a4292d4bbeed99ce9ea570880d6e19b61a

二、加密基本参数

  • 在一些对称和非对称加密算法中,经常会用到以下三个参数:初始向量 iv、加密模式 mode、填充方式 padding

iv

在密码学中,初始向量,与密钥结合使用,作为加密数据的手段,

mode

目前流行的加密和数字认证算法,都是采用块加密方式,就是将需要加密的明文分成固定大小的数据块,然后对其执行密码算法,得到密文。

  • ECB:电子码本模式,是一种基础的加密方式,密文被分割成分组长度相等的块(不足补齐),然后单独一个个加密,一个个输出组成密文。
  • CBC:密码块链接模式,是一种循环模式,前一个分组的密文和当前分组的明文异或操作后再加密,这样做的目的是增强破解难度。
  • PCBC:填充密码块链接模式,也称为明文密码块链接模式(Plaintext Cipher Block Chaining),是一种可以使密文中的微小更改在解密时导致明文大部分错误的模式,并在加密的时候也具有同样的特性。
  • CFB:密码反馈模式,可以将块密码变为自同步的流密码,类似于 CBC,CFB 的解密过程几乎就是颠倒的 CBC 的加密过程。
  • OFB:输出反馈模式,可以将块密码变成同步的流密码,它产生密钥流的块,然后将其与明文块进行异或,得到密文。与其它流密码一样,密文中一个位的翻转会使明文中同样位置的位也产生翻转。
  • CTR:计数器模式,也被称为 ICM 模式(Integer Counter Mode,整数计数模式)和 SIC 模式(Segmented Integer Counter),在 CTR 模式中,有一个自增的算子,这个算子用密钥加密之后的输出和明文异或的结果得到密文,相当于一次一密。这种加密方式简单快速,安全可靠,而且可以并行加密,但是在计算器不能维持很长的情况下,密钥只能使用一次。

padding

块密码只能对确定长度的数据块进行处理,而消息的长度通常是可变的。因此部分模式最后一块数据在加密前需要进行填充。

  • PKCS7:在填充时首先获取需要填充的字节长度 = 块长度 - (数据长度 % 块长度), 在填充字节序列中所有字节填充为需要填充的字节长度值。
  • PKCS5:PKCS5 作为 PKCS7 的子集算法,概念上没有什么区别,只是在 blockSize 上固定为 8 bytes,即块大小固定为 8 字节。
  • ZeroPadding:在填充时首先获取需要填充的字节长度 = 块长度 - (数据长度 % 块长度), 在填充字节序列中所有字节填充为 0 。
  • ISO10126:在填充时首先获取需要填充的字节长度 = 块长度 - (数据长度 % 块长度),在填充字节序列中最后一个字节填充为需要填充的字节长度值,填充字节中其余字节均填充随机数值。
  • ANSIX923:在填充时首先获取需要填充的字节长度 = 块长度 - (数据长度 % 块长度),在填充字节序列中最后一个字节填充为需要填充的字节长度值,填充字节中其余字节均填充数字零。

三、对称加密(传统加密)

  • 特征:加密和解密使用同一个密钥。

  • 加密解密过程:明文->密钥加密->密文,密文->密钥解密->明文。

  • 解密条件:key,iv,mode,padding

DES

  • 8位密钥
  • mode 支持:CBC,CFB,CTR,CTRGladman,ECB,OFB 等。
  • padding 支持:ZeroPadding,NoPadding,AnsiX923,Iso10126,Iso97971,Pkcs7 等。
JavaScript 实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 引用 crypto-js 加密模块
var CryptoJS = require('crypto-js')

function desEncrypt() {
var key = CryptoJS.enc.Utf8.parse(desKey),
iv = CryptoJS.enc.Utf8.parse(desIv),
srcs = CryptoJS.enc.Utf8.parse(text),
// CBC 加密模式,Pkcs7 填充方式
encrypted = CryptoJS.DES.encrypt(srcs, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return encrypted.toString();
}

function desDecrypt() {
var key = CryptoJS.enc.Utf8.parse(desKey),
iv = CryptoJS.enc.Utf8.parse(desIv),
srcs = encryptedData,
// CBC 加密模式,Pkcs7 填充方式
decrypted = CryptoJS.DES.decrypt(srcs, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return decrypted.toString(CryptoJS.enc.Utf8);
}

var text = "I love Python!" // 待加密对象
var desKey = "6f726c64f2c2057" // 密钥
var desIv = "0123456789ABCDEF" // 初始向量

var encryptedData = desEncrypt()
var decryptedData = desDecrypt()

console.log("加密字符串: ", encryptedData)
console.log("解密字符串: ", decryptedData)

// 加密字符串: +ndbEkWNw2QAfIYQtwC14w==
// 解密字符串: I love Python!

3DES

  • 特征:原理和DES几乎是一样的,只是使用3个密钥,对相同的数据执行三次加密,增强加密强度。

  • mode 支持:CBC,CFB,CTR,CTRGladman,ECB,OFB 等。

  • padding 支持:ZeroPadding,NoPadding,AnsiX923,Iso10126,Iso97971,Pkcs7 等。

JavaScript 实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 引用 crypto-js 加密模块
var CryptoJS = require('crypto-js')

function tripleDesEncrypt() {
var key = CryptoJS.enc.Utf8.parse(desKey),
iv = CryptoJS.enc.Utf8.parse(desIv),
srcs = CryptoJS.enc.Utf8.parse(text),
// ECB 加密方式,Iso10126 填充方式
encrypted = CryptoJS.TripleDES.encrypt(srcs, key, {
iv: iv,
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Iso10126
});
return encrypted.toString();
}

function tripleDesDecrypt() {
var key = CryptoJS.enc.Utf8.parse(desKey),
iv = CryptoJS.enc.Utf8.parse(desIv),
srcs = encryptedData,
// ECB 加密方式,Iso10126 填充方式
decrypted = CryptoJS.TripleDES.decrypt(srcs, key, {
iv: iv,
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Iso10126
});
return decrypted.toString(CryptoJS.enc.Utf8);
}

var text = "I love Python!" // 待加密对象
var desKey = "6f726c64f2c2057c" // 密钥
var desIv = "0123456789ABCDEF" // 偏移量

var encryptedData = tripleDesEncrypt()
var decryptedData = tripleDesDecrypt()

console.log("加密字符串: ", encryptedData)
console.log("解密字符串: ", decryptedData)

// 加密字符串: 3J0NX7x6GbewjjhoW2HKqg==
// 解密字符串: I love Python!

AES

  • mode 支持:CBC,CFB,CTR,CTRGladman,ECB,OFB 等。
  • padding 支持:ZeroPadding,NoPadding,AnsiX923,Iso10126,Iso97971,Pkcs7 等。
JavaScript 实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 引用 crypto-js 加密模块
var CryptoJS = require('crypto-js')

function tripleAesEncrypt() {
var key = CryptoJS.enc.Utf8.parse(aesKey),
iv = CryptoJS.enc.Utf8.parse(aesIv),
srcs = CryptoJS.enc.Utf8.parse(text),
// CBC 加密方式,Pkcs7 填充方式
encrypted = CryptoJS.AES.encrypt(srcs, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return encrypted.toString();
}

function tripleAesDecrypt() {
var key = CryptoJS.enc.Utf8.parse(aesKey),
iv = CryptoJS.enc.Utf8.parse(aesIv),
srcs = encryptedData,
// CBC 加密方式,Pkcs7 填充方式
decrypted = CryptoJS.AES.decrypt(srcs, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return decrypted.toString(CryptoJS.enc.Utf8);
}

var text = "I love Python!" // 待加密对象
var aesKey = "6f726c64f2c2057c" // 密钥,16 倍数
var aesIv = "0123456789ABCDEF" // 偏移量,16 倍数

var encryptedData = tripleAesEncrypt()
var decryptedData = tripleAesDecrypt()

console.log("加密字符串: ", encryptedData)
console.log("解密字符串: ", decryptedData)

// 加密字符串: dZL7TLJR786VGvuUvqYGoQ==
// 解密字符串: I love Python!

四、非对称加密RSA

特征:

  • 非对称加密算法需要两个密钥:公开密钥(publickey) 和私有密(privatekey)
  • 有字符 + / =、而且比较长
  • 如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密。
  • 如果用私有密钥对数据进行加密,只有用对应的公开密钥才能解密。

解密条件:

  • 公钥 publickey
  • 存在位置: 后端api,js里、网页源码里

JavaScript 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// 引用 node-rsa 加密模块
var NodeRSA = require('node-rsa');

function rsaEncrypt() {
pubKey = new NodeRSA(publicKey,'pkcs8-public');
var encryptedData = pubKey.encrypt(text, 'base64');
return encryptedData
}

function rsaDecrypt() {
priKey = new NodeRSA(privatekey,'pkcs8-private');
var decryptedData = priKey.decrypt(encryptedData, 'utf8');
return decryptedData
}

var key = new NodeRSA({b: 512}); //生成512位秘钥
var publicKey = key.exportKey('pkcs8-public'); //导出公钥
var privatekey = key.exportKey('pkcs8-private'); //导出私钥
var text = "I love Python!"

var encryptedData = rsaEncrypt()
var decryptedData = rsaDecrypt()

console.log("公钥:\n", publicKey)
console.log("私钥:\n", privatekey)
console.log("加密字符串: ", encryptedData)
console.log("解密字符串: ", decryptedData)

/*
公钥:
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAOV1BwTJSVce/QjJAro5fXG9WzOpal09
Qtv1yuXKE81vZSNTHxW6dICwPT/kjCfC3bA5Qs6wnYBANuwD6wlAS0UCAwEAAQ==
-----END PUBLIC KEY-----
私钥:
-----BEGIN PRIVATE KEY-----
MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEA5XUHBMlJVx79CMkC
ujl9cb1bM6lqXT1C2/XK5coTzW9lI1MfFbp0gLA9P+SMJ8LdsDlCzrCdgEA27APr
CUBLRQIDAQABAkAiXwJbJC+5PioXG80tyhjRZdT4iyMkrl2Kh2oKO9f1iLaBXLya
D0HW82wFh+cUy8GcMl9jse8DE8wd1TdORmHhAiEA/rwmWjXHVgDqcH/fqk8Ufku0
fXvs56h5QDoh1so5vokCIQDmmL3JDW6Y7RuK2qwFbHBZtYPRFRVdn5X1oqU2FOSX
3QIhAOVTjVN5RtNuT6Cn/jvcpZ5tmTe+8TA8w6vGqeAsfn/BAiBvKKIUEQ2HWoU0
YkUaODPQiteIKomqIAvB5S2O7HNlYQIgWMuLUxGZbbcAmIX+YmRXuET97S7OWv+z
WHVfb/rbXtI=
-----END PRIVATE KEY-----
加密字符串: hHXTF1K3w55Wd6OSjVYtqxceJ5VhlySNUahel9pwKD92Ef7wIT7DYPuJRKiqz5tuHtUqujbmbZBSL0qDE/EA+A==
解密字符串: I love Python!
*/

常用的浏览器解密模式

找到rsa文件,去创建同样的rsa对象。

找到加密的参数modulus,exponent直接构建