2036 字
10 分钟
python密码学实验
2026-07-16

实验一:熟悉 Python 开发环境,凯撒密码与仿射密码#

实验目的#

  • 熟悉 Pycharm/ Python Idle 开发

  • 完成 Casear 密码的编程。

实验内容#

1、安装 Python、Pycharm;了解 Idle 的应用;学会 pip 安装命令,将 Cryptography gmpy2 库安装到 python 中。

2、编写 Casear 密码程序,扩展到仿射密码、以及 Casear 密码的破译程序。

caesar 密码 python 实现#

Python 密码学教程 - w3schools

第一版代码:

两个函数分别实现对 Caesar 密码的加密和解密,关键的操作公式是相同的,只是对密钥进行加减操作。

for i in message:
ciphertext += (chr(ord(i) + k)) # 将明文汉字转换为对应ASCLL数值或Unicode数值(ord函数),然后在此数值上+3,再将该值返回汉字(chr函数)

第二版代码:

同样是两个函数分别实现对 Caesar 密码的加密和解密,将公式进行修改,第一版并不能把密码限制在 26 个字母。

for i in range(len(text)):
char = text[i]
if (char.isupper()):
ciphertext += chr((ord(char) + key - ord('a')) % 26 + ord('a'))
else:
ciphertext += chr((ord(char) + key - ord('A')) % 26 + ord('A'))

第三版:

能够自定义

SYMBOLS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 !?.'
def caesar_encrypt(mode, message, key):
if mode[0] == 'd':
key = -key
ciphertext = ''
for symbol in message:
if symbol.isalpha():
num = ord(symbol)+key
if symbol.isupper(): # 所有密文字母是大写
if num > ord('Z'):
num -= 26
elif num < ord('A'):
num += 26
elif symbol.islower():
if num > ord('z'):
num -= 26
elif num < ord('a'):
num += 26
ciphertext += chr(num)
else:
ciphertext += symbol
return ciphertext

暴力破解

def caesar_decrypt(message):
LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
letters = "abcdefghijklmnopqrstuvwxyz"
for key in range(26):
translated = ''
for symbol in message:
if symbol in LETTERS:
num = LETTERS.find(symbol)
num = num - key
if num < 0:
num = num + len(LETTERS)
translated = translated + LETTERS[num]
elif symbol in letters:
num = letters.find(symbol)
num = num - key
if num < 0:
num = num + len(letters)
translated = translated + letters[num]
else:
translated = translated + symbol
print('Hacking key #%s: %s' % (key, translated))

仿射密码#

仿射密码 Python 实现 仿射密码是一种替换密码。它是利用加密函数一个字母对一个字母的加密。

加密函数是 E(x)= (ax + b) (mod m),其中,a 和 m 互质,m 是字符集的大小。 (例如,26 即是以 26 个字母作为编码,当 m 是 26 时,a 必须是 1,3,5,7,9,11,15,17,19,21,23,25 其中之一)

解密函数为 D(x) = a-1(x - b) (mod m),其中 a-1是 a 在 Zm 群的乘法逆元。

乘法逆元 群 G 中任意一个元素 a,都在 G 中有唯一的逆元 a’,具有性质 aa’ = a’a = e,其中 e 为群的单位元。

'''
仿射密码
(a,b)
m = 26,字符集为小写字母
加密函数是E(x)= (ax + b) (mod m)
解密函数为D(x) = (a^-1)(x - b) (mod m),其中a^-1是a的乘法逆元
'''
#通过一个简单的遍历得到a的乘法逆元,也可以通过gmpy2库中的invert函数实现
def get_inverse(a):
for i in range(1,27):
if a*i%26==1:
return i
#加密
def encipher(a, b, p):
c=[]
for i in p:
temp=((ord(i)-97)*a+b)%26+97
c.append(chr(temp))
print(''.join(c))
#解密
def decipher(a, b, c):
a_inv = get_inverse(a)
p=[]
for i in c:
temp=(((ord(i)-97)-b)*a_inv)%26+97
p.append(chr(temp))
print(''.join(p))
if __name__ == "__main__":
a = 11
b = 6
message = 'sorcery'
encipher(a,b,message)
#decipher(a,b,message)
'''
仿射密码
m = 52
字符集为小写和大写字母
'''
import string
def encrypt(k1,k2,message):
dic = string.ascii_letters
c = []
for i in message:
if i.islower():
num = ord(i)-ord('a')
c.append(dic[(num*k1+k2)%52])
elif i.isupper():
num = ord(i)-ord('A')+26
c.append(dic[(num*k1+k2)%52])
else:
c.append(i)
print(''.join(c))
def decrypt(k1,k2,message):
for i in range(52):
if k1*i%52==1:
inv = i
break
dic = string.ascii_letters
m = []
for i in message:
if i.islower():
num = ord(i)-ord('a')
m.append(dic[inv*(num-k2)%52])
elif i.isupper():
num = ord(i)-ord('A')+26
m.append(dic[inv*(num-k2)%52])
else:
m.append(i)
print(''.join(m))
message = 'gVEXGT iDIT' #待加密或解密的消息
a = 5 # key的范围0~51之间
b = 29 # key的范围0~51之间
# encrypt(a,b,message)
decrypt(a,b,message)
class Affine(object):
DIE = 128
KEY = (7, 3, 55)
def __init__(self):
pass
def encryptChar(self, char):
K1, K2, kI = self.KEY
return chr((K1 * ord(char) + K2) % self.DIE)
def encrypt(self, string):
return "".join(map(self.encryptChar, string))
def decryptChar(self, char):
K1, K2, KI = self.KEY
return chr(KI * (ord(char) - K2) % self.DIE)
def decrypt(self, string):
return "".join(map(self.decryptChar, string))
affine = Affine()
print(affine.encrypt('Affine Cipher'))
print(affine.decrypt('*18?FMT'))

实验二:哈希函数#

1、 编程实现生成空字符串、‘Alice’、‘Bob’的 md5、sha256 的哈希值;

import hashlib
def hash_md5():
alice = hashlib.md5(b"Alice")
bob = hashlib.md5(b"Bob")
print('"Alice" md5:' + alice.hexdigest())
print('"Bob" md5:' + bob.hexdigest())
def hash_sha256():
alice = hashlib.sha256(b"Alice")
bob = hashlib.sha256(b"Bob")
print('"Alice" sha256:' + alice.hexdigest())
print('"Bob" sha256:' + bob.hexdigest())

2、 编程实现生成自己名字的哈希值,注意编码的转换;

def myhash(str = "Yangjiaqing"):
res = hashlib.md5(str.encode(encoding="utf-8"))
print(str + " md5: " + res.hexdigest())

3、 编写体现哈希雪崩的代码,哈希值用二进制表示; 参考 Listing2-5 代码; Python 哈希函数与消息认证实验 展示散列函数的雪崩效应

def cmpcount(str1, str2):
count = 0
for i in range(0, len(str1)):
if str1[i] != str2[i]:
count += 1
return count
def avalanche(str1 = 'bob', str2 = 'aob'):
bin1 = str1.encode('utf-8')
bin2 = str2.encode('utf-8')
hexstring1 = hashlib.md5(bin1).hexdigest()
binstring1 = '{:08b}'.format(int(hexstring1, 16))
# binstring1 = bin(int(hexstring1, 16))
hexstring2 = hashlib.md5(bin2).hexdigest()
binstring2 = '{:08b}'.format(int(hexstring2, 16))
# binstring2 = bin(int(hexstring2, 16))
print(int(hexstring1, 16))
print(int(hexstring2, 16))
print(str1 + " md5:" + binstring1)
print(str2 + " md5:" + binstring2)
print("两个哈希值不同的位数:" + str(cmpcount(binstring1, binstring2)))

4、 利用 scrypt 密钥派生函数,实现口令加盐,生成更加安全的密钥(口令); 创建一个 Python 盐 Scrypt 介绍 Scrypt 是一个强大的密钥派生函数,其通过内存密集的计算方式来抵抗 GPU、ASIC、FPGA 这类密码破解硬件的攻击。

Scrypt 接收多个输入参数,进行计算后输出密钥:

key = Scrypt(password, salt, N, r, p, derived-key-len) 其中的参数被称为” Scrypt 配置参数”,说明如下:

N - 迭代次数,将影响 CPU 和内存用量,例:16384 、2048 ; r - 块大小,将影响 CPU 和内存用量,例:8 ; p - 并行因数 (并行运行的线程数,将影响 CPU 和内存用量),通常为 1 ; password - 输入的密码(推荐至少为 8 - 10 个字符); salt - 安全产生的随机字节序列(最小为 64 位,推荐 128 位); derived-key-len - 输出的密钥要有多少字节长,例如 32 (256 位) Scrypt 的输出密钥长度可以是 128 位到 512 位,但是通常为 256 位。

Salt 用使用 secrets 模块生成,也可以用 os.urandom()随机生成

def hash_password(password = b'p@$Sw0rD~7'):
salt_length = 16
salt = secrets.token_bytes(salt_length)
key = pyscrypt.hash(password, salt, 2048, 8, 1, 32)
return key.hex()

5、实现区块链中的工作量证明编程,通过设置不同的难度,体会生成符合要求哈希值需要时间长短的不同; 从零开始构建一个区块链(二): 工作量证明 使用 python 实现简版区块链-工作量证明 区块链的简单实现 - GitHub

import sys
import hashlib
class NonceNotFoundError(Exception):
pass
def encode(str, code='utf-8'):
return str.encode(code)
def decode(bytes, code='utf-8'):
return bytes.decode(code)
def sum256_hex(*args):
m = hashlib.sha256()
for arg in args:
if isinstance(arg, str):
m.update(arg.encode())
else:
m.update(arg)
return m.hexdigest()
def sum256_byte(*args):
m = hashlib.sha256()
for arg in args:
if isinstance(arg, str):
m.update(arg.encode())
else:
m.update(arg)
return m.digest()
class ProofOfWork(object):
_N_BITS = 20
MAX_BITS = 256
MAX_SIZE = sys.maxsize
def __init__(self, n_bits=_N_BITS):
self._n_bits = n_bits
self._target_bits = 1 << (self.MAX_BITS - n_bits)
def _prepare_data(self, nonce):
data_lst = [str(nonce)]
return encode(''.join(data_lst))
def run(self):
nonce = 0
found = False
hash_hex = None
print('Mining a new block')
while nonce < self.MAX_SIZE:
data = self._prepare_data(nonce)
hash_hex = sum256_hex(data)
hash_val = int(hash_hex, 16)
sys.stdout.write("try nonce == %d hash_hex == %s \r" % (nonce, hash_hex))
if (hash_val < self._target_bits):
found = True
break
nonce += 1
if found:
print('Found nonce == %d' % nonce)
else:
print('Not Found nonce')
raise NonceNotFoundError('nonce not found')
return nonce, hash_hex
if __name__ == "__main__":
bc = ProofOfWork()
bc.run()

实验三:实现对称加密编程#

分组密码的五大工作模式

使用 cryptography 进行 AES 的 cbc 模式加密 - 知乎 (zhihu.com)

istommao/cryptokit: cryptokit is a cryptography kit (github.com)

4、练习 3-12 手工 CBC:编程应用 AES 的 ECB 模式实现 CBC 模式

def ecbTocbc(self, data):
if not isinstance(data, bytes):
data = data.encode()
cipher = Cipher(algorithms.AES(self.aes_key),
modes.ECB(),
backend=default_backend())
dataList = []
cipherText = []
padded_data = self.pkcs7_padding(data)
binary_data = bin((int(padded_data.hex(), 16)))[2:]
while len(binary_data) / 128 >= 0:
if len(binary_data) / 128 == 0 & len(binary_data) % 128 == 0:
break
elif len(binary_data) / 128 == 0 & len(binary_data) % 128 != 0:
dataList.append(binary_data[0:])
dataList.remove()
else:
dataList.append(binary_data[0:128])
binary_data = binary_data[128:]
c = "{:08b}".format(int(self.aes_iv.hex(), 16))
for i in dataList:
ci = cipher.encryptor().update(bytes(i^c))
cipherText.append(ci)
c = ci.decode()
print(c)
m = ''.join([c.hex() for c in cipherText])
return m

5、练习 3-13 简单 CTR 模式:编程应用 AES 的 ECB 模式实现 CTR 模式

def ecbToctr(self, data):
if not isinstance(data, bytes):
data = data.encode()
iv = self.aes_iv
cipher = Cipher(algorithms.AES(self.aes_key),
modes.ECB(),
backend=default_backend())
dataList = []
cipherText = []
padded_data = self.pkcs7_padding(data)
binary_data = "{:08b}".format(int(padded_data.hex(), 16)) + '0'
while len(binary_data) / 128 >= 0:
if len(binary_data) / 128 == 0 & len(binary_data) % 128 == 0:
break
elif len(binary_data) / 128 == 0 & len(binary_data) % 128 != 0:
dataList.append(binary_data[0:])
dataList.remove()
else:
dataList.append(binary_data[0:128])
binary_data = binary_data[128:]
for i in dataList:
ci = cipher.encryptor().update(iv) ^ i.encode()
iv += 1
cipherText.append(ci)
print(ci)
m = ''.join(cipherText)
return m

实验四:实现非对称加密编程#

非对称密钥沉思系列(1):RSA 专题之 PKCSv1.5 填充模式下的选择性密文攻击概述-腾讯云开发者社区-腾讯云 (tencent.com)

python密码学实验
https://h1s97x.github.io/posts/notes/notes-python-cryptography/
作者
H1S97X
发布于
2026-07-16
许可协议
CC BY-NC-SA 4.0
随机文章