Python 基于pycryptodome,实现对AES、DES、3DES、RSA、blowfish、RC4等常用加密算法的使用,文末附各种加密的源码示例

(中文名:加密圆顶)pycryptodome是一个基于c实现的Python库,它在2.x中支持2.7以上版本,或3.x中支持3.5以上版本的Python。

可以使用以下命令安装它:

pip install pycryptodome

该库支持以下特性

  • 认证加密模式 Authenticated encryption modes (GCM, CCM, EAX, SIV, OCB)
  • AES加密在英特尔上的加速 Accelerated AES on Intel platforms via AES-NI
  • 一种jit编译以提高运算速度 First class support for PyPy
  • 椭圆曲线加密 Elliptic curves cryptography (NIST curves P-192, P-224, P-256, P-384 and P-521)
  • 更好更紧凑的接口 Better and more compact API (nonce and iv attributes for ciphers, automatic generation of random nonces and IVs, simplified CTR cipher mode, and more)
  • 各种hash SHA-3 hash algorithms (FIPS 202) and derived functions (NIST SP-800 185):
    • SHAKE128 and SHA256 XOFs
    • cSHAKE128 and cSHAKE256 XOFs
    • KMAC128 and KMAC256
    • TupleHash128 and TupleHash256
  • 一个兄弟提出的算法 KangarooTwelve XOF (derived from Keccak)
  • SHA散列算法 Truncated hash algorithms SHA-512/224 and SHA-512/256 (FIPS 180-4)
  • 一种散列算法 BLAKE2b and BLAKE2s hash algorithms
  • 一种流式加密 Salsa20 and ChaCha20/XChaCha20 stream ciphers
  • Google所采用的一种新式加密算法 Poly1305 MAC
  • 也是Google新算法 ChaCha20-Poly1305 and XChaCha20-Poly1305 authenticated ciphers
  • 两种加密算法以及HKDF的推导函数 scrypt, bcrypt and HKDF derivation functions
  • DSA加密 Deterministic (EC)DSA
  • 密钥保护容器 Password-protected PKCS#8 key containers
  • 密钥分享方法 Shamir’s Secret Sharing scheme
  • 基于硬件的随机数 Random numbers get sourced directly from the OS (and not from a CSPRNG in userspace)
  • 简化的安装流程并且支持windows系统 Simplified install process, including better support for Windows
  • RSA和DSA的密钥生成器 Cleaner RSA and DSA key generation (largely based on FIPS 186-4)
  • 源码很漂亮 Major clean ups and simplification of the code base

更多文档可参考【官网文档】

概述

DES、3DES、AES都是对称加密算法,即一个密钥既用于加密也用于解密。而RSA是不对称加密,需要使用公钥和私钥分别进行加解密。

对称加密中通常需要三个参数,分别是密钥key,向量iv(一种初始的数值用于变更加密的走向以得到不同的加密结果)和密文content

不论是DES、3DES,或者还是AES的加密,常用的主要分为MODE_CBC、MODE_CFB、MODE_ECB、MODE_OFB这四种,其他的如EAX等这里不作演示。

四种分组加密模式简介

MODE_ECB ECB(Electronic Codebook)电码本

  • 是一种简单加密
  • 这种模式不需要传入iv
  • 但是可能会被明文攻击
  • 密钥需要传入8位的bytes

MODE_CBC (Cipher-block chaining)密码分组链接

  • 需要传入8位bytes的iv
  • 密钥需要传入8位的bytes
  • 它不容易被主动攻击
  • 安全性好于ECB
  • 而且就算密文有损坏也还能继续解密
  • 适合加密大数据
  • 广泛用于SSL、IPSec中。

MODE_CFB CFB(Cipher FeedBack) 密钥反馈

  • 需要传入8位bytes的iv
  • 密钥需要传入8位的bytes
  • 密文损坏了会出问题

MODE_OFB (Output Feedback)输出反馈模式

  • 需要传入8位bytes的iv
  • 密钥需要传入8位的bytes
  • 密文损坏了会出问题

对称加密

DES加密

from Crypto.Cipher import DES

def padding_to(raw: bytes, padding: int, max_length: int = None):
    '''
    部分加解密是需要补齐位数到指定padding的
    '''
    c = len(raw)/padding
    block: int = int(c)
    if block != c:
        block += 1
    result = raw.ljust(padding*block, b'\0')
    if max_length:
        result = result[0:max_length]
    return result

def test_des(key,iv,content):
  # MODE_CBC
  e = DES.new(padding_to(key,8,8), DES.MODE_CBC, padding_to(iv,8,8)).encrypt(padding_to(content,8))
  d = DES.new(padding_to(key,8,8), DES.MODE_CBC, padding_to(iv,8,8)).decrypt(e)
  print(f'e = {e}\nd = {d}\n\n')
  # MODE_CFB
  e = DES.new(padding_to(key,8,8), DES.MODE_CFB, padding_to(iv,8,8)).encrypt(padding_to(content,8))
  d = DES.new(padding_to(key,8,8), DES.MODE_CFB, padding_to(iv,8,8)).decrypt(e)
  print(f'e = {e}\nd = {d}\n\n')
  # MODE_ECB no need for iv
  e = DES.new(padding_to(key,8,8), DES.MODE_ECB).encrypt(padding_to(content,8))
  d = DES.new(padding_to(key,8,8), DES.MODE_ECB).decrypt(e)
  print(f'e = {e}\nd = {d}\n\n')
  # MODE_OFB
  e = DES.new(padding_to(key,8,8), DES.MODE_OFB, padding_to(iv,8,8)).encrypt(padding_to(content,8))
  d = DES.new(padding_to(key,8,8), DES.MODE_OFB, padding_to(iv,8,8)).decrypt(e)
  print(f'e = {e}\nd = {d}\n\n')
config = {
        "key": "SGTSerfend2022",
        "iv": "1Ssecret1Ssecret1Ssecret"
    }
content = ('0123456789abcdefAAAAAAAAAA'*5).encode()
iv = str(config['iv']).encode()
key = str(config['key']).encode()
test_des(key,iv,content)

DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,1977年被美国联邦政府的国家标准局确定为联邦资料处理标准(FIPS),并授权在非密级政府通信中使用,随后该算法在国际上广泛流传开来。需要注意的是,在某些文献中,作为算法的DES称为数据加密算法(Data Encryption Algorithm,DEA),已与作为标准的DES区分开来。

DES算法的入口参数有三个:Key、Data、Mode。其中Key为7个字节共56位,是DES算法的工作密钥;Data为8个字节64位,是要被加密或被解密的数据;Mode为DES的工作方式,有两种:加密或解密。

密钥需要是56位(实际使用64位),iv需要是64位

3DES加密

from Crypto.Cipher import DES3

def padding_to(raw: bytes, padding: int, max_length: int = None):
    '''
    部分加解密是需要补齐位数到指定padding的
    '''
    c = len(raw)/padding
    block: int = int(c)
    if block != c:
        block += 1
    result = raw.ljust(padding*block, b'\0')
    if max_length:
        result = result[0:max_length]
    return result

def test_3des(key,iv,content):
  # MODE_CBC
  e = DES3.new(padding_to(key,24,24), DES3.MODE_CBC, padding_to(iv,8,8)).encrypt(padding_to(content,8))
  d = DES3.new(padding_to(key,24,24), DES3.MODE_CBC, padding_to(iv,8,8)).decrypt(e)
  print(f'e = {e}\nd = {d}\n\n')
  # MODE_CFB
  e = DES3.new(padding_to(key,24,24), DES3.MODE_CFB, padding_to(iv,8,8)).encrypt(padding_to(content,8))
  d = DES3.new(padding_to(key,24,24), DES3.MODE_CFB, padding_to(iv,8,8)).decrypt(e)
  print(f'e = {e}\nd = {d}\n\n')
  # MODE_ECB no need for iv
  e = DES3.new(padding_to(key,24,24), DES3.MODE_ECB).encrypt(padding_to(content,8))
  d = DES3.new(padding_to(key,24,24), DES3.MODE_ECB).decrypt(e)
  print(f'e = {e}\nd = {d}\n\n')
  # MODE_OFB
  e = DES3.new(padding_to(key,24,24), DES3.MODE_OFB, padding_to(iv,8,8)).encrypt(padding_to(content,8))
  d = DES3.new(padding_to(key,24,24), DES3.MODE_OFB, padding_to(iv,8,8)).decrypt(e)
  print(f'e = {e}\nd = {d}\n\n')
config = {
        "key": "SGTSerfend2022",
        "iv": "1Ssecret1Ssecret1Ssecret"
    }
content = ('0123456789abcdefAAAAAAAAAA'*5).encode()
iv = str(config['iv']).encode()
key = str(config['key']).encode()
test_3des(key,iv,content)

3DES(或称为Triple DES)是三重数据加密算法(TDEA,Triple Data Encryption Algorithm)块密码的通称。它相当于是对每个数据块应用三次DES加密算法

由于计算机运算能力的增强,原版DES密码的密钥长度变得容易被暴力破解;3DES即是设计用来提供一种相对简单的方法,即通过增加DES的密钥长度来避免类似的攻击,而不是设计一种全新的块密码算法

密钥需要是3 * 56 = 168位(实际使用192位),iv需要是64位

AES加密

from Crypto.Cipher import AES

def padding_to(raw: bytes, padding: int, max_length: int = None):
    '''
    部分加解密是需要补齐位数到指定padding的
    '''
    c = len(raw)/padding
    block: int = int(c)
    if block != c:
        block += 1
    result = raw.ljust(padding*block, b'\0')
    if max_length:
        result = result[0:max_length]
    return result

def test_aes(key,iv,content):
  # MODE_CBC
  e = AES.new(padding_to(key,32,32), AES.MODE_CBC, padding_to(iv,16,16)).encrypt(padding_to(content,16))
  d = AES.new(padding_to(key,32,32), AES.MODE_CBC, padding_to(iv,16,16)).decrypt(e)
  print(f'e = {e}\nd = {d}\n\n')
  # MODE_CFB
  e = AES.new(padding_to(key,32,32), AES.MODE_CFB, padding_to(iv,16,16)).encrypt(padding_to(content,16))
  d = AES.new(padding_to(key,32,32), AES.MODE_CFB, padding_to(iv,16,16)).decrypt(e)
  print(f'e = {e}\nd = {d}\n\n')
  # MODE_ECB no need for iv
  e = AES.new(padding_to(key,32,32), AES.MODE_ECB).encrypt(padding_to(content,16))
  d = AES.new(padding_to(key,32,32), AES.MODE_ECB).decrypt(e)
  print(f'e = {e}\nd = {d}\n\n')
  # MODE_OFB
  e = AES.new(padding_to(key,32,32), AES.MODE_OFB, padding_to(iv,16,16)).encrypt(padding_to(content,16))
  d = AES.new(padding_to(key,32,32), AES.MODE_OFB, padding_to(iv,16,16)).decrypt(e)
  print(f'e = {e}\nd = {d}\n\n')
config = {
        "key": "SGTSerfend2022",
        "iv": "1Ssecret1Ssecret1Ssecret"
    }
content = ('0123456789abcdefAAAAAAAAAA'*5).encode()
iv = str(config['iv']).encode()
key = str(config['key']).encode()
test_aes(key,iv,content)

这个标准用来替代原先的DES(Data Encryption Standard),已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院 (NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一 [1] 。

该算法为比利时密码学家Joan Daemen和Vincent Rijmen所设计,结合两位作者的名字,以Rijdael之名命之,投稿高级加密标准的甄选流程。(Rijdael的发音近于 “Rhine doll”。)

密钥需要是32位,iv需要是16位

blowfish加密

from Crypto.Cipher import Blowfish

def padding_to(raw: bytes, padding: int, max_length: int = None):
    '''
    部分加解密是需要补齐位数到指定padding的
    '''
    c = len(raw)/padding
    block: int = int(c)
    if block != c:
        block += 1
    result = raw.ljust(padding*block, b'\0')
    if max_length:
        result = result[0:max_length]
    return result

def test_Blowfish(key,iv,content):
  # MODE_CBC
  e = Blowfish.new(padding_to(key,32,32), Blowfish.MODE_CBC, padding_to(iv,8,8)).encrypt(padding_to(content,8))
  d = Blowfish.new(padding_to(key,32,32), Blowfish.MODE_CBC, padding_to(iv,8,8)).decrypt(e)
  print(f'e = {e}\nd = {d}\n\n')
  # MODE_CFB
  e = Blowfish.new(padding_to(key,32,32), Blowfish.MODE_CFB, padding_to(iv,8,8)).encrypt(padding_to(content,8))
  d = Blowfish.new(padding_to(key,32,32), Blowfish.MODE_CFB, padding_to(iv,8,8)).decrypt(e)
  print(f'e = {e}\nd = {d}\n\n')
  # MODE_ECB no need for iv
  e = Blowfish.new(padding_to(key,32,32), Blowfish.MODE_ECB).encrypt(padding_to(content,8))
  d = Blowfish.new(padding_to(key,32,32), Blowfish.MODE_ECB).decrypt(e)
  print(f'e = {e}\nd = {d}\n\n')
  # MODE_OFB
  e = Blowfish.new(padding_to(key,32,32), Blowfish.MODE_OFB, padding_to(iv,8,8)).encrypt(padding_to(content,8))
  d = Blowfish.new(padding_to(key,32,32), Blowfish.MODE_OFB, padding_to(iv,8,8)).decrypt(e)
  print(f'e = {e}\nd = {d}\n\n')
config = {
        "key": "SGTSerfend2022",
        "iv": "1Ssecret1Ssecret1Ssecret"
    }
content = ('0123456789abcdefAAAAAAAAAA'*5).encode()
iv = str(config['iv']).encode()
key = str(config['key']).encode()
test_Blowfish(key,iv,content)

Blowfish是一个对称加密块算法,由Bruce Schneider于1993年设计,现已应用在多种加密产品。Blowfish能保证很好的加密速度,并且目前为止没有发现有效地破解方法。目前为止AES比Blowfish有更广的知名度。

密钥需要是32-448位(或1-14个字符),iv需要是8位

RC4加密

from Crypto.Cipher import ARC4


def test_rc4(key: bytes, content: bytes):
    e = ARC4.new(key).encrypt(content)
    d = ARC4.new(key).decrypt(e)
    print(f'e = {e}\nd = {d}\n\n')
    assert d == content


if __name__ == '__main__':
    config = {
        "key": "SGTSerfend2022",
    }
    content = ('0123456789abcdefAAAAAAAAAA'*5).encode()
    key = str(config['key']).encode()
    test_rc4(key, content)

非对称加密

RSA加密

整体测试示例代码
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5 as PKCS1_signature
from Crypto.Cipher import PKCS1_v1_5 as PKCS1_cipher
from Crypto.Hash import SHA
def test_rsa(content):
  rsa = RSA.generate(2048)
  public_key = rsa.public_key().export_key()
  private_key = rsa.export_key()
  print(f'public_key: {public_key}\n\nprivate_key: {private_key}\n')
  private_key = RSA.importKey(private_key)
  public_key = RSA.importKey(public_key)

  # sign a message
  signer = PKCS1_signature.new(private_key)
  digest = SHA.new()
  digest.update(content)
  sign = signer.sign(digest)
  print(f'sign: {sign}\n')

  # check sign for a message
  verifier = PKCS1_signature.new(public_key)
  digest = SHA.new()
  digest.update(content)
  sign_result = verifier.verify(digest,sign)
  print(f'the message check sign result is :{sign_result}\n')

  # encrypt rsa
  cipher = PKCS1_cipher.new(public_key)
  encrypt_text = cipher.encrypt(content)
  print(f'encrypt_text: {encrypt_text}\n')

  # decrypt rsa
  cipher = PKCS1_cipher.new(private_key)
  decrypt_text = cipher.decrypt(encrypt_text,b'')
  print(f'decrypt_text: {decrypt_text}\n')
content = ('0123456789abcdefAAAAAAAAAA'*5).encode()
test_rsa(content)

RSA是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的 [1] 。

RSA公开密钥密码体制的原理是:根据数论,寻求两个大素数比较简单,而将它们的乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥 [4] 。

产生密钥对

可以是产生128 224 256 512 768 1024 2048等整数位数的密钥

from Crypto.PublicKey import RSA
rsa = RSA.generate(2048)
public_key = rsa.public_key().export_key()
private_key = rsa.export_key()
print(f'public_key: {public_key}\n\nprivate_key: {private_key}\n')
private_key = RSA.importKey(private_key)
public_key = RSA.importKey(public_key)
加解密

利用产生的密钥对,调用RSA.importKey分别导入公钥和私钥

from Crypto.Signature import PKCS1_v1_5 as PKCS1_signature
from Crypto.Cipher import PKCS1_v1_5 as PKCS1_cipher
content = ('0123456789abcdefAAAAAAAAAA'*5).encode()
# sign a message
signer = PKCS1_signature.new(private_key)
digest = SHA.new()
digest.update(content)
sign = signer.sign(digest)
print(f'sign: {sign}\n')

# check sign for a message
verifier = PKCS1_signature.new(public_key)
digest = SHA.new()
digest.update(content)
sign_result = verifier.verify(digest,sign)
print(f'the message check sign result is :{sign_result}\n')
校验签名(判断数据是否是可靠的,没有被篡改的)

使用SHA1等散列算法生成一个hash,用于生成签名

from Crypto.Signature import PKCS1_v1_5 as PKCS1_signature
from Crypto.Cipher import PKCS1_v1_5 as PKCS1_cipher
content = ('0123456789abcdefAAAAAAAAAA'*5).encode()
# encrypt rsa
cipher = PKCS1_cipher.new(public_key)
encrypt_text = cipher.encrypt(content)
print(f'encrypt_text: {encrypt_text}\n')

# decrypt rsa
cipher = PKCS1_cipher.new(private_key)
decrypt_text = cipher.decrypt(encrypt_text,b'')
print(f'decrypt_text: {decrypt_text}\n')

注意事项

padding_to方法是因为有些key、iv和待加密的数据的长度是需要是一些数值的倍数,不足长度的是需要补齐的,这里使用\0对其进行补齐

max_length是补齐后的最大长度,超过这个长度的数据将会被截取

def padding_to(raw: bytes, padding: int, max_length: int = None):
    '''
    部分加解密是需要补齐位数到指定padding的
    '''
    c = len(raw)/padding
    block: int = int(c)
    if block != c:
        block += 1
    result = raw.ljust(padding*block, b'\0')
    if max_length:
        result = result[0:max_length]
    return result

其他文档

  • CTF逆向-常用的逆向工具 提取码:pnbt
  • B站教程中国某省队CTF集训(逆向工程部分)
    • 中国某省队CTF集训(逆向工程部分)(已授权)(一)
    • 基础加密方式例如 XXTEABase64换表
    • Python库 Z3 方程式、不定式等的 约束求解
    • 基础的假跳转花指令(脏字节)
    • 非自然程序流程
      • 扁平化程序控制流
      • OLLVM程序流程(虚拟机壳) 很难一般不考
      • ida里面按X键跟踪,寻找所有Tyw的引用(即类型是写入的),通常就是关键位置
    • 中国某省队CTF集训(逆向工程部分)(已授权)(二)
    • ollydb动调去壳,upx为例子
    • python的逆向和自定义虚拟指令
      • 使用pycdc 提取码:dorr 解密python编译的exe或者pyc
      • 逐条去解析用py字典手动实现的指令调用
      • C++编译的程序的逆向
    • 中国某省队CTF集训(逆向工程部分)(已授权)(三)
      • 简单模运算加密
      • base58 寻找一下特别大的数,这种数通常是算法的标识,或者ida7.7版本以上自带的find crypt插件ctrl+alt+f
      • 常见的关键位置是有新的内存分配的地方通常是关键地方,或者函数中间突然return的地方也是
      • 迷宫题 注意绘制出来就好
      • 动调题
        • 注意观察会执行的反调试分支,例如出现int 3,需要跳过去
  • 基本知识

更多CTF逆向题通用性做法和常用工具下载参考该博文内容:CTF逆向Reverse题的玩法

相关逆向CTF题

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐