常用加解密算法介绍
版权归作者所有,如有转发,请注明文章出处:https://cyrus-studio.github.io/blog/
常见加解密工具
CyberChef
CyberChef 是一个功能强大的数据处理工具,由 GCHQ(英国政府通信总部)开发。它提供了一系列 加密、解密、编码、解码、数据转换、压缩、哈希、取证分析 等功能,适用于安全研究、数据处理和取证分析等场景。
CyberChef Web 地址:https://gchq.github.io/CyberChef/
openssl
OpenSSL 是一个开源加密库,支持 SSL/TLS 协议,实现 RSA、AES、SM2、SM4 等算法,提供加密、证书管理、哈希计算等功能,广泛用于网络安全、身份认证和数据保护。
项目地址:https://github.com/openssl/openssl
各种常见的加密算法在 openssl 中都有实现
cryptopp
Crypto++ 是一个开源 C++ 加密库。
cryptopp 编译相对于 openssl 比较简便,不需要安装特殊依赖环境。
项目地址:https://github.com/weidai11/cryptopp
chilkat
Chilkat 是一个跨平台加密和网络通信库,收费,不开源,但是已经编译好各种平台的库,直接拿来就用。
下载地址:https://www.chilkatsoft.com/downloads.asp
编码算法
编码算法是一种用于数据转换的方法,它将信息从一种格式转换为另一种格式,便于存储和传输。
Hex
Hex 编码是一种将二进制数据转换为十六进制字符串的编码方式
data = b"Hello"
hex_encoded = data.hex()
print("Hex 编码:", hex_encoded)
hex_decoded = bytes.fromhex(hex_encoded)
print("Hex 解码:", hex_decoded.decode())
输出如下:
Hex 编码: 48656c6c6f
Hex 解码: Hello
URL Encode / URL Decode
URL 编码 是一种用于在 URL 中安全传输特殊字符的编码方式,将非 ASCII 字符、特殊字符转换为百分号(%)+ 两位十六进制数的格式。
URL 解码 是将 URL 编码的内容转换回原始字符的过程。
import urllib.parse
# 原始字符串
text = "Hello World! 你好?"
# URL 编码
encoded_text = urllib.parse.quote(text)
print("URL 编码:", encoded_text)
# URL 解码
decoded_text = urllib.parse.unquote(encoded_text)
print("URL 解码:", decoded_text)
输出如下:
URL 编码: Hello%20World%21%20%E4%BD%A0%E5%A5%BD%EF%BC%9F
URL 解码: Hello World! 你好?
HTML Entity
HTML Entity(HTML 实体编码) 是 HTML 中用于表示特殊字符的编码方式,通常用于防止 HTML 解析错误、显示特殊符号、避免 XSS 攻击(避免 alert(1) 被浏览器解析执行)。
常见 HTML 实体
import html
# HTML 实体编码
text = '<Hello & "World">'
encoded_text = html.escape(text)
print("HTML 实体编码:", encoded_text)
# HTML 实体解码
decoded_text = html.unescape(encoded_text)
print("HTML 实体解码:", decoded_text)
输出如下:
HTML 实体编码: <Hello & "World">
HTML 实体解码: <Hello & "World">
Base64
Base64 是一种二进制到文本的编码方式,常用于数据传输、存储、避免特殊字符问题。
它将任意二进制数据转换成可打印的 ASCII 字符(A-Z, a-z, 0-9, +, /,=)。
关于 Base64 算法详细介绍:https://zh.wikipedia.org/zh-hans/Base64
标准 Base64 算法中,3个字节为一组由4个可打印字符来表示
不足 3 字节时,用 = 进行填充(占位)。
默认是标准索引表,点右边小三角也可以切换其他变形的索引表
当遇到这种情况就需要从代码中查找对应的索引表了
import base64
# 原始数据
data = "Hello, Base64!"
# Base64 编码
encoded = base64.b64encode(data.encode()).decode()
print("Base64 编码:", encoded)
# Base64 解码
decoded = base64.b64decode(encoded).decode()
print("Base64 解码:", decoded)
输出如下:
Base64 编码: SGVsbG8sIEJhc2U2NCE=
Base64 解码: Hello, Base64!
Hash 算法
Hash 算法(散列算法) 是一种将任意长度的输入数据转换为固定长度的哈希值(摘要)的算法。它不可逆,常用于数据完整性校验、密码存储、数字签名、区块链等。
CRC-32
CRC-32 通过 对数据块进行循环冗余校验,生成一个 32位(4字节)的哈希值(通常称为 CRC 校验码),用于验证数据是否在传输过程中发生了变化。
CRC-32 生成 4 个字节 32位 的校验值,554b4ff1 实际上是 Hex,CyberChef 显示的是 Hex 的字符串
import binascii
# 数据
data = b"Hello, CRC-32!"
# 计算 CRC-32
crc32_value = binascii.crc32(data)
print(f"CRC-32 校验值: {crc32_value:#010x}")
输出如下:
CRC-32 校验值: 0x84d41ca3
MD5
MD5 是一种广泛使用的哈希函数,旨在生成一个128位(16字节)的哈希值,通常以32位十六进制数表示。它最初由 Ronald Rivest 在 1991 年设计,用于数据完整性校验,例如文件校验、数字签名等应用。
特征:固定返回长度为 32 位的字符串
Hex 数据
To Hexdump 可以看到数据在内存中的分布就是这样
import hashlib
# 数据
data = "Hello, MD5!"
# 计算 MD5
md5_hash = hashlib.md5(data.encode()).hexdigest()
print(f"MD5 哈希值: {md5_hash}")
输出如下:
MD5 哈希值: 383e139e64e5f46de9d03ba3695da2d8
SHA1
SHA-1 是由美国国家安全局(NSA)设计的一种哈希函数,它生成一个160位的哈希值(通常表示为 40 位的十六进制数)。SHA-1 最初是作为 SHA 系列的一部分,在 数据完整性校验、数字签名等领域被广泛使用。
特征:
固定返回长度为 40 位的字符串
只有字母和数字,没有特殊符号
import hashlib
# 数据
data = "Hello, SHA-1!"
# 计算 SHA-1
sha1_hash = hashlib.sha1(data.encode()).hexdigest()
print(f"SHA-1 哈希值: {sha1_hash}")
输出如下:
SHA-1 哈希值: f322e078fef4f49da1618d3793d3272a91f0488c
SHA256
SHA-256 是 SHA-2(Secure Hash Algorithm 2)系列中的一种哈希函数,它生成一个 256位的哈希值(通常表示为 64 位的十六进制数)。SHA-256 是现代加密和数据完整性校验中广泛使用的算法,具有较高的安全性。
特征:
固定返回长度为 64 位的字符串
只有字母和数字,没有特殊符号
import hashlib
# 数据
data = "Hello, SHA-256!"
# 计算 SHA-256
sha256_hash = hashlib.sha256(data.encode()).hexdigest()
print(f"SHA-256 哈希值: {sha256_hash}")
输出如下:
SHA-256 哈希值: d0e8b8f11c98f369016eb2ed3c541e1f01382f9d5b3104c9ffd06b6175a46271
HMAC
HMAC(基于哈希的消息认证码)使用一个密钥(Key)和一个哈希函数(Hash Function),将输入消息进行加密计算,生成一个固定长度的认证码(MAC)。它结合了哈希函数和密钥,提供了一种 安全的哈希过程,防止消息在传输过程中被篡改或伪造。
比如哈希函数是 MD2,密钥可能有也可能没有
当哈希函数是 MD5 ,密钥是 cyrus
所以返回字符串长度取决于具体的哈希函数
import hmac
import hashlib
# 密钥和数据
key = b"secret_key"
message = b"Hello, HMAC!"
# 计算 HMAC-SHA256
hmac_result = hmac.new(key, message, hashlib.sha256).hexdigest()
print(f"HMAC 哈希值: {hmac_result}")
输出如下:
HMAC 哈希值: e27642cd349f85fa9b8ed8309230cf19c24d4780db1f5d4b3012ad994930f072
Adler-32
Adler-32 是一个 32位(4字节) 的哈希算法,它通过计算数据的部分和和累积值来生成一个 32 位的校验和。
它由 Mark Adler 于 1995 年提出,主要用于检测数据完整性。虽然它不如 CRC-32 或 SHA-256 那样强大,但由于其计算速度快,广泛用于 压缩格式(如 zlib)中。
特征和 CRC-32 差不多
import zlib
# 数据
data = b"Hello, Adler-32!"
# 计算 Adler-32 校验和
adler32_hash = zlib.adler32(data) # 保证输出为 32 位
print(f"Adler-32 校验和: {adler32_hash:#010x}")
输出如下:
Adler-32 校验和: 0x2cfe04dc
对称算法
对称算法是一种加密算法,使用相同的密钥进行加密和解密。这种方式的优点是加密和解密速度非常快,但问题在于密钥的传输和管理上,因为如果密钥被泄露,加密信息也会暴露。
XOR
最简单的对称加密:异或(相同为 0,不同为 1)。
def xor_encrypt_decrypt(data, key):
return bytes([b ^ key for b in data])
# 原始数据
plaintext = b"Hello"
# 密钥(单字节)
key = 42 # 任何数都可以作为密钥
# 加密
ciphertext = xor_encrypt_decrypt(plaintext, key)
print("密文:", ciphertext)
# 解密
decrypted = xor_encrypt_decrypt(ciphertext, key)
print("解密:", decrypted.decode())
输出如下:
密文: b'bOFFE'
解密: Hello
RC4
RC4(Rivest Cipher 4)是一种流加密算法,由 Ronald Rivest 于 1987 年 设计,最初是 RSA Security 的专有算法,后被泄露并公开。
RC4 运算速度快、实现简单,曾被广泛用于SSL/TLS、WEP、VPN、无线网络安全等,但由于安全漏洞,目前已被淘汰。
使用 RC4 算法和密钥 cyrus 计算加密数据
把加密后的数据使用密码 cyrus 和 RC4 算法再计算一次得到未加密的数据
RC4 依赖 XOR 进行加解密,因此加密和解密过程完全相同。
def rc4(data: bytes, key: bytes) -> bytes:
S = list(range(256)) # S 盒初始化
j = 0
out = bytearray()
# KSA(密钥调度算法)
for i in range(256):
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i] # 交换
# PRGA(伪随机生成)
i = j = 0
for byte in data:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i] # 交换
k = S[(S[i] + S[j]) % 256]
out.append(byte ^ k) # XOR 计算密文
return bytes(out)
# 测试 RC4 加密和解密
key = b"SecretKey"
plaintext = b"Hello, RC4!"
ciphertext = rc4(plaintext, key)
print("密文:", ciphertext)
decrypted = rc4(ciphertext, key) # 再次 RC4 处理即可解密
print("解密:", decrypted.decode())
输出如下:
密文: b"\\\xddP+\xb0^>\xf0\xa7'\x1c"
解密: Hello, RC4!
DES
DES 是一种 分组加密算法,采用 64 位数据块,并使用 56 位密钥(64 位密钥中 8 位是奇偶校验位)。
1. Key(密钥)
密钥长度:64 位(8 字节)
但其中 56 位 是有效密钥位,剩余的 8 位 用作奇偶校验。
2. IV(初始化向量)
初始化向量(IV)是用于某些加密模式(如 CBC、CFB、OFB)的 随机数,用于增加加密的随机性,防止相同明文产生相同密文。
IV 必须与数据块大小相同,即 8 字节(64 位)。
ECB 模式不需要 IV,但 CBC、CFB、OFB 模式需要 IV。
3. Mode(加密模式)
Mode 中 CBC 和 ECB 是比较常见的
CBC 每个块会依赖前一个块,ECB 每个块单独加密
Key 和 IV 必须为 8 个字节
Python 的 pycryptodome 库提供了 DES 实现:
pip install pycryptodome
ECB(电子密码本模式,Electronic Codebook)
特点:
每个 8 字节的明文独立加密,相同的明文块总是会产生相同的密文。
不需要 IV。
适用场景:仅适用于单独的数据块,不适用于长数据。
Python 代码示例
from Crypto.Cipher import DES
from Crypto.Util.Padding import pad, unpad
key = b'8ByteKey' # 8 字节密钥(56 位有效)
data = b"Hello, DES!" # 待加密数据
# 创建 DES 加密器(ECB 模式)
cipher = DES.new(key, DES.MODE_ECB)
# 加密
ciphertext = cipher.encrypt(pad(data, DES.block_size))
print("密文:", ciphertext.hex())
# 解密
plaintext = unpad(cipher.decrypt(ciphertext), DES.block_size)
print("解密:", plaintext.decode())
输出如下:
密文: 583d732b24aa664ec46b788d096a2da5
解密: Hello, DES!
CBC(密码分组链接模式,Cipher Block Chaining)
特点
每个明文块 在加密前与前一个密文块 XOR,这样相同的明文块不会产生相同的密文。
需要 IV(初始化向量)。
适用场景:适用于大多数加密需求,如 文件、网络通信等。
Python 代码示例
from Crypto.Cipher import DES
from Crypto.Util.Padding import pad, unpad
# 设置密钥(8 字节)和 IV(8 字节)
key = b'8ByteKey'
iv = b'12345678'
# 明文
data = b"Hello, DES!"
# 创建加密对象
cipher_encrypt = DES.new(key, DES.MODE_CBC, iv)
# 加密
ciphertext = cipher_encrypt.encrypt(pad(data, DES.block_size))
print("CBC 密文:", ciphertext.hex())
# 创建解密对象( PyCryptodome 不允许在同一个 Cipher 对象上既加密又解密。)
cipher_decrypt = DES.new(key, DES.MODE_CBC, iv)
# 解密
plaintext = unpad(cipher_decrypt.decrypt(ciphertext), DES.block_size)
print("CBC 解密:", plaintext.decode())
输出如下:
CBC 密文: 4c5d97b0607bd66e3c35a54a92f058ea
CBC 解密: Hello, DES!
CFB(密码反馈模式,Cipher Feedback)
特点:
类似于 CBC,但它以流模式工作,加密块可以小于 8 字节。
需要 IV。
适用场景:适用于 需要流加密的应用。
Python 代码示例
from Crypto.Cipher import DES
# 设置密钥(8 字节)和 IV(8 字节)
key = b'8ByteKey'
iv = b'12345678'
# 明文
data = b"Hello, DES!"
# 创建加密对象
cipher_encrypt = DES.new(key, DES.MODE_CFB, iv)
# 加密
ciphertext = cipher_encrypt.encrypt(data)
print("CFB 密文:", ciphertext.hex())
# 创建解密对象( PyCryptodome 不允许在同一个 Cipher 对象上既加密又解密。)
cipher_decrypt = DES.new(key, DES.MODE_CFB, iv)
# 解密
plaintext = cipher_decrypt.decrypt(ciphertext)
print("CFB 解密:", plaintext.decode())
OFB(输出反馈模式,Output Feedback)
特点:
以流模式工作,不会传播加密错误。
需要 IV。
适用于实时加密(如语音、视频加密)。
Python 代码示例
from Crypto.Cipher import DES
# 设置密钥(8 字节)和 IV(8 字节)
key = b'8ByteKey'
iv = b'12345678'
# 明文
data = b"Hello, DES!"
# 创建加密对象
cipher_encrypt = DES.new(key, DES.MODE_OFB, iv)
# 加密
ciphertext = cipher_encrypt.encrypt(data)
print("OFB 密文:", ciphertext.hex())
# 创建解密对象( PyCryptodome 不允许在同一个 Cipher 对象上既加密又解密。)
cipher_decrypt = DES.new(key, DES.MODE_OFB, iv)
# 解密
plaintext = cipher_decrypt.decrypt(ciphertext)
print("OFB 解密:", plaintext.decode())
输出如下:
OFB 密文: ca5578137e3d02503a6f02
OFB 解密: Hello, DES!
CTR(计数器模式,Counter Mode)
特点:
将 IV 作为 计数器,不断递增,生成独立的加密流。
适用于 并行计算,效率高。
适用场景:适用于 高性能并行加密。
Python 代码示例
from Crypto.Cipher import DES
from Crypto.Util import Counter
# 设置密钥(8 字节)
key = b'8ByteKey'
# 计数器(CTR 模式不需要 IV,而是用 Counter)
ctr = Counter.new(64)
# 创建加密对象
cipher_encrypt = DES.new(key, DES.MODE_CTR, counter=ctr)
# 明文
data = b"Hello, DES!"
# 加密
ciphertext = cipher_encrypt.encrypt(data)
print("CTR 密文:", ciphertext.hex())
# **重新创建 Counter,确保加密和解密使用相同的计数器初始值**
ctr = Counter.new(64) # 重新创建计数器,保证与加密时一致
# 创建解密对象
cipher_decrypt = DES.new(key, DES.MODE_CTR, counter=ctr)
# 解密
plaintext = cipher_decrypt.decrypt(ciphertext)
print("CTR 解密:", plaintext.decode())
输出如下:
CTR 密文: fe79bfdfe81bf8306254a8
CTR 解密: Hello, DES!
DES 各模式对比
模式 | 是否需要 IV | 加密方式 | 特点 | 适用场景 |
---|---|---|---|---|
ECB | 不需要 | 每个块独立加密 | 易被模式分析,不安全 | 仅适用于少量数据 |
CBC | 需要 IV | XOR 前一块密文 | 更安全,适用于文件加密 | 文件、数据库 |
CFB | 需要 IV | 流式加密 | 适用于流数据 | 网络通信 |
OFB | 需要 IV | 流式加密(错误不会传播) | 适用于实时加密 | 语音、视频 |
CTR | 需要计数器 | 伪随机数流 | 可并行计算,速度快 | 高性能并行加密 |
3DES(Triple DES)
3DES(Triple Data Encryption Standard,三重数据加密标准) 是 DES(数据加密标准) 的加强版,通过对数据进行 三次加密 提高安全性
Key 16 或 24 字节,IV 8 个字节
from Crypto.Cipher import DES3
from Crypto.Util.Padding import pad, unpad
# 3DES 密钥(必须是 16 或 24 字节)
key = b'Sixteen byte key' # 16 字节密钥
iv = b'12345678' # 8 字节 IV
# 创建 3DES CBC 加密对象
cipher_encrypt = DES3.new(key, DES3.MODE_CBC, iv)
# 明文
data = b"Hello, 3DES!"
# 加密
ciphertext = cipher_encrypt.encrypt(pad(data, DES3.block_size))
print("3DES 密文:", ciphertext.hex())
# 解密(重新创建对象)
cipher_decrypt = DES3.new(key, DES3.MODE_CBC, iv)
plaintext = unpad(cipher_decrypt.decrypt(ciphertext), DES3.block_size)
print("3DES 解密:", plaintext.decode())
输出如下:
3DES 密文: c83780a4aa2a69e83694b085690f6d23
3DES 解密: Hello, 3DES!
AES
AES(Advanced Encryption Standard,高级加密标准) 是一种 对称加密算法,用于加密和解密数据。AES 由 美国国家标准与技术研究院(NIST) 在 2001 年正式发布,取代了 DES 和 3DES,目前被广泛应用于 网络安全、金融、通信 等领域。
支持 128(16字节)、192(24字节)、256(32字节) 位密钥。
特性 | 描述 |
---|---|
加密方式 | 对称加密(加密和解密使用相同的密钥) |
分组长度 | 128 位(16 字节) |
密钥长度 | 128 位、192 位、256 位(分别对应 10、12、14 轮加密) |
安全性 | 目前无已知有效攻击,比 3DES 更安全 |
运算模式 | 支持 ECB、CBC、CFB、OFB、CTR 等模式 |
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
# 16 字节(128 位)密钥
key = b'Sixteen byte key'
iv = b'1234567890123456' # 16 字节 IV(仅 CBC 需要)
# 创建 AES CBC 加密对象
cipher_encrypt = AES.new(key, AES.MODE_CBC, iv)
# 明文(需填充到 16 字节倍数)
data = b"Hello, AES!"
ciphertext = cipher_encrypt.encrypt(pad(data, AES.block_size))
print("AES CBC 密文:", ciphertext.hex())
# 解密
cipher_decrypt = AES.new(key, AES.MODE_CBC, iv)
plaintext = unpad(cipher_decrypt.decrypt(ciphertext), AES.block_size)
print("AES CBC 解密:", plaintext.decode())
输出如下:
AES CBC 密文: 03f4e378d5f8be3ecf2294490dd5bfff
AES CBC 解密: Hello, AES!
国密 SM4
GmSSL,支持国密算法(SM2/SM3/SM4)的开源 SSL/TLS 加密库 :http://gmssl.org/docs/sm4.html
SMS4的密钥长度和分组长度均为128比特,其设计安全性等同于AES-128,但是近年来的一些密码分析表明SMS4的安全性略弱于AES-128。
在国内一些 zf 和银行 app 用的比较多。
特性 | 描述 |
---|---|
算法类型 | 对称加密(加密解密使用相同密钥) |
分组大小 | 128 位(16 字节) |
密钥长度 | 128 位(16 字节) |
加密轮数 | 32 轮 |
安全性 | 比 DES/3DES 更安全,可替代 AES-128 |
运算模式 | 支持 ECB、CBC、CFB、OFB、CTR |
pip install gmssl
from gmssl import sm4
from Crypto.Util.Padding import pad, unpad
# 16 字节密钥(128 位)
key = b'1234567890abcdef'
iv = b'1234567890abcdef' # 仅 CBC 需要
# 创建 SM4 CBC 加密对象
cipher_encrypt = sm4.CryptSM4()
cipher_encrypt.set_key(key, sm4.SM4_ENCRYPT)
# 明文
data = b"Hello, SM4!"
ciphertext = cipher_encrypt.crypt_cbc(iv, pad(data, 16))
print("SM4 CBC 密文:", ciphertext.hex())
# 解密
cipher_decrypt = sm4.CryptSM4()
cipher_decrypt.set_key(key, sm4.SM4_DECRYPT)
plaintext = unpad(cipher_decrypt.crypt_cbc(iv, ciphertext), 16)
print("SM4 CBC 解密:", plaintext.decode())
输出如下:
SM4 CBC 密文: 67cb1b462378a51d8bd04fcd9e2094157bb51f24808a845f07ed14f5ec6f0575
SM4 CBC 解密: Hello, SM4!
非对称算法
非对称算法(Asymmetric Algorithm) 是一种使用不同的密钥进行加密和解密的加密算法,包括公钥(Public Key)和私钥(Private Key)。
公钥加密,私钥解密(用于安全通信)
私钥加密,公钥验证(用于数字签名)
非对称算法的特点
密钥对(公钥 + 私钥):无需共享私钥,避免密钥分发问题。
支持数字签名:可验证数据来源和完整性,防止篡改。
比对称加密慢:计算复杂,通常用于密钥交换和身份认证,大数据加密仍用对称算法(如 AES)。
RSA
RSA(Rivest-Shamir-Adleman) 是一种 非对称加密算法,1977 年由 Ron Rivest、Adi Shamir 和 Leonard Adleman 提出。它基于 大整数因子分解问题 的数学难题,广泛用于 数据加密、数字签名、密钥交换 等领域。
详细介绍:RSA加密算法
生成私钥和公钥
RSA Key Generator:https://emn178.github.io/online-tools/rsa/key-generator/
常见密钥长度
密钥长度 | 安全性 | 应用场景 |
---|---|---|
512 位 | 极不安全 | 早已被破解,不推荐使用 |
1024 位 | 不安全 | 2003 年 NIST 就不推荐 |
2048 位 | 目前安全 | 最低推荐,适用于一般应用 |
3072 位 | 更安全 | 适用于高安全需求,如数字签名 |
4096 位 | 极高安全性 | 适用于 长期数据保护 |
8192+ 位 | 超高安全性 | 计算开销巨大,极少使用 |
使用公钥加密数据
RSA Encrypt:https://emn178.github.io/online-tools/rsa/encrypt/
使用私钥解密数据
RSA Decrypt:https://emn178.github.io/online-tools/rsa/decrypt/
生成 RSA 密钥
from Crypto.PublicKey import RSA
# 生成 2048 位密钥对
key = RSA.generate(2048)
# 导出公钥 & 私钥
private_key = key.export_key()
public_key = key.publickey().export_key()
# 保存到文件
with open("rsa_private.pem", "wb") as f:
f.write(private_key)
with open("rsa_public.pem", "wb") as f:
f.write(public_key)
print("RSA 密钥对已生成")
RSA 加密
from Crypto.Cipher import PKCS1_OAEP
from Crypto.PublicKey import RSA
import base64
# 加载公钥
with open("rsa_public.pem", "rb") as f:
public_key = RSA.import_key(f.read())
# 创建加密器
cipher = PKCS1_OAEP.new(public_key)
# 加密
plaintext = "Hello, RSA!"
ciphertext = cipher.encrypt(plaintext.encode())
# 转 Base64 输出
print("密文:", base64.b64encode(ciphertext).decode())
输出如下:
密文: MvznGTUHQ9SJ2IqXZ6jGQL0Mu2oWDa0kSWJRB2+8aSvzTl9MWc7qaTk816y1po4DsA3o0mkr6k1jon/qglNevPU21FqE+P2EFA3AT/1pciztZrWdiy8lbQ0RkqQOb9lZ4TcuvAR28Be9KtDgJJSc3Gfi2wCd1lvE+hfyQnHYLPDm2Vl8eulCIPz/awCe7T+aFeRXAUAZNbIk2y7jOP8CSn/m8jLgwOQ7rr73SKyKzgCD5qxzBJqNwNe7L3uLXSCMqB+2hheJram7cVdPDVXljQ86spQxrcyfc4bKgKEcIxs0uR3XjamLnHhfuTgEDcqLKCgwdwPahJq13SMlkQrjuw==
RSA 与 AES 结合使用
RSA 与 AES 结合使用的方法
用 AES 加密数据(对称加密,速度快)。
用 RSA 加密 AES 密钥(非对称加密,确保密钥安全)。
发送加密的 AES 密钥 + 加密数据,接收方用 RSA 解密 AES 密钥,再用 AES 解密数据。
结合两者优点,既安全又高效,是 TLS/HTTPS、文件加密、数据传输 的常用方案。
发送方:AES 加密数据 & RSA 加密 AES 密钥
from Crypto.Cipher import AES, PKCS1_OAEP
from Crypto.PublicKey import RSA
from Crypto.Random import get_random_bytes
import base64
# 读取 RSA 公钥
with open("rsa_public.pem", "rb") as f:
public_key = RSA.import_key(f.read())
# 生成 AES 密钥(16/24/32 字节,对应 AES-128/192/256)
aes_key = get_random_bytes(16) # 这里使用 AES-128
# 创建 AES 加密器(CBC 模式)
iv = get_random_bytes(16) # IV 向量
cipher_aes = AES.new(aes_key, AES.MODE_CBC, iv)
# 加密数据
plaintext = b"Hello, RSA + AES!"
padded_plaintext = plaintext + b' ' * (16 - len(plaintext) % 16) # 填充
ciphertext = cipher_aes.encrypt(padded_plaintext)
# 用 RSA 公钥加密 AES 密钥
cipher_rsa = PKCS1_OAEP.new(public_key)
encrypted_aes_key = cipher_rsa.encrypt(aes_key)
# 发送以下数据:
# 1. `encrypted_aes_key`(RSA 加密后的 AES 密钥)
# 2. `iv`(AES IV)
# 3. `ciphertext`(AES 加密后的数据)
print("RSA 加密后的 AES 密钥:", base64.b64encode(encrypted_aes_key).decode())
print("AES IV:", base64.b64encode(iv).decode())
print("AES 加密后的数据:", base64.b64encode(ciphertext).decode())
输出如下:
RSA 加密后的 AES 密钥: HX9pSwziu9Sz0bqBMSVroFPDqQCDoh6o1q/VH9UmfcRU2eMjlgyKJy2WUiXe2YqnRSILE8kJ9SVa8sZgdtWoyVyvLK49AUGjlm7LDEsYPX7uXo2y9yn9kUoQc9WXdsiOBcshG0hsXwNssOtRL7jWfH5lYDcKrP9i1wYcvQiGw61tGM4zR9A0ao0Qi5ajGmyMfLAGpodFuUvSA1ocXoWZG31zG0YgY5tjPNQXf1EbXjVk0aStwyHjVUu6svN8li9AHzOWF42HjCPCyCAHvbicFTFhxHdK3zORqhcAv7avybDugwxAMTskSfhHoHZ2k+Lac08se9fFMs5wd6JbtgBpCQ==
AES IV: fEYV2sUEJxoEfyabNxJl8g==
AES 加密后的数据: 8zUQ/tExI1+vk/BAOmn67hV4tTNLVnurhgN/RkG9cNU=
接收方:RSA 解密 AES 密钥 & AES 解密数据
from Crypto.Cipher import AES, PKCS1_OAEP
from Crypto.PublicKey import RSA
import base64
# 读取 RSA 私钥
with open("rsa_private.pem", "rb") as f:
private_key = RSA.import_key(f.read())
# 接收的加密数据
encrypted_aes_key = base64.b64decode("HX9pSwziu9Sz0bqBMSVroFPDqQCDoh6o1q/VH9UmfcRU2eMjlgyKJy2WUiXe2YqnRSILE8kJ9SVa8sZgdtWoyVyvLK49AUGjlm7LDEsYPX7uXo2y9yn9kUoQc9WXdsiOBcshG0hsXwNssOtRL7jWfH5lYDcKrP9i1wYcvQiGw61tGM4zR9A0ao0Qi5ajGmyMfLAGpodFuUvSA1ocXoWZG31zG0YgY5tjPNQXf1EbXjVk0aStwyHjVUu6svN8li9AHzOWF42HjCPCyCAHvbicFTFhxHdK3zORqhcAv7avybDugwxAMTskSfhHoHZ2k+Lac08se9fFMs5wd6JbtgBpCQ==")
iv = base64.b64decode("fEYV2sUEJxoEfyabNxJl8g==")
ciphertext = base64.b64decode("8zUQ/tExI1+vk/BAOmn67hV4tTNLVnurhgN/RkG9cNU=")
# 用 RSA 私钥解密 AES 密钥
cipher_rsa = PKCS1_OAEP.new(private_key)
aes_key = cipher_rsa.decrypt(encrypted_aes_key)
# 用 AES 密钥解密数据
cipher_aes = AES.new(aes_key, AES.MODE_CBC, iv)
plaintext = cipher_aes.decrypt(ciphertext)
print("解密后的数据:", plaintext.decode())
输出如下:
解密后的数据: Hello, RSA + AES!
ECC
ECC(Elliptic Curve Cryptography,椭圆曲线密码学)是一种 非对称加密算法,基于 椭圆曲线离散对数问题(ECDLP),提供与 RSA 相同安全级别,但密钥更短、计算更快、资源占用更少。
ecc algorithm online:https://8gwifi.org/ecfunctions.jsp
1. 椭圆曲线参数(Curve)
ECC 依赖于特定的 椭圆曲线(Elliptic Curves),不同曲线有不同的安全性和性能。
曲线名称 | 密钥长度(bit) | 等效 RSA | 说明 |
---|---|---|---|
secp160r1 | 160-bit | RSA-1024 | 早期曲线,已不推荐 |
secp192r1 (NIST P-192) | 192-bit | RSA-1536 | 安全性不足 |
secp256r1 (NIST P-256) | 256-bit | RSA-3072 | 最低推荐曲线 |
secp384r1 (NIST P-384) | 384-bit | RSA-7680 | 更高安全性 |
secp521r1 (NIST P-521) | 521-bit | RSA-15360 | 超高安全级别 |
Curve25519 | 256-bit | RSA-3072 | 高效安全,现代推荐 |
Curve448 | 448-bit | RSA-7680 | 高安全性,适合长期使用 |
NIST P-256 和 Curve25519 是当前最常用的 ECC 曲线。 |
2. 公私钥(Private Key & Public Key)
私钥(Private Key):随机生成的 256-bit (P-256) 或 384-bit (P-384) 大整数,用于解密或签名。
公钥(Public Key):私钥乘以椭圆曲线基点 G 生成,即 Public Key = Private Key × G,用于加密或验证签名。
pip install cryptography
生成 ECC 密钥对,并保存到文件
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import serialization
# 生成 ECC P-256(secp256r1)私钥
private_key = ec.generate_private_key(ec.SECP256R1())
# 导出私钥
pem_private = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
)
# 导出公钥
public_key = private_key.public_key().public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
print("ECC 私钥:", pem_private.decode())
print("ECC 公钥:", public_key.decode())
3. ECDH(椭圆曲线 Diffie-Hellman)共享密钥
ECC 本身不能直接加密数据,而是使用 ECDH(Elliptic Curve Diffie-Hellman) 进行密钥交换:
发送方和接收方分别生成自己的密钥对。
通过 exchange() 方法,使用自己的 私钥 和对方的 公钥 计算 共享密钥:
shared_secret = private_key.exchange(ec.ECDH(), public_key)
- 共享密钥不能直接用作 AES 密钥,需要通过 HKDF 进行密钥派生。
4. HKDF(密钥派生函数)
HKDF(HMAC-based Key Derivation Function) 用于从 ECDH 共享密钥 生成对称密钥(如 AES 密钥):
输入:ECDH 共享密钥
输出:固定长度的 AES 密钥(128-bit / 256-bit)
示例代码:
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from cryptography.hazmat.primitives import hashes
derived_key = HKDF(
algorithm=hashes.SHA256(),
length=32, # 生成 32 字节的 AES-256 密钥
salt=None,
info=b"ECC Encryption",
).derive(shared_secret)
5. 对称加密(AES-GCM)
ECC 生成的密钥用于 AES-GCM 加密,需要以下参数:
IV(初始化向量):随机 12 字节,防止重放攻击
Tag(认证标签):AES-GCM 生成的 16 字节数据,用于数据完整性验证
示例代码:
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
import os
iv = os.urandom(12) # 生成随机 IV
cipher = Cipher(algorithms.AES(derived_key), modes.GCM(iv))
encryptor = cipher.encryptor()
ciphertext = encryptor.update(b"Hello, ECC!") + encryptor.finalize()
相关参数说明
参数名 | 作用 |
---|---|
Curve | 椭圆曲线类型(如 secp256r1, Curve25519) |
Private Key | 私钥,大整数(用于解密 / 签名) |
Public Key | 公钥,由 Private Key × G 计算(用于加密 / 验证) |
ECDH Secret | 共享密钥,由 私钥 × 对方公钥计算 |
HKDF Key | 通过 HKDF 从共享密钥派生 AES 密钥 |
IV(Nonce) | AES-GCM 加密时使用的随机值(防重放) |
Tag | AES-GCM 认证标签(防篡改) |
结论:ECC 主要用于安全的密钥交换,而不是直接加密数据! |
完整示例代码
ECC 本身不能直接加密大数据,通常与 ECIES(椭圆曲线集成加密方案) 结合使用。
ECIES 结合了 非对称 + 对称加密:
使用 ECC 计算共享密钥(ECDH)
用共享密钥派生 AES 密钥(HKDF)
使用 AES 进行数据加密
发送加密数据 + 发送者的临时公钥(接收方可计算相同共享密钥)
下面使用 cryptography 库的 ECIES + AES-GCM 进行加密解密。
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
import os
# 加密数据
def ecc_encrypt(public_key, plaintext):
# 生成临时密钥对
ephemeral_key = ec.generate_private_key(ec.SECP256R1())
shared_secret = ephemeral_key.exchange(ec.ECDH(), public_key)
# 通过 HKDF 生成对称密钥
derived_key = HKDF(
algorithm=hashes.SHA256(),
length=32, # AES-256 密钥
salt=None,
info=b"ECC Encryption",
).derive(shared_secret)
# 生成随机 IV
iv = os.urandom(12)
# 使用 AES-GCM 进行加密
cipher = Cipher(algorithms.AES(derived_key), modes.GCM(iv))
encryptor = cipher.encryptor()
ciphertext = encryptor.update(plaintext) + encryptor.finalize()
return ephemeral_key.public_key(), iv, encryptor.tag, ciphertext
# 解密数据
def ecc_decrypt(private_key, ephemeral_public_key, iv, tag, ciphertext):
shared_secret = private_key.exchange(ec.ECDH(), ephemeral_public_key)
# 通过 HKDF 生成对称密钥
derived_key = HKDF(
algorithm=hashes.SHA256(),
length=32, # AES-256 密钥
salt=None,
info=b"ECC Encryption",
).derive(shared_secret)
# 使用 AES-GCM 进行解密
cipher = Cipher(algorithms.AES(derived_key), modes.GCM(iv, tag))
decryptor = cipher.decryptor()
return decryptor.update(ciphertext) + decryptor.finalize()
# 读取 ECC 公钥和私钥
with open("ecc_private_key.pem", "rb") as f:
private_key = serialization.load_pem_private_key(f.read(), password=None)
with open("ecc_public_key.pem", "rb") as f:
public_key = serialization.load_pem_public_key(f.read())
# 加密
plaintext = b"Hello, ECC Encryption!"
ephemeral_public_key, iv, tag, ciphertext = ecc_encrypt(public_key, plaintext)
print(f"✅ 加密成功: {ciphertext.hex()}")
# 解密
decrypted_text = ecc_decrypt(private_key, ephemeral_public_key, iv, tag, ciphertext)
print(f"✅ 解密成功: {decrypted_text.decode()}")
输出如下:
✅ 加密成功: b1ab21c4ce2485e57c4313cd1b7107d6907eaf0500d0
✅ 解密成功: Hello, ECC Encryption!
RSA vs. ECC
对比项 | RSA 2048 | ECC 256 |
---|---|---|
安全性 | 传统但安全 | 同样安全但更高效 |
密钥长度 | 2048 位 | 256 位 |
计算速度 | 慢 | 快(适用于移动设备) |
应用场景 | 电子签名、SSL | 区块链、移动安全 |
现代密码学趋势:RSA 2048 仍然可用,但计算较慢,ECC 256 位 ≈ RSA 3072 位,性能更优
压缩算法
压缩算法是一种减少数据大小的方法,通过去除冗余信息或高效编码,以降低存储和传输的成本。压缩算法广泛用于文件存储、数据传输、多媒体处理等领域。
Gzip
Gzip(GNU zip) 是一种无损压缩算法和文件格式,广泛用于文件压缩、Web 传输优化等场景。它基于 DEFLATE 算法(结合 LZ77 + Huffman 编码),可以高效地压缩文本和二进制数据。
可以看到输入数据长度有 876,经过 Gzip 压缩后只有 51。
Gzip 压缩数据前缀固定的是 1f 8b
import gzip
data = b"Hello, Gzip! " * 10 # 需要压缩的数据
# 压缩
compressed = gzip.compress(data)
print("Compressed:", compressed)
# 解压
decompressed = gzip.decompress(compressed)
print("Decompressed:", decompressed.decode())
输出如下:
Compressed: b'\x1f\x8b\x08\x00z\xb7\xc9g\x02\xff\xf3H\xcd\xc9\xc9\xd7Qp\xaf\xca,PT\xf0\x18\x08\x0e\x00\xbb\xac\x886\x82\x00\x00\x00'
Decompressed: Hello, Gzip! Hello, Gzip! Hello, Gzip! Hello, Gzip! Hello, Gzip! Hello, Gzip! Hello, Gzip! Hello, Gzip! Hello, Gzip! Hello, Gzip!
Zlib
Zlib 是一种无损数据压缩库,基于 DEFLATE 算法(LZ77 + Huffman 编码)。支持 流式处理,适用于网络传输(如 HTTP、WebSocket),Zlib 压缩数据可用于 Gzip(不同的是 Zlib 有头部信息)。
Zlib 压缩数据默认前缀是 78 9c,不过 Zlib 有 10 个不同的压缩等级,不同等级前缀是不一样的。
如果不指定 level,Zlib 默认使用 level=6,在压缩率和速度之间取得平衡。
何时选择不同的压缩级别?
level=1 适用于 网络传输、流式压缩(如 HTTP 传输)。
level=6 默认值,适用于 一般用途(如日志压缩)。
level=9 适用于 长期存储,如数据库备份、归档文件。
import binascii
import zlib
data = b"Hello, Zlib! " * 100
# 使用不同级别进行压缩
compressed_fast = zlib.compress(data, level=1) # 速度最快
compressed_default = zlib.compress(data) # 默认
compressed_best = zlib.compress(data, level=9) # 压缩率最高
# 打印前 10 个字节(文件头部分)
print("Level 1 头部:", binascii.hexlify(compressed_fast[:10]))
print("Level 默认 头部:", binascii.hexlify(compressed_default[:10]))
print("Level 9 头部:", binascii.hexlify(compressed_best[:10]))
print(f"原始大小: {len(data)} 字节")
print(f"快速压缩大小: {len(compressed_fast)} 字节")
print(f"最佳压缩大小: {len(compressed_best)} 字节")
输出如下:
Level 1 头部: b'7801f348cdc9c9d75188'
Level 默认 头部: b'789cf348cdc9c9d75188'
Level 9 头部: b'78daf348cdc9c9d75188'
原始大小: 1300 字节
快速压缩大小: 35 字节
最佳压缩大小: 32 字节
从输出可以看到,压缩等级不一样,header 也不一样。
Zip
ZIP 是一种无损压缩格式,用于打包多个文件并进行压缩。ZIP 并不是单一算法,而是支持多种压缩算法(如 Deflate、BZip2、LZMA 等),其中最常用的是 DEFLATE(LZ77 + Huffman 编码)。
前缀是 PK(50 4B)
ZIP 压缩文件
import zipfile
# 创建 ZIP 文件并添加文件
with zipfile.ZipFile("example.zip", "w", zipfile.ZIP_DEFLATED) as zipf:
zipf.write("1.txt") # 添加文件
zipf.write("2.txt") # 添加文件
ZIP 解压文件
import zipfile
# 解压 ZIP 文件
with zipfile.ZipFile("example.zip", "r") as zipf:
zipf.extractall("example") # 解压到文件夹
读取 ZIP 内文件
import zipfile
with zipfile.ZipFile("example.zip", "r") as zipf:
file_list = zipf.namelist() # 获取 ZIP 内文件列表
print("ZIP 内文件:", file_list)
# 读取某个文件的内容
with zipf.open("1.txt") as f:
print(f.read().decode()) # 读取并解码
使用不同算法进行 ZIP 压缩
import zipfile
# 创建 ZIP 文件,选择不同的压缩算法
def create_zip(compression_method, zip_filename="output.zip"):
with zipfile.ZipFile(zip_filename, "w", compression=compression_method) as zipf:
zipf.write("1.txt") # 压缩文件1
zipf.write("2.txt") # 压缩文件2
print(f"文件已压缩为 {zip_filename},压缩方式: {compression_method}")
# 使用不同压缩算法
create_zip(zipfile.ZIP_STORED, "stored.zip") # 无压缩
create_zip(zipfile.ZIP_DEFLATED, "deflated.zip") # 使用 Deflate(默认)
create_zip(zipfile.ZIP_BZIP2, "bzip2.zip") # 使用 BZip2
create_zip(zipfile.ZIP_LZMA, "lzma.zip") # 使用 LZMA(最高压缩率)
不同的压缩算法文件头都是 PK(50 4B)
Tar
Tar(Tape Archive) 是一种用于打包多个文件的归档格式,常用于Linux/Unix 系统。Tar 本身不压缩数据,但可以与 Gzip、Bzip2、LZMA 等压缩算法结合使用,形成 .tar.gz、.tar.bz2、.tar.xz 等格式。
Tar 归档文件由多个文件头(Header)+ 文件数据组成:
[文件头] + [文件内容] + [文件头] + [文件内容] + ...
文件头(Header):包含文件名、大小、权限、时间戳等信息。
文件数据(Content):文件的原始内容(未压缩)。
简单的打包算法,数据还是原始数据。
创建 .tar(仅打包,不压缩)
import tarfile
# 创建 tar 归档(不压缩)
with tarfile.open("archive.tar", "w") as tar:
tar.add("1.txt") # 添加文件
tar.add("2.txt") # 添加文件
tar.add("example") # 添加文件夹(包含其中所有文件)
创建 .tar.gz(使用 Gzip 压缩)
import tarfile
# 创建 tar.gz 归档
with tarfile.open("archive.tar.gz", "w:gz") as tar:
tar.add("1.txt") # 添加文件
tar.add("2.txt") # 添加文件
创建 .tar.bz2(使用 Bzip2 压缩,压缩率更高)
import tarfile
# 创建 tar.bz2 归档(Bzip2 压缩)
with tarfile.open("archive.tar.bz2", "w:bz2") as tar:
tar.add("1.txt")
tar.add("2.txt")
tar.add("example")
创建 .tar.xz(使用 LZMA/XZ 压缩,最高压缩率)
import tarfile
# 创建 tar.xz 归档(LZMA 压缩)
with tarfile.open("archive.tar.xz", "w:xz") as tar:
tar.add("1.txt")
tar.add("2.txt")
tar.add("example")
7z
7z 是 7-Zip 压缩工具所使用的压缩格式,具有高压缩率、多种压缩算法支持等特点,被广泛应用于大文件和批量文件的压缩。
前缀是 7z(37 7A)
安装 py7zr
pip install py7zr
使用 py7zr 进行 7z 压缩
import py7zr
# 创建 7z 压缩包
with py7zr.SevenZipFile('example.7z', 'w') as archive:
archive.write('1.txt') # 添加单个文件
archive.writeall('example') # 添加整个文件夹
解压 7z 文件
import py7zr
# 解压 7z 文件
with py7zr.SevenZipFile('example.7z', 'r') as archive:
archive.extractall(path='example')