0%

Python-安全加密

Python 在安全加密方面的最佳实践。如:

  • cryptography:提供了常用的加密方法,名字太长,OUT
  • hashlib:【标准库】为不同的安全哈希和信息摘要算法实现的公共接口,如 MD5、SHA1、SHA224、SHA256、SHA384 和 SHA512 等
  • Passlib:安全的密码存储/哈希库,非常高的安全级别
  • hashmac:在基于各种哈希算法/散列算法同时,使和密钥增加安全性。与 hashilib 的 api 基本一致
  • hmac:【标准库】标准的 Hmac 算法
  • pyobfuscate:Python 代码混淆器,通过多种方式改变源码,一些可以被反解,一些不可以。

概述

  • cryptography
  • hashids
  • paramiko
  • passlib
  • pycrypto
  • pyNacl

MD5:Message-Digest Algorithm 5:信息 - 摘要算法 5:计算机广泛使用的散列算法之一(又译摘要算法、哈希算法),用于确保信息传输完整一致

  • 广泛用于安全领域:如常用于服务器提供一个 MD5 校验和,用户下载完文件后,可用 MD5 算法计算下载文件的 MD5 校验和,通过对比一致性,判断文件是否正确。
  • 数据安全的三个要素:
    • 保密性
    • 完整性
    • 可用性
  • 对称加密与非对称加密:
    • 对称加密:加密和解密采用相同的密钥。如:DES、RC2、RC4
    • 非对称加密:需要两个密钥:公钥和私钥。如果用公钥加密,需要用私钥才能解密。如:RSA
    • 区别:对称加密速度更快,通常用于大量数据的加密;非对称加密安全性更高(不需要传送私钥)

字符混淆

  • 不能实现真正的加密,只是看到脚本的人无法直接记下密码
1
2
3
4
5
6
import base64

print(base64.b64encode("password".encode("utf-8")))
# cGFzc3dvcmQ=
print(base64.b64decode("cGFzc3dvcmQ=").decode("utf-8"))
# password

secrets

secrets:生成密码

基本使用

1
2
3
4
5
6
7
8
import secrets

value = secrets.token_bytes(length)
print(f"Bytes: {value}")
# Bytes: b'U\xe9n\x87...\x85>\x04j:\xb0'
value = secrets.token_hex(length)
print(f"Hex: {value}")
# Hex: fb5dd85e7d73f7a08b8e3...4fd9f95beb08d77391

cryptography

cryptography:提供了常用的加密方法,常用于二进制文件、图片等的加密

  • 支持对称加密算法(如 AES、DES)、非对称加密算法(如 RSA)和哈希算法
1
2
3
4
5
from cryptography.fernet import Fernet
key = Fernet.generate_key()
cipher_suite = Fernet(key)
cipher_text = cipher_suite.encrypt(b"A really secret message. Not for prying eyes.")
plain_text = cipher_suite.decrypt(cipher_text)

hashilib

hashlib:【标准库】为不同的安全哈希和信息摘要算法实现的公共接口,常用于字符串、文本文件等的加密。支持多种哈希算法,如 MD5、SHA1、SHA224、SHA256、SHA384 和 SHA512 等

  • 摘要/哈希/散列算法:通过一个函数,将任意长度的数据转换为一个长度固定的数据串(常用 16 进制的字符串表示),
  • 目的:发现原始数据是否被篡改过。
    • 摘要函数为单向函数,计算 f(data) 很容易,但通过得到的 digest 反推 data 却非常困难,而对原始数据改一个 bit,都会导致计算出的 digest 完全不同
  • 常用 MD5、SHA1,比 SHA1 更安全的算法是 SHA256 和 SHA512,不过越安全的算法不仅越慢,而且摘要长度更长。
  • 碰撞:两个不同的数据通过某个摘要算法得到了相同的摘要
  • 用处:保存用户密码:登录时用用户输入的密码对应的 MD5 与数据库存储的 MD5 对比。
  • 摘要算法不是加密算法,不能用于加密(因为无法通过摘要反推明文),只能用于防篡改,但是它的单向计算特性决定了可以在不存储明文口令的情况下验证用户口令。
    • 需要字节形式的字符串
    • 存储密码的哈希值而不是密码本身
    • 发送文件时同时发送其哈希值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import hashlib
m = hashlib.md5() #哈希对象
m.update(b"test")
m.hexdigest()
'05a671c66aefea124cc08b76ea6d30bb'
m.digest()
b'\x05\xa6q\xc6j\xef\xea\x12L\xc0\x8bv\xeam0\xbb'
hash=hashlib.new('ripemd160',b'chen') # 算法名、字节数据
dics = hashlib.algorithms_guaranteed # 所有平台支持的 hash 算法的名称
dics = hashlib.algorithms_available # 在 Python 解析器中可用的 hash 算法的名称, 传递给 new()时, 可识别
# hashlib.pbkdf2_hmac(hash_name, password, salt, iterations, dklen=None) // 加盐加密 hash_name:hash 名称, password:数据, salt:盐, iterations:循环次数, dklen:密钥长度
hash_bytes = hashlib.pbkdf2_hmac('sha256', b'luzhuo.me', b'80', 100000)
# hash 对象
num = hash.digest_size # hash 结果的大小
num = hash.block_size # hash 算法的内部块的大小
strs = hash.name # hash 名称, 可传给 new()使用
hash.update(b"data") # 字节缓冲区 hash.update(a) hash.update(b) == hash.update(a+b)
hash_bytes = hash.digest() # 字节 hash
hash_str = hash.hexdigest() # 16 进制字符串 hash
hash = hash.copy() # 拷贝 hash 对象副本
1
2
3
4
5
6
7
8
9
10
11
12
13
# md5 算法:速度快,生成固定的 128 bit 字节,通常用一个 32 位的 16 进制字符串表示
import hashlib
md5 = hashlib.md5()
md5.update('how to use md5 in python hashlib?'.encode('utf-8'))
print(md5.hexdigest())
# d26a53750bc40b38b65a520292f69306

# 若数据量较大,可分块多次调用 `update()`,最后的计算结果是一样的
import hashlib
md5 = hashlib.md5()
md5.update('how to use md5 in '.encode('utf-8'))
md5.update('python hashlib?'.encode('utf-8'))
print(md5.hexdigest())
1
2
3
4
5
6
# SHA1:结果是 160 bit 字节,通常用一个 40 位的 16 进制字符串表示。
import hashlib
sha1 = hashlib.sha1()
sha1.update('how to use sha1 in '.encode('utf-8'))
sha1.update('python hashlib?'.encode('utf-8'))
print(sha1.hexdigest())

passlib

Passlib:安全的密码存储/哈希库,非常高的安全级别

hashmac

hashmac:在基于各种哈希算法/散列算法同时,使和密钥增加安全性。与 hashilib 的 api 基本一致

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
import hmac
def hmac_demo():
# 加密
h = hmac.new(b"net")
h.update(b"luzhuo.me")
h_str = h.hexdigest()
print(h_str)
# 比较密码
boolean = hmac.compare_digest(h_str, hmac.new(b"net", b"luzhuo.me").hexdigest())
print(boolean)

def hmac_func():
# 创建 key 和内容,再都进行加密
# hmac.new(key, msg=None, digestmod=None) // 创建新的 hmac 对象, key:键, msg:update(msg), digestmod:hash 名称(同 hashlib.new())(默认 md5)
hc = hmac.new(b"key")
# hmac 对象
hc.update(b"msg") # 字节缓冲区 hc.update(a) hc.update(b) == hc.update(a+b)
hash_bytes = hc.digest() # 字节 hash
hash_str = hc.hexdigest() # 16 进制 hash 字符串
hc = hc.copy() # 拷贝 hmac 副本
num = hc.digest_size # hash 大小
num = hc.block_size # hash 算法内部块大小
strs = hc.name # hash 名称
# hmac.compare_digest(a, b) // 比较两个 hash 密钥是否相同, 参数可为: str / bytes-like object, (注:建议使用,不建议使用 a==b)
boolean = hmac.compare_digest(hmac.new(b"net", b"luzhuo.me").digest(), hmac.new(b"net", b"luzhuo.me").digest())

hmac

hmac:【标准库】标准的 Hmac 算法,常用于验证消息的完整性

  • 对在应用程序之间传递或存储的可能受攻击的数据,以实际数据 + 共享密钥结合的形式,生成的哈希检查传输或存储的的完整生
  • 利用一个 key 对 message 计算杂凑后得到 hash
  • Hmac 算法:Keyed-Hashing for Message Authentication。它通过一个标准算法,在计算哈希的过程中,把 key 混入计算过程中。
  • 和我们自定义的加 salt 算法不同,Hmac 算法针对所有哈希算法都通用,无论是 MD5 还是 SHA-1。采用 Hmac 替代我们自己的 salt 算法,可以使程序算法更标准化,也更安全。
1
2
3
4
5
6
7
8
import hmac
message=b'Hello world!' # bytes 类型
key=b'secret'
h=hmac.new(key,message,digestmod='MD5')

# 如果消息很长,可以多次调用 h.update(msg)
h.hexdigest()
'fa4ee7d173f2d97ee79022d1a7355bcf'
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 hmac

digest_maker = hmac.new(b'secret-shared-key-goes-here')

with open('lorem.txt', 'rb') as f:
while True:
block = f.read(1024)
if not block:
break
digest_maker.update(block)

digest = digest_maker.hexdigest()
print(digest)

# 默认加密方法为MD5,但它不够安全,且可能冲突,建议用SHA-1算法
import base64
import hmac
import hashlib

with open('lorem.txt', 'rb') as f:
body = f.read()

hash = hmac.new(
b'secret-shared-key-goes-here',
body,
hashlib.sha1,
)

digest = hash.digest()
print(base64.encodebytes(digest))

pyobfuscate

pyobfuscate:Python 代码混淆器,通过多种方式改变源码,一些可以被反解,一些不可以。

  • 脚本语言的 pyc 和 pyo 文件能反编译出源码,
  • 通过混淆代码可增加破解者阅读代码的成本。
  • pyexe、PyInstaller、Py2app 等打包工具:可得到 pyc 文件或源代码
  • 目前大部分开源的 Python 代码混淆工具都是可逆的,最安全的不可逆方式是把 Python 代码编译成 C 模块,直接发布编译后的类库即可。但需要编写额外的代码来生成 C 模块,并且生成后的模块不一定可以直接运行。
  • Cython:Cython 是属于 PYTHON 的超集,首先会将 PYTHON 代码转化成 C 语言代码,然后通过 c 编译器生成可执行文件。
    • 优势:资源丰富,适合快速开发。翻译成 C 后速度比较快。
    • 缺点是:无法支持 JIT 技术
  • 类似于 C/C++ 的 CXX-OBFUS

jmpy

jmpy:将 .py 文件编译成 .pyd

  • 需要配置

遇到的问题

  • 加密时 error: Unable to find vcvarsall.bat
  • 解决方案:
    • 参考资料
    • 参考资料
    • 安装最新版本的 Visusl Studio,选择 使用 C++ 的桌面开发,选择 MSVC 相关的可选组件
      • mingw 解决一个问题,又来一个新的问题,真是**,我**,**Windows

pyarmor

pyarmor:Python代码保护工具,可以对python脚本进行加密和混淆。

1
pip install pyarmor

基本使用

1
pyarmor obfuscate --output dist/obfuscated main.py

附 反调试

  • 当检测到调试器或代码被修改时,应用自动退出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import sys
import os

def detect_debugger():
# 简单的反调试检测
if hasattr(sys, 'gettrace') and sys.gettrace() is not None:
return True
# 更复杂的检测逻辑...
return False

if detect_debugger():
print("检测到调试器,应用退出")
os._exit(0)
python
运行

给博主来一杯卡布奇诺