简介 收集了常见的各种加密算法,编码算法的原理, 再js中和py中的基本实现方法,遇到js 加密的时候可以快速还原加密过程,有的网站在加密的过程中可能还经过了其他处理,但是大致的方法是一样的:
常见的加密算法:
对称加密 (加密解密密钥相同): DES,3DES,AES,RC4,RABBIT
非对称加密 (区分公钥和私钥): RSA,DSA,ECC
消息摘要算法/签名算法: MD5,SHA,HMAC,PBKDF2
常见编码算法: Base64
JS 加密解密模块 Crypto-JS
crypto-js 支持 MD5 SHA RIPEMD-160 HMAC PBKDF2 AES DESC 3DES Rabbit RC4等 不支持SA ECC 是应用比较广的加密模块 使用 npm install crypto-js 安装
参考资料:
Node-RSA
Node-RSA 对 RSA 算法提供了支持, 使用命令 npm install node-rsa 安装。
参考资料:
JSEncryot
JSEncrypt 对 RSA 算法提供了更加全面的支持,使用命令 npm install jsencrypt 安装。
参考资料:
Python 加密解密库 Cryptodome & Crypto
在 Python 中有很多算法是通过第三方库 Cryptodome 或者 Crypto来实现的, Cryptodome 几乎是 Cryto的替代品
Cryptodome 支持几乎所有主流加密算法,包括 MD5、SHA、BLAKE2b、BLAKE2s、HMAC、PBKDF2、AES、DES、3DES(Triple DES)、ECC、RSA、RC4 等。
Cryptodome 使用命令 pip install pycryptodome 进行安装,Crypto 使用命令 pip install pycrypto 进行安装。
参考资料:
Hashlib
Python 的标准库 hashlib 提供了常见的摘要算法,如 MD5,SHA、BLAKE2b、BLAKE2s 等。
参考资料:
HMAC
Python 的标准库 hmac 对 HMAC 算法提供了支持。
参考资料:
pyDes
Python 的第三方库 pyDes 对 DES 算法提供了支持, 使用命令 pip install pydes 进行安装
参考资料:
ESA
Python 的第三方库 rsa 对 RSA 算法提供了支持。使用命令 pip install rsa 进行安装。
参考资料:
加密解密基本参数 在一些对称和非对称加密算法中,经常会用到以下三个参数: 初始向量iv,加密模式mode,填充方式 padding
初始向量iv
在密码学中, 初始向量又称初始变数 与 密钥结合使用,作为加密数据的手段, 它是一个 固定长度的值, iv的长度取决于加密方法,通常与使用的加密密钥或密码块的长度相当, 一般在使用过程中会要求它是 随机数 或拟随机数, 使用随机数产生的初始向量才能达到语义安全,让攻击者难以对原文一致且使用同一把密钥生成的密文进行破解。
加密模式 mode
目前流行的加密和数字认证算法,都是采用块加密方式,就是将需要加密的明文分成固定大小的数据块,然后对其执行密码算法,得到密文。数据块的大小通常采用跟密钥一样的长度。加密模式在加密算法的基础上发展出来,同时也可以独立于加密算法而存在,加密模式定义了怎样通过重复利用加密算法将大于一个数据块大小的明文转化为密文,描述了加密每一数据块的过程。目前利用较多的加密模式有以下几种:
ECB: Electronic Code Book(电子码本模式),是一种基础的加密方式,密文被分割成分组长度相等的块(不足补齐),然后单独一个个加密,一个个输出组成密文。
CBC:Cipher Block Chaining(密码块链接模式),是一种循环模式,前一个分组的密文和当前分组的明文异或操作后再加密,这样做的目的是增强破解难度。
CFB:Cipher Feedback(密码反馈模式),可以将块密码变为自同步的流密码,类似于 CBC,CFB 的解密过程几乎就是颠倒的 CBC 的加密过程
OFB:Output Feedback(输出反馈模式),可以将块密码变成同步的流密码,它产生密钥流的块,然后将其与明文块进行异或,得到密文。与其它流密码一样,密文中一个位的翻转会使明文中同样位置的位也产生翻转。
CTR:Counter mode(计数器模式),也被称为 ICM 模式(Integer Counter Mode,整数计数模式)和 SIC 模式(Segmented Integer Counter),在 CTR 模式中,有一个自增的算子,这个算子用密钥加密之后的输出和明文异或的结果得到密文,相当于一次一密。这种加密方式简单快速,安全可靠,而且可以并行加密,但是在计算器不能维持很长的情况下,密钥只能使用一次。
填充方式 padding
块密码只能对确定长度的数据块进行处理, 而消息 的长度通常是可变的,因此部分模式最后一块数据在加密前需要进行填充,有数种填充方法,其中最简单的一种是在明文的最后填充空字符以使其长度为块长度的整数倍。常见填充 方式有以下几种:
PKCS7: 在填充时首先获取填充的字节长度 = 块长度- (数据长度 % 块长度) ,在填充字节序列中所有字节填充为 需要填充的字节长度值
PKCS5:PKCS5 作为 PKCS7 的子集算法,概念上没有什么区别,只是在 blockSize 上固定为 8 bytes,即块大小固定为 8 字节。
ZeroPadding:在填充时首先获取需要填充的字节长度 = 块长度 - (数据长度 % 块长度), 在填充字节序列中所有字节填充为 0 。
ISO10126:在填充时首先获取需要填充的字节长度 = 块长度 - (数据长度 % 块长度),在填充字节序列中最后一个字节填充为需要填充的字节长度值,填充字节中其余字节均填充随机数值。
ANSIX923:在填充时首先获取需要填充的字节长度 = 块长度 - (数据长度 % 块长度),在填充字节序列中最后一个字节填充为需要填充的字节长度值,填充字节中其余字节均填充数字零。
Base64 Base64 是一种用 64 个字符来表示任意二进制数据的方法。
JS实现:
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 var CryptoJS = require ('crypto-js' )function base64Encode ( ) { var srcs = CryptoJS .enc .Utf8 .parse (text); var encodeData = CryptoJS .enc .Base64 .stringify (srcs); return encodeData } function base64Decode ( ) { var srcs = CryptoJS .enc .Base64 .parse (encodeData); var decodeData = srcs.toString (CryptoJS .enc .Utf8 ); return decodeData } var text = "I love Python!" var encodeData = base64Encode ()var decodeData = base64Decode ()console .log ("Base64 编码: " , encodeData)console .log ("Base64 解码: " , decodeData)
Python 实现
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 import base64def base64_encode (text ): """base64 encode text """ encode_data = base64.b64encode(text.encode('utf-8' )) return encode_data def base64_decode (text ): """"base64 decode text """ decode_data = base64.b64decode(text) return decode_data if __name__ == '__main__' : text = 'I love Python' encode_data = base64_encode(text) decode_data = base64_decode(encode_data) print ('Base64 编码:' , encode_data) print ('Base64 解码:' , decode_data)
MD5 全称 MD5 消息摘要算法(英文名称:MD5 Message-Digest Algorithm),又称哈希算法、散列算法
JS 实现:
1 2 3 4 5 6 7 8 9 let CryptoJS = require ('crypto-js' )function MD5Test ( ) { let text = 'hello world' return new CryptoJS .MD5 (text).toString () } console .log (MD5Test ())
Python 实现:
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 import hashlibdef md5_test1 (): """md5 test""" md5 = hashlib.new('md5' , 'I love python!' .encode('utf-8' )) print (md5.hexdigest()) def md5_test2 (): """md5 test""" md5 = hashlib.md5() md5.update('I love ' .encode('utf-8' )) md5.update('python!' .encode('utf-8' )) print (md5.hexdigest()) if __name__ == '__main__' : md5_test1() md5_test2()
PBKDF2 PBKDF2是 RSA 实验室的公钥加密标准,PBKDF2 将伪随机函数(例如 HMAC),把明文和一个盐值(salt)作为输入参数,然后进行重复运算,并最终产生密钥,如果重复的次数足够大,破解的成本就会变得很高。
JS实现:
1 2 3 4 5 6 7 8 9 10 11 12 let CryptoJS = require ('crypto-js' )function pbkdf2Encrypt ( ) { let text = 'I lov Python' let salt = '12345d' let encryptedData = CryptoJS .PBKDF2 (text, salt, {keySize : 128 / 32 , iterations : 10 }) return encryptedData.toString () } console .log (pbkdf2Encrypt ())
Python 实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import binasciifrom Cryptodome.Hash import SHA1from Cryptodome.Protocol.KDF import PBKDF2text = 'I lov Python' salt = b'12345d' result = PBKDF2(text, salt, count=10 , hmac_hash_module=SHA1) result = binascii.hexlify(result) print (result)
SHA SHA 全称安全哈希算法 SHA 是比 MD5 更安全一点的摘要算法,MD5 的密文是 32 位,而 SHA-1 是 40 位,版本越强,密文越长,代价是速度越慢。
JS 实现:
1 2 3 4 5 6 7 8 9 10 let CryptoJS = require ('crypto-js' )function SHA1Encrypt ( ) { var text = "I love python!" return CryptoJS .SHA1 (text).toString (); } console .log (SHA1Encrypt ())
Python 实现:
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 import hashlibdef sha1_test1 (): """sha1 test1""" sha1 = hashlib.new('sha1' , 'I love python!' .encode('utf-8' )) print (sha1.hexdigest()) def sha1_test2 (): """sha1 test2""" sha1 = hashlib.sha1() sha1.update('I love python!' .encode('utf-8' )) print (sha1.hexdigest()) if __name__ == '__main__' : sha1_test1() sha1_test2()
HMAC HMAC 全称散列消息认证码,秘钥相关的哈希运算消息认证码, 密钥相关的哈希运算消息认证码,HMAC 加密算法是一种安全的基于加密 Hash 函数和共享密钥的消息认证协议,它要求通信双方共享密钥 key、约定算法、对报文进行 Hash 运算,形成固定长度的认证码。通信双方通过认证码的校验来确定报文的合法性。
JS 实现:
1 2 3 4 5 6 7 8 9 10 let CryptoJS = require ('crypto-js' )function HMACEncrypt ( ) { let text = "I love python!" let key = "secret" return CryptoJS .HmacMD5 (text, key).toString (); } console .log (HMACEncrypt ())
Python 实现:
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 import hmacdef hamc_test1 (): """hamc_test""" message = b'I love python!' key = b'secret' md5 = hmac.new(key, message, digestmod='MD5' ) print (md5.hexdigest()) def hamc_test2 (): """hamc_test""" 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__' : hamc_test2() hamc_test1()
DES DES 全称数据加密标准, 加密与解密使用同一密钥,属于对称加密算法,DES 是一个分组加密算法,使用 56 位的密钥(一般认为密钥是 64 位,但是密钥的每个第 8 位设置为奇偶校验位,所以实际上有效位只有 56 位),由于 56 位密钥长度相对较短,所以 DES 是不安全的,现在基本上已被更高级的加密标准 AES 取代。
JS 实现:
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 49 let 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), 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, 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)
Python 实现:
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 import binasciifrom pyDes import des, CBC, PAD_PKCS5def des_encrypt (key, text, iv ): k = des(key, CBC, iv, pad=None , padmode=PAD_PKCS5) de = k.encrypt(text, padmode=PAD_PKCS5) return binascii.b2a_hex(de) def des_decrypt (key, text, iv ): k = des(key, CBC, iv, pad=None , padmode=PAD_PKCS5) de = k.decrypt(binascii.a2b_hex(text), padmode=PAD_PKCS5) return de if __name__ == '__main__' : secret_key = '12345678' text = 'I love Python!' iv = secret_key secret_str = des_encrypt(secret_key, text, iv) print ('加密字符串:' , secret_str) clear_str = des_decrypt(secret_key, secret_str, iv) print ('解密字符串:' , clear_str)
3DES 3DES 三重数据加密算法, 是对称加密算法中的一种.3DES 即是设计用来提供一种相对简单的方法,即通过增加 DES 的密钥长度来避免破解,所以严格来说 3DES 不是设计一种全新的块密码算法。
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 let 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), 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, 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)
Python 实现:
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 from Cryptodome import Randomfrom Cryptodome.Cipher import DES3def add_to_16 (value ): while len (value) % 16 != 0 : value += '\0' return str .encode(value) def des_encrypt (key, text, iv ): cipher_encrypt = DES3.new(add_to_16(key), DES3.MODE_OFB, iv) encrypted_text = cipher_encrypt.encrypt(text.encode("utf-8" )) return encrypted_text def des_decrypt (key, text, iv ): cipher_decrypt = DES3.new(add_to_16(key), DES3.MODE_OFB, iv) decrypted_text = cipher_decrypt.decrypt(text) return decrypted_text if __name__ == '__main__' : key = '12345678' text = 'I love Python!' iv = Random.new().read(DES3.block_size) secret_str = des_encrypt(key, text, iv) print ('加密字符串:' , secret_str) clear_str = des_decrypt(key, secret_str, iv) print ('解密字符串:' , clear_str)
AES AES 全称高级加密标准,它本身只有一个密钥,即用来实现加密,也用于解密。
mode 支持:CBC,CFB,CTR,CTRGladman,ECB,OFB 等。 padding 支持:ZeroPadding,NoPadding,AnsiX923,Iso10126,Iso97971,Pkcs7 等。
JS 实现:
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 let 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), 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, 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" var aesIv = "0123456789ABCDEF" var encryptedData = tripleAesEncrypt ()var decryptedData = tripleAesDecrypt ()console .log ("加密字符串: " , encryptedData)console .log ("解密字符串: " , decryptedData)
Python 实现:
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 import base64from Cryptodome.Cipher import AESdef add_to_16 (value ): """Add a value to""" while len (value) % 16 != 0 : value += '\0' return str .encode(value) def aes_encrypt (key, t, iv ): """Aes encrypt""" aes = AES.new(add_to_16(key), AES.MODE_CBC, add_to_16(iv)) encrypt_aes = aes.encrypt(add_to_16(t)) encrypt_text = str (base64.encodebytes(encrypt_aes), encoding='utf-8' ) return encrypt_text def aes_decrypt (key, t, iv ): aes = AES.new(add_to_16(key), AES.MODE_CBC, add_to_16(iv)) base64_decrypted = base64.decodebytes(t.encode(encoding='utf-8' )) decrypted_text = str (aes.decrypt(base64_decrypted), encoding='utf-8' ).replace('\0' , '' ) return decrypted_text if __name__ == '__main__' : secret_key = '12345678' text = 'I love Python!' iv = secret_key encrypted_str = aes_encrypt(secret_key, text, iv) print ('加密字符串:' , encrypted_str) decrypted_str = aes_decrypt(secret_key, encrypted_str, iv) print ('解密字符串:' , decrypted_str)
RC4 RC4 是一种流行加密算法,密钥长度可变。它加解密使用相同的密钥,因此也属于对称加密算法。RC4 是有线等效加密(WEP)中采用的加密算法,也曾经是 TLS 可采用的算法之一,
JS 实现:
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 let CryptoJS = require ('crypto-js' )function RC4Encrypt ( ) { return CryptoJS .RC4 .encrypt (text, key).toString (); } function RC4Decrypt ( ) { return CryptoJS .RC4 .decrypt (encryptedData, key).toString (CryptoJS .enc .Utf8 ); } var text = "I love Python!" var key = "6f726c64f2c2057c" var encryptedData = RC4Encrypt ()var decryptedData = RC4Decrypt ()console .log ("加密字符串: " , encryptedData)console .log ("解密字符串: " , decryptedData)
Python 实现:
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 import base64from Cryptodome.Cipher import ARC4def rc4_encrypt (key, t ): """Encrypt""" enc = ARC4.new(key.encode('utf8' )) res = enc.encrypt(t.encode('utf-8' )) res = base64.b64encode(res) return res def rc4_decrypt (key, t ): """Decrypt""" data = base64.b64encode(t) enc = ARC4.new(key.encode('utf8' )) res = enc.decrypt(data) return res if __name__ == '__main__' : secret_key = '12345678' text = 'I love Python!' encrypted_str = rc4_encrypt(secret_key, text) print ('加密字符串:' , encrypted_str) decrypted_str = rc4_decrypt(secret_key, encrypted_str) print ('解密字符串:' , decrypted_str)
RSA RSA 加密算法是一种非对称加密算法。在公开密钥加密和电子商业中RSA被广泛使用。它被普遍认为是目前比较优秀的公钥方案之一。RSA是第一个能同时用于加密和数字签名的算法,它能够抵抗到目前为止已知的所有密码攻击。
JS 实现:
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 let 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 }); var publicKey = key.exportKey ('pkcs8-public' ); var privatekey = key.exportKey ('pkcs8-private' ); var text = "I love Python!" 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)
Python 实现:
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 import rsa as rsadef rsa_encrypt (pu_key, t ): """Encrypt""" return rsa.encrypt(t.encode("utf-8" ), pu_key) def rsa_decrypt (pr_key, t ): """私钥解密""" return rsa.decrypt(t, pr_key).decode("utf-8" ) if __name__ == "__main__" : public_key, private_key = rsa.newkeys(512 ) print ('公钥:' , public_key) print ('私钥:' , private_key) text = 'I love Python!' encrypted_str = rsa_encrypt(public_key, text) print ('加密字符串:' , encrypted_str) decrypted_str = rsa_decrypt(private_key, encrypted_str) print ('解密字符串:' , decrypted_str)