一、摘要算法
1.1 简介
摘要算法(Hashing Algorithm),也称为哈希算法,是一种将任意长度的数据映射为固定长度的值的算法。这个固定长度的值被称为“哈希值”或“摘要”。摘要算法的主要特点是: 不可逆、高效、 唯一性 (不同的输入应生成不同的输出)和敏感性(即使输入的改变非常微小,输出也会完全不同)。
摘要算法广泛用于数据完整性验证、数字签名、密码存储等领域。下面是关于摘要算法的详细介绍,包括常见的算法及其应用。
1.2 摘要算法的特点
固定长度输出:不管输入数据的大小是多少,摘要算法总是生成固定长度的输出。对于MD5来说,输出是128位(16字节);对于SHA-256来说,输出是256位(32字节)。
-
不可逆性:摘要算法是单向的,从哈希值无法反推出原始输入。这一点使它们适合用于密码学中的密码存储和数字签名。
-
雪崩效应:输入的微小变化(如一个比特的变动)会导致输出的哈希值发生巨大变化。这一特性有助于确保输出的随机性和不可预测性。
-
高效性:摘要算法通常是设计为高效的,它们能够快速地处理大数据并生成对应的哈希值。
-
抗碰撞性:两份不同的数据产生相同的哈希值的情况应非常罕见。抗碰撞性使摘要算法在许多安全场景中变得重要。
1.3 MD5 算法
- python版本:
from hashlib import md5
obj = md5()
obj.update("yuan".encode("utf-8"))
#obj.update("alex".encode('utf-8')) # 可以添加多个被加密的内容
bs = obj.hexdigest()
print(bs)
- 拓展(sha1,sha256):
from hashlib import sha1, sha256
sha = sha256(b'salt')
sha.update(b'alex')
print(sha.hexdigest())
- javascript版本:
const CryptoJS = require('crypto-js');
// 原始数据
const data = '123456';
// 生成MD5摘要
const md5Digest = CryptoJS.MD5(data).toString();
console.log(md5Digest);
二、 DES/AES加密(可逆)
-
DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的算法。该加密算法是一种对称加密方式,其加密运算、解密运算需要使用的是同样的密钥(一组字符串)即可。
-
注意:
- 现在用AES这个标准来替代原先的DES。
- AES和DES的区别:
- 加密后密文长度的不同:
- DES加密后密文长度是8的整数倍
- AES加密后密文长度是16的整数倍
- 应用场景的不同:
- 企业级开发使用DES足够安全
- 如果要求高使用AES
- 加密后密文长度的不同:
-
DES算法的入口参数有三个:
- Key、Data、Mode,padding、iv。
- Key为DES算法的工作密钥;
- Data为要被加密或被解密的数据;
- Mode为DES的工作模式。最常用的模式就是 CBC 模式和 ECB模式
- ECB:是一种基础的加密方式,密文被分割成分组长度相等的块(不足补齐),然后单独一个个加密,一个个输出组成密文。
- CBC:是一种循环模式,前一个分组的密文和当前分组的明文异或后再加密,这样做的目的是增强破解难度。
- padding为填充模式,如果加密后密文长度如果达不到指定整数倍(8个字节、16个字节),填充对应字符
- iv:参数中的iv主要用于CBC模式,确保即使加密相同的明文,每次产生的密文也不相同,增强加密的安全性。iv通常是一个16字节的随机字符串。这个字符串在解密时也需要用到,因此需要妥善保存。
- Key、Data、Mode,padding、iv。
-
Python版本:
-
环境安装:
pip install pycryptodome
-
加密代码:
from Crypto.Cipher import AES from Crypto.Util.Padding import pad import base64 key = '0123456789abcdef'.encode() # 秘钥: 必须16字节 iv = b'abcdabcdabcdabcd' # 偏移量:16位/字节(字节类型) text = 'alex is a monkey!' # 加密内容 #设置加密内容的长度填充(位数为16的整数倍) text = pad(text.encode(), 16) #创建加密对象 aes = AES.new(key, AES.MODE_CBC, iv) # 创建一个aes对象 en_text = aes.encrypt(text) # 加密明文 print("aes加密数据:::", en_text) #返回二进制类型数据 #二进制密文转换成字符串格式 en_text = base64.b64encode(en_text).decode() # 将返回的字节型数据转进行base64编码 print(en_text)
-
解密代码:
from Crypto.Cipher import AES import base64 from Crypto.Util.Padding import unpad key = '0123456789abcdef'.encode() iv = b'abcdabcdabcdabcd' aes = AES.new(key, AES.MODE_CBC, iv) #需要解密的文本 text = 'X/A0fy9S7+kUI3HYQRKO46WTlid6T1DBhXutwmPdboY='.encode() #将密文数据转换为二进制类型 ecrypted_base64 = base64.b64decode(text) source = aes.decrypt(ecrypted_base64) # 解密 #未填充数据 print("aes解密数据:::", source.decode()) #取消填充数据 print("aes解密数据:::", unpad(source, 16).decode())
-
-
JS版本:
-
加密:
const CryptoJS = require("crypto-js") // 密钥(128位,16字节) var key = CryptoJS.enc.Utf8.parse('0123456789abcdef'); // 初始化向量(IV)(128位,16字节) var iv = CryptoJS.enc.Utf8.parse('1234567890abcdef'); // 待加密的数据 var plaintext = 'Hello, bobo!'; // 进行AES-128加密,使用CBC模式和PKCS7填充 var encrypted = CryptoJS.AES.encrypt(plaintext, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); // 获取加密后的密文 var ciphertext = encrypted.toString(); console.log(ciphertext);
-
解密:
const CryptoJS = require("crypto-js") // 密钥(128位,16字节) var key = CryptoJS.enc.Utf8.parse('0123456789abcdef'); // 初始化向量(IV)(128位,16字节) var iv = CryptoJS.enc.Utf8.parse('1234567890abcdef'); // 密文数据 var encrypText = 'GYc9oxlZB/PeyfFG3ppK6Q=='; // 进行加密,使用CBC模式和PKCS7填充 var decrypted = CryptoJS.AES.decrypt(encrypText, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); // 解密 var plaintext = decrypted.toString(CryptoJS.enc.Utf8); console.log(plaintext);
-
-
上述代码的关键字:
- AES,DES
- encrypt(用于加密的函数名),decrypt(用于解密的函数名)
- xxxkey:秘钥一般是单独生成的,一定不会傻到明文的写在代码中!
三、RSA加密(可逆)
- RSA加密:
- RSA加密算法是一种非对称加密算法。在公开密钥加密和电子商业中RSA被广泛使用。
- 非对称加密算法:
- 非对称加密算法需要两个密钥:
- 公开密钥(publickey:简称公钥)
- 私有密钥(privatekey:简称私钥)
- 公钥与私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。
- 非对称加密算法需要两个密钥:
- 注意:
- 使用时都是使用公匙加密使用私匙解密。公匙可以公开,私匙自己保留。
- 算法强度复杂、安全性依赖于算法与密钥但是由于其算法复杂,而使得加密解密速度没有对称加密解密的速度快。
- 使用流程和场景介绍
- 通过公匙加密,使用私匙解密。私匙是通过公匙计算生成的。假设ABC三方之间相互要进行加密通信。大家相互之间使用公匙进行信息加密,信息读取时使用各自对应的私匙进行信息解密
- 用户输入的支付密码会通过RSA加密
- 公钥私钥生成方式:
- 公私匙可以在线生成
- http://web.chacuo.net/netrsakeypair
- 公私匙可以在线生成
- 环境安装:npm install jsencrypt
JS代码示例:
window = global;
const JSEncrypt = require('jsencrypt');
var PUBLIC_KEY = '-----BEGIN PUBLIC KEY-----MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALyBJ6kZ/VFJYTV3vOC07jqWIqgyvHulv6us/8wzlSBqQ2+eOTX7s5zKfXY40yZWDoCaIGk+tP/sc0D6dQzjaxECAwEAAQ==-----END PUBLIC KEY-----';
//私钥
var PRIVATE_KEY = '-----BEGIN PRIVATE KEY-----MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAvIEnqRn9UUlhNXe84LTuOpYiqDK8e6W/q6z/zDOVIGpDb545NfuznMp9djjTJlYOgJogaT60/+xzQPp1DONrEQIDAQABAkEAu7DFsqQEDDnKJpiwYfUE9ySiIWNTNLJWZDN/Bu2dYIV4DO2A5aHZfMe48rga5BkoWq2LALlY3tqsOFTe3M6yoQIhAOSfSAU3H6jIOnlEiZabUrVGqiFLCb5Ut3Jz9NN+5p59AiEA0xQDMrxWBBJ9BYq6RRY4pXwa/MthX/8Hy+3GnvNw/yUCIG/3Ee578KVYakq5pih8KSVeVjO37C2qj60d3Ok3XPqBAiEAqGPvxTsAuBDz0kcBIPqASGzArumljkrLsoHHkakOfU0CIDuhxKQwHlXFDO79ppYAPcVO3bph672qGD84YUaHF+pQ-----END PRIVATE KEY-----';
//使用公钥加密
var encrypt = new JSEncrypt();//实例化加密对象
encrypt.setPublicKey(PUBLIC_KEY);//设置公钥
var encrypted = encrypt.encrypt('hello bobo!');//对指定数据进行加密
console.log(encrypted);//使用私钥解密
//使用私钥解密
var decrypt = new JSEncrypt();
decrypt.setPrivateKey(PRIVATE_KEY);//设置私钥
var uncrypted = decrypt.decrypt(encrypted);//解密
console.log(uncrypted);
Python代码示例:
1.创建公钥和私钥
from Crypto.PublicKey import RSA
# 通过相关算法生成唯一秘钥
rsakey = RSA.generate(1024)
#将秘钥保存到文件中
with open("rsa.public.pem", mode="wb") as f:
f.write(rsakey.publickey().exportKey())
with open("rsa.private.pem", mode="wb") as f:
f.write(rsakey.exportKey())
2.加密算法实现
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
import base64
# 加密
data = "我喜欢你"
with open("rsa.public.pem", mode="r") as f:
pk = f.read()
rsa_pk = RSA.importKey(pk)
#基于公钥创建加密对象
rsa = PKCS1_v1_5.new(rsa_pk)
result = rsa.encrypt(data.encode("utf-8"))
# 处理成b64方便传输
b64_result = base64.b64encode(result).decode("utf-8")
print(b64_result)
3.解密算法实现
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
import base64
data = '17wJJtBBujJurHRu3teDC44jSllmqcB9a22U1DQ5/IsI0m3NuShPTxBq8pLTWRdszPapiXfjvOh47P9u5+7U4hvNZL+kKqs3H5m4BKKphORUUfqb9zTowoHb1mM9ji2LuMAYmc1l70ZR+s9XsV3HrHCV/S2FzGWngcWpNVtsTJg='
# 解密
with open("rsa.private.pem", mode="r") as f:
prikey = f.read()
rsa_pk = RSA.importKey(prikey)
#创建解密对象
rsa = PKCS1_v1_5.new(rsa_pk)
result = rsa.decrypt(base64.b64decode(data), None)
print("rsa解密数据:::", result.decode("utf-8"))
以上是在JavaScript和python中对常用摘要算法和常用请求加密算法的详细的介绍和代码的实现。