模块安装
- JS:
npm install crypto-js --save
1. MD5
MD5
哈希视为字符串,而是将其视为十六进制数, MD5
哈希长度为128位,通常由32
个十六进制数字表示。因此在看见加密字段长度为32位时可以先试试看是不是MD5加密。
JS实现
// 引用 crypto-js 加密模块
var CryptoJS = require('crypto-js')
function MD5Test() {
var text = "hello word!"
return CryptoJS.MD5(text).toString()
}
console.log(MD5Test())
Python实现
import hashlib
def md5_test():
md5 = hashlib.md5()
md5.update('python'.encode('utf-8'))
print(md5.hexdigest())
if __name__ == '__main__':
md5_test()
2. SHA
全称安全哈希算法。SHA
通常指 SHA
家族的五个算法
- SHA-1:长度40
- SHA-224:长度56
- SHA-256:长度64
- SHA-384:长度96
- SHA-512:长度128
JS实现
var CryptoJS = require('crypto-js')
function SHAEncrypt() {
var text = "hello!"
return CryptoJS.SHA1(text).toString();
return CryptoJS.SHA224(text).toString();
return CryptoJS.SHA256(text).toString();
return CryptoJS.SHA384(text).toString();
return CryptoJS.SHA512(text).toString();
}
console.log(SHAEncrypt())
Python实现
import hashlib
def sha1_test():
sha1 = hashlib.sha1()
sha1.update('hello!'.encode('utf-8'))
print(sha1.hexdigest())
if __name__ == '__main__':
sha1_test()
3. HMAC
简单来说HMAC是在其他算法的基础上加上共享密钥(key)实现的,因此生成的密文长度和使用的基础算法一样。
JS实现
var CryptoJS = require('crypto-js')
function HMACText() {
var text = "hello word"
var key = "我是key"
var a = CryptoJS.HmacMD5(text, key).toString()
// var a = CryptoJS.HmacSHA1(text, key).toString()
console.log("明文:", text);
console.log("密文:", a);
console.log("长度:", a.length);
}
HMACText()
Python实现
import hmac
def hmac_test1():
message = 'hello word!'.encode()
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('hello '.encode('utf8'))
sha1.update('word!'.encode('utf8'))
print(sha1.hexdigest())
if __name__ == '__main__':
hmac_test1()
hmac_test2()
4. 对称加密
简单来说就是加密和解密使用同一个密钥。
常见算法归纳
DES:56位密钥,由于密钥太短,被逐渐被弃用。
AES:有128位、192位、256位密钥,现在比较流行。密钥长、可以增加破解的难度和成本。
工作模式归纳
- ECB模式 全称Electronic Codebook模式,译为电子密码本模式,每个数据块独立进行加/解密
- CBC模式 全称Cipher Block Chaining模式,译为密文分组链接模式
- 先将明文切分成若干小块,然后每个小块与初始块或者上一段的密文段进行逻辑异或运算后,再用密钥进行加密。第一个明文块与一个叫初始化向量的数据块进行逻辑异或运算
- CFB模式 全称Cipher FeedBack模式,译为密文反馈模式
- OFB模式 全称Output Feedback模式,译为输出反馈模式。
- CTR模式 全称Counter模式,译为计数器模式。
4.1 DES
DES
算法的入口参数有3个:key、DATA、Mode、padding
key
为7个字节
共56位,是DES算法的工作密钥Data
为8个字节
64位,是要被加密或被解密的数据Mode
为DES
的工作方式padding
为填充模式,如果加密后密文长度如果达不到指定整数倍(8个字节,16个字节),填充
JS实现
var CryptoJS = require('crypto-js')
function encryptByDES(message) {
var keyHex = CryptoJS.enc.Utf8.parse(key)
var encrypted = CryptoJS.DES.encrypt(message, keyHex, {
iv: CryptoJS.enc.Utf8.parse(iv),
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7 //我也可以不要
});
return encrypted.toString()
}
function decryptByDES(ciphertext) {
var keyHex = CryptoJS.enc.Utf8.parse(key)
var decrypted = CryptoJS.DES.decrypt({
ciphertext: CryptoJS.enc.Base64.parse(ciphertext)
}, keyHex, {
iv: CryptoJS.enc.Utf8.parse(iv),
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7 //我也可以不要
});
return decrypted.toString(CryptoJS.enc.Utf8)
}
var key = "我是密钥key"
var iv = "我是初始向量,可以不要"
var message = "我是需要加密的变量"
var encryptedData = encryptByDES(message)
var decryptedData = decryptByDES(encryptedData)
console.log("加密字符串: ", encryptedData)
console.log("解密字符串: ", decryptedData)
Python实现
pip install pyDes
import binascii
# 加密模式 CBC,填充方式 PAD_PKCS5
from pyDes import des, CBC, PAD_PKCS5
def des_encrypt(key, text, iv):
k = des(key, CBC, iv, pad=None, padmode=PAD_PKCS5)
en = k.encrypt(text, padmode=PAD_PKCS5)
return binascii.b2a_hex(en)
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 = 'hello world' # 加密对象
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)
4.2 AES
参数定义:
- key length(密钥位数,密码长度)
AES128,AES192,AES256(128 位、192 位或 256 位)
- key (密钥,密码)key指的就是密码了,
AES128
就是128位
的,如果位数不够,某些库可能会自动填充到128
。 - IV (向量)IV称为初始向量,不同的IV加密后的字符串是不同的,加密和解密需要相同的IV。
- mode (加密模式)AES分为几种模式,比如ECB,CBC,CFB等等,这些模式除了ECB由于没有使用IV而不太安全,其他模式差别并没有太明显。
- padding (填充方式)对于加密解密两端需要使用同一的PADDING模式,大部分PADDING模式为
PKCS5, PKCS7, NOPADDING
。
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 = "hello word!" // 待加密对象
var aesKey = "6f726c64f2c2057c" // 密钥,16 倍数
var aesIv = "0123456789ABCDEF" // 偏移量,16 倍数
var encryptedData = tripleAesEncrypt()
var decryptedData = tripleAesDecrypt()
console.log("加密字符串: ", encryptedData)
console.log("解密字符串: ", decryptedData)
5. 非对称加密
与对称加密算法不同,非对称加密算法需要两个密钥:公开密钥(publickey)
和私有密钥(privatekey)
。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。
- 常见非对称加密算法
RSA
、DSA
。 - 非对称加密算法私钥由数据接收方持有,不会在网络上传递,保证了密钥的安全。
- 非对称加密算法通常比对称加密算法计算复杂,性能消耗高。
- 非对称加密算法可用于数字签名。
注意:
- 使用时都是使用公钥加密使用私钥解密,公钥可以公开,私钥自己保留。
- 算法强度复杂、安全性依赖于算法与密钥但是由于其算法复杂,而使加密解密速度慢于对称加密
JS实现
npm install node-rsa --save
var NodeRSA = require('node-rsa');
function rsaEncrypt(text) {
pubKey = new NodeRAS(publicKey, 'pkcs8-public')
var encryptedData = pubKey.encrypt(text, 'base64')
return encryptedData
}
function rsaDecrypt(encryptedDate) {
priKey = new NodeRAS(privateKey, 'pkcs8-private')
var decryptedData = priKey.decrypt(encryptedDate, 'utf-8')
return decryptedData
}
var key = new NodeRAS({b: 512}) //生成512位的密钥
var publicKey = key.exportKey('pkcs8-public') // 导出公钥
var privateKey = key.exportKey('pkcs8-private') // 导出私钥
var text = "我是需要加密内容"
var encryptedDate = rsaEncrypt(text)
var decryptedDate = rsaDecrypt(encryptedDate)
console.log("公钥:", publicKey)
console.log("私钥:", privateKey)
console.log("加密字符串:", encryptedDate)
console.log("解密字符串:", decryptedDate)
6. 国密
由国家密码管理局发布的一系列国产加密算法,这其中就包括 SM1、SM2、SM3 、SM4、SM7、SM9、ZUC
(祖冲之加密算法)等,SM
代表商密,即商业密码,是指用于商业的、不涉及国家秘密的密码技术。SM1
和 SM7
的算法不公开,其余算法都已成为ISO/IEC
国际标准。
6.1 算法分类
算法名称 | 算法类别 | 应用领域 | 特点 |
---|---|---|---|
SM1 | 对称(分组)加密算法 | 芯片 | 分组长度、密钥长度均为 128 比特 |
SM2 | 非对称(基于椭圆曲线 ECC)加密算法 | 数据加密 | ECC 椭圆曲线密码机制 256 位,相比 RSA 处理速度快,消耗更少 |
SM3 | 散列(hash)函数算法 | 完整性校验 | 安全性及效率与 SHA-256 相当,压缩函数更复杂 |
SM4 | 对称(分组)加密算法 | 数据加密和局域网产品 | 分组长度、密钥长度均为 128 比特,计算轮数多 |
SM7 | 对称(分组)加密算法 | 非接触式 IC 卡 | 分组长度、密钥长度均为 128 比特 |
SM9 | 标识加密算法(IBE) | 端对端离线安全通讯 | 加密强度等同于 3072 位密钥的 RSA 加密算法 |
ZUC | 对称(序列)加密算法 | 移动通信 4G 网络 | 流密码 |
6.2 算法还原
JS实现sm2
npm install sm-crypto --save
目前支持SM2、SM3 和 SM4
const sm2 = require('sm-crypto').sm2
// 1 - C1C3C2,0 - C1C2C3,默认为1
const cipherMode = 1
// 获取密钥对
let keypair = sm2.generateKeyPairHex()
let publicKey = keypair.publicKey // 公钥
let privateKey = keypair.privateKey // 私钥
let msgString = "this is the data to be encrypted"
let encryptData = sm2.doEncrypt(msgString, publicKey, cipherMode) // 加密结果
let decryptData = sm2.doDecrypt(encryptData, privateKey, cipherMode) // 解密结果
console.log("encryptData: ", encryptData)
console.log("decryptData: ", decryptData)
Python实现sm2
pip install gmssl
目前支持SM2、SM3 和 SM4
from gmssl import sm2
# 16 进制的公钥和私钥
private_key = '00B9AB0B828FF68872F21A837FC303668428DEA11DCD1B24429D0C99E24EED83D5'
public_key = 'B9C9A6E04E9C91F7BA880429273747D7EF5DDEB0BB2FF6317EB00BEF331A83081A6994B8993F3F5D6EADDDB81872266C87C018FB4162F5AF347B483E24620207'
sm2_crypt = sm2.CryptSM2(public_key=public_key, private_key=private_key)
# 待加密数据和加密后数据为 bytes 类型
data = b"this is the data to be encrypted"
enc_data = sm2_crypt.encrypt(data)
dec_data = sm2_crypt.decrypt(enc_data)
print('enc_data: ', enc_data.hex())
print('dec_data: ', dec_data)
取盐校验
(不可逆) md5 md2 md4 带密码的md5(hmac)
sha1 sha256 sha512
对称加密(可还原)
AES DES 3DES 非对称加密(可还原)
RSA(私钥 公钥) 同一个明文可以生成不同密文
特点:
1. 16进制,最大到f
2. base64 A-z a-z 0-9 +_=
1. 97d1605433a827a7f6b609847b80996d
2. l9FgVDOoJ6f2tgmEe4CZbQ==
md5:16位 32位 40位
32位、40位由16位两边做了一些处理
默认key 0123456789abcdef
123456通过md5加密:
49ba59abbe56e057
e10adc3949ba59abbe56e057f20f883e
12345通过sha1加密:
7c4a8d09ca3762af61e59520943dc26494f8941b
记一下123456的
sha1 sha256 sha512
40位 64位 128位
1.抓包 2.调试 搜索 password userid url链接 persistentCookie i/login/116005 (关键词 如果没有混淆,可以找到明文字体) abcdef 123456789 1732584193(搜索到md5加密算法) XHR
赋值方式:
对象.password password= (格式化多了一个空格 password =) ['password'] ["password"]
加盐:
hash(hash($input))
hash($input.$salt)
hash(hash($input).$salt)
搜索md5加密或者base64加密(RSA 转base64),通过跟栈,获得原始加密地方
hook btoa
3.扣取js
扣全了吗
this是谁
对象会用 : 冒号
var duixiang={
name: 'xiaoming',
md5:function (){
return 'md5'
}
}
const dx= duixiang;
console.log(dx.md5())
var xxx=function(){}
function xx(){
}
扣js改越少越好,不改可以运行最好,js的体积大小
如果utils是全局变量(utils=) 可以全扣
在闭包导出变量 在变量后面}的逗号,window.utils=utils; var(改,成var) 导出utils
导出 扣代码、补环境
4.改写 5.本地运行出值 请求服务器拿值
二进制数据进行编码和解码的方式
-
字节(byte)数组转化成 十六进制(hex):
每一个字节(8位二进制数)可以被表示为一个两位的十六进制数。比如,
10101100
这个字节可以变成AC
。字节数组转化成十六进制字符串是,将数组中的每一个字节都转化成一个两位的十六进制数,然后将这些十六进制数连接起来,形成一个字符串。 -
字节(byte)数组转化成 Base64:
Base64编码是一种编码方式,将二进制数据转化为一种仅包含64种可打印字符(A-Z, a-z, 0-9, +, /)以及等号(=,用于填充)的编码方式。这样原本二进制的数据就可以用文本的方式进行处理了,比如可以在网页上显示,或者通过邮件发送。其基本的转化过程是先将3个字节(24位)的数据,切分成4个6位的数据,然后对应到 Base64 的字符集合上,形成一个包含4个字符的字符串。
-
UTF-8编码与解码:
UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码,也是一种全球最常用的编码方式。它可以用来表示世界上几乎所有的字符,对于英语字符只需要一个字节的空间,对于其他语言字符,比如汉字,则可能需要2到4个字节的空间。当我们对一个字符串进行UTF-8编码时,就是将这个字符串的每一个字符转化为对应的一组字节(byte);解码过程则是相反,将一组字节转化为对应的字符。
举例来说,如果你有一个字节数组 [72,101,108,108,111]
:
-
转化为十六进制形式就是
"48656c6c6f"
-
转化为 Base64 形式是
"SGVsbG8="
-
如果这是一个UTF-8编码的字符串,解码之后就是
"Hello"
总结来说,这些都是对二进制数据进行编码和解码的方式,使数据在不同形式之间进行转换,满足不同的使用需求。
javascript自执行函数
写法
-
最前最后加括号
(function(){alert(1);}());
JSLINT推荐这种写法
-
function外面加括号
(function(){alert(1);})();
目前很多比较好的js library 使用的都是第二种方式。 比如: web 图形绘制的: git , draw2d ,....
-
function前面加运算符,常见的是!与void
!function(){alert(1);}(); void function(){alert(2);}();
在function前面加!、+、 -甚至是逗号等到都可以起到函数定义后立即执行的效果,而()、!、+、-、=等运算符,都将函数声明转换成函数表达式,消除了javascript引擎识别函数表达式和函数声明的歧义
在Web开发中,保护用户数据是至关重要的,而对数据进行加密是其中一种有效手段。本文将深入浅出地介绍常见的加解密算法,包括消息摘要算法、对称加密算法以及非对称加密算法。
消息摘要算法
消息摘要算法,哈希算法
消息摘要算法是一种单向散列函数,常用于加密和数据完整性验证。常见的消息摘要算法包括MD5、SHA-1、SHA-256和SHA-512等。它的特点是对不同的明文生成唯一且定长的密文,是不可逆的,即无法通过“密文”还原出明文。
md5
const CryptoJs = require('crypto-js');
let password = "123456";
let encPwd = CryptoJs.MD5(password).toString();
console.log(encPwd); // e10adc3949ba59abbe56e057f20f883e
sha1
const CryptoJs = require('crypto-js');
let password = "123456";
let encPwd = CryptoJs.SHA1(password).toString();
console.log(encPwd); // 7c4a8d09ca3762af61e59520943dc26494f8941b
对称加密算法
对称加密算法
对称加密算法是一种加密技术,它使用相同的密钥(称为对称密钥)同时用于加密和解密数据。常见的加密算法有DES
、AES
、3DES
等。AES是一种广泛使用的对称加密算法,被认为是目前最安全的对称加密算法之一。
AES-ECB
let password = "123456";
let key = "1234567890abcdef"
cfg = {
mode: CryptoJs.mode.ECB,
padding: CryptoJs.pad.Pkcs7
}
let encPwd = CryptoJs.AES.encrypt(password, key, cfg).toString()
console.log(encPwd) // U2FsdGVkX1+meKI+IXd44qgc50bKb2rDbN91OutwBWs=
根据密钥长度的不同, 可以把AES加密算法分为AES-128/AES-192/AES-256。也就是说密钥的长度必须是16/24/32个字节 。常见mode模式有CBC
、ECB
两种,这两种模式的区别在于是否需要配置iv
向量
AES-CBC
const CryptoJs = require('crypto-js');
let password = CryptoJs.enc.Utf8.parse("123456") // 指定以什么编码方式解析明文
let key = CryptoJs.enc.Utf8.parse("1234567890abcdef")
let iv = CryptoJs.enc.Utf8.parse("123456") // 需指定初始向量
cfg = {
mode: CryptoJs.mode.CBC,
padding: CryptoJs.pad.Pkcs7,
iv: iv
}
let encPwd = CryptoJs.AES.encrypt(password, key, cfg).toString()
非对称加密算法
非对称加密算法
非对称加密算法是一种密码学中的加密方式,也被称为公钥加密算法。与对称加密算法不同,非对称加密算法使用一对密钥,分别是公钥和私钥。非对称加密算法的一个关键特性是,使用公钥加密的数据只能由相应的私钥解密,而使用私钥加密的数据只能由相应的公钥解密。常见的非对称加密算法包括RSA和ECC等
公钥可以公开分享的密钥,用于加密数据。任何人都可以获得公钥,但不能由公钥推导出私钥。
私钥是保密的密钥,用于解密由公钥加密的数据。只有私钥的持有者能够解密使用公钥加密的信息。
RSA
window = global
const JSEncrypt = require('jsencrypt')
publickey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnX3j/luQG7JnPFIFJKEvPC/tFtv14XIzT7FQXYpKsOt2t4uLh6hZa5H5WcEinF46nc91UbrS5UA9Fnnm+Ev20pwUEPVu4On47am6vJOsq8oqQoZDsMu6VGZIzKIm8vDylO6I2xrTaXY2G3hdiRKF7988tA4oYsFOTZ/yG/BOlNwIDAQAB'
// 加密
let jse = new JSEncrypt()
jse.setPublicKey(publickey)
var encStr = jse.encrypt('123456')
console.log("加密数据: " + encStr)
// 解密
privatekey = 'MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAKdfeP+W5Absmc8UgUkoS88L+0W2/XhcjNPsVBdikqw63a3i4uHqFlrkflZwSKcXjqdz3VRutLlQD0Weeb4S/bSnBQQ9W7g6fjtqbq8k6yryipChkOwy7pUZkjMoiby8PKU7ojbGtNpdjYbeF2JEoXv3zy0DihiwU5Nn/Ib8E6U3AgMBAAECgYA6KW0stEytM08HrQJ4X65oVquMwFg4mUC+7CMUtUZu303lfTCGfQgjsb9NXluA5SjHe/Xvv0DCHNYRxU5dBNBwhIXaRLy6zLKKKp/0gOn1C3dFY/MQOVoEpJ8uxUQh9Kf37F5J9gT64JNooKTTNydqTcmfIhG/u3WFiTVjfW5sEQJBANmvAgUneA6eEC6LwhX9gxdp0T2S+hop19zAm4ErHQld47TlSAxVgwArQG4oJ5J2OWlIT4vzuO1OJOaCj4wZYXMCQQDE1W0uZA1YtjVK7OUuD3f/rgNzolpc0XEEZDPxKsoirEFgW/cFNCTJKIdGK2RgnthLWiN01a9bL6+sF2vLO2wtAkAd0h3Cuv91cS3iUn8KKCqXQIXLm6DriKPrt+8VqORXbidNlsNh/SzvDv3KmXGiXNPMmn1bPM4upC/l7CjiFnAFAkBnmu+dO4zK5R2oEomPdRT0v+OROiPWN2gFp7iveJZtKb4/uiiL1KaIO4z4ol5zfSjcgNWo6dEjbjZJnwpeLykBAkAY/tYLGyrHe0isoZL2xXPlrvde2tbKcbzMrheH1wuqEMX0o0+uHCyFgn2rAzMcfUlntb9iZLLJDkJ+bFET1j3l'
jse.setPrivateKey(privatekey)
var Str = jse.decrypt(encStr)
console.log("解密数据: " + Str)