1、凯撒密码
凯撒密码(移位密码):
是一种替换加密,明文中的所有字母都在字母表上向后或向前按照一个固定数目进行偏移后被替换成密文。
当偏移量为13位的时候,凯撒密码又叫回转密码(ROT13):明文加密得到密文,密文再加密就会得到明文(因为偏移量为13位,一共26个字母,加密两次就会回到明文了),题目关键字眼会有回转、回旋、十三踢等字眼。
凯撒密码的加密和解密原理:
加密:将每个字母都向后移动k位,其中k为加密密钥。
解密:反向操作,将每个字母都向前移动k位。
凯撒密码python:
##凯撒密码py
def encryption(str,k):
result = ""
for i in range(len(str)):
if str[i].isupper():
result += chr((ord(str[i]) + k-65) % 26 + 65)
else:
result += chr((ord(str[i]) + k - 97) % 26 + 97)
return result
def decryption(str,k):
result = ""
for i in range(len(str)):
if str[i].isupper():
result += chr((ord(str[i]) - k - 65) % 26 + 65)
else:
result += chr((ord(str[i]) - k - 97) % 26 + 97)
return result
if __name__ == '__main__':
while True:
choice = input("请选择加密或解密:\na.加密\nb.解密\nc.退出\n")
if choice == 'a':
str = input("请输入需要加密的字符串:")
k = int(input("请输入加密密钥:"))
print("加密后的字符串为:", encryption(str,k))
elif choice == 'b':
str = input("请输入需要解密的字符串:")
k = int(input("请输入解密密钥:"))
print("解密后的字符串为:", decryption(str,k))
elif choice == 'c':
break
例题:
[LitCTF 2023]Is this only base?
先base64解密
然后根据提示凯撒解密23位,可以使用上面的程序
2、栅栏密码
栅栏密码,就是将一段被加密的明文划分成N个组,然后取每个组的第1个字符,根据情况排列成一段话,特点相对简单,字母不会太多。
1)基础型
基础型:将明文按行排列为m*n矩阵,然后按列得到密文(一般给m,n随机);
python
'''
栅栏密码
可以根据num分栏
'''
import math
def encryption(plaintext,num):
tmp_dict = {}
#初始化字典
for i in range(num):
tmp_dict[i] = []
#根据num 进行分组赋值(核心代码)
for i in range(len(plaintext)):
tmp_dict[i%num].append(plaintext[i])
#从tmp_dict遍历出密文然后进行拼接
ciphtertext = []
for j in tmp_dict.values():
j = ''.join(j)
ciphtertext.append(j)
ciphtertext = ''.join(ciphtertext)
print(f'密文为: {ciphtertext}')
def decryption(ciphertext,num):
plaintext = []
t = int(len(ciphertext)/num)
r = len(ciphertext) % num
b = list(range(1,r+1))
c = len(range(num)) - len(b)
#用0补充b,使其长度和num一样
for i in range(c):
b.append(0)
# print(r,b)
if r != 0:
for i,j in zip(range(num),b):
a = 1
#余数最多只有9
if j == 1:
plaintext.append(ciphertext[0 + t * i:a + t + t * i])
elif j >= 2:
plaintext.append(ciphertext[0 + (j-1) * a + t * i:j * a + t + t * i])
else:
# print(f'b,j,r分别为{b,j,r}')
j = b[j+r-2]
plaintext.append(ciphertext[0 + j*a + 1 + t * i:j*a + 1 + t + t * i])
else:
t = math.ceil(len(ciphertext)/num)
for i in range(num):
plaintext.append(ciphertext[0 + t * i: t + t * i])
print(f'栅栏为{num}时,明文为: ')
for i in range(math.ceil(len(ciphertext)/num)):
for j in range(len(plaintext)):
try:
# print(plaintext)
print(plaintext[j][i],end='')
except:
pass
print()
if __name__ == '__main__':
enter = int(input('加密输入0\n解密输入1\n无密钥暴力破解输入2\n'))
# enter = 2
#加密
if enter == 0:
plaintext = input('请输入明文: ').lower()
num = int(input('总共将明文分为为num栏,请输入num: '))
print(f'明文共{len(plaintext)}位')
print('-----------------------------')
# plaintext = 'stay hungry stay foolishstay hungry stay foolish'
# num = 4
if len(plaintext) % num != 0:
plaintext = plaintext + ' '
encryption(plaintext,num)
#解密
if enter == 1:
ciphertext = input('请输入密文: ')
num = int(input('请输入栅栏数: '))
# ciphertext = 'qhaiuinazgiiys uhsu'
# num = 7
print(f'栅栏数为{num},密文长度为{len(ciphertext)}')
decryption(ciphertext,num)
#不知道栅栏数时进行解密,初始设定为256,可以自己调
if enter == 2:
# ciphertext = 'qhaiuinazgiiys uhsu'
num = 2
ciphertext = input('请输入密文: ')
decryption(ciphertext, num)
while num < 257:
if num <= len(ciphertext):
print(f'栅栏数为{num},密文长度为{len(ciphertext)}')
decryption(ciphertext,num)
num = num + 1
else:
print(f'\n目前{len(ciphertext)}位,栅栏在{num}时被停止')
break
# print('--------破解完毕--------')
2)w型
W型:将明文按照w的形状排列,然后按行得到密文。
3)例题:
[WUSTCTF 2020]佛说:只能四天
佛曰密码,解密,得到
平等文明自由友善公正自由诚信富强自由自由平等民主平等自由自由友善敬业平等公正平等富强平等自由平等民主和谐公正自由诚信平等和谐公正公正自由法治平等法治法治法治和谐和谐平等自由和谐自由自由和谐公正自由敬业自由文明和谐平等自由文明和谐平等和谐文明自由和谐自由和谐和谐平等和谐法治公正诚信平等公正诚信民主自由和谐公正民主平等平等平等平等自由和谐和谐和谐平等和谐自由诚信平等和谐自由自由友善敬业平等和谐自由友善敬业平等法治自由法治和谐和谐自由友善公正法治敬业公正友善爱国公正民主法治文明自由民主平等公正自由法治平等文明平等友善自由平等和谐自由友善自由平等文明自由民主自由平等平等敬业自由平等平等诚信富强平等友善敬业公正诚信平等公正友善敬业公正平等平等诚信平等公正自由公正诚信平等法治敬业公正诚信平等法治平等公正友善平等公正诚信自由公正友善敬业法治法治公正公正公正平等公正诚信自由公正和谐公正平等
可以看出这是核心价值观密码,解密得RLJDQTOVPTQ6O6duws5CD6IB5B52CC57okCaUUC3SO4OSOWG3LynarAVGRZSJRAEYEZ_ooe_doyouknowfence
可以看出这是栅栏密码(基础型),用上面的程序一个一个试,得到4的时候正确,R5UALCUVJDCGD63RQISZTBOSO54JVBORP5SAT2OEQCWY6CGEO53Z67L_doyouknowCaesar
然后,用凯撒解密,能知道凯撒不是最后一步,然后就尝试用base32解密得到flag
3、base64
base64编码使用6个二进制表示一个字符
例题:
[BJDCTF 2020]base??
根据题目可以看出他重新规范了每个位置相对应的字母,可以写出:
import base64
dict={0: 'J', 1: 'K', 2: 'L', 3: 'M', 4: 'N', 5: 'O', 6: 'x', 7: 'y', 8: 'U', 9: 'V', 10: 'z', 11: 'A', 12: 'B', 13: 'C', 14: 'D', 15: 'E', 16: 'F', 17: 'G', 18: 'H', 19: '7', 20: '8', 21: '9', 22: 'P', 23: 'Q', 24: 'I', 25: 'a', 26: 'b', 27: 'c', 28: 'd', 29: 'e', 30: 'f', 31: 'g', 32: 'h', 33: 'i', 34: 'j', 35: 'k', 36: 'l', 37: 'm', 38: 'W', 39: 'X', 40: 'Y', 41: 'Z', 42: '0', 43: '1', 44: '2', 45: '3', 46: '4', 47: '5', 48: '6', 49: 'R', 50: 'S', 51: 'T', 52: 'n', 53: 'o', 54: 'p', 55: 'q', 56: 'r', 57: 's', 58: 't', 59: 'u', 60: 'v', 61: 'w', 62: '+', 63: '/', 64: '='}
a = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' #标准表
c='FlZNfnF6Qol6e9w17WwQQoGYBQCgIkGTa9w3IQKw'
ds='' #把dict转换成字符串方便处理
for i in range(65):
ds+=dict[i]
l=[]
for i in range(len(c)):
l.append(ds.index(c[i])) #无论换不换表,base64变换本身产生的6位二进制数对应的十进制数是不变的,这里就是找到密文c的每个字符在dict表中键值
#print(l) #l中存的是索引值(下标数字)
m1=''
for ll in l:
m1+=a[ll] #找到l中所存的每个数字在标准的base64加密表中所对应的字符
print(m1) #m1是标准base64表编码结果
m2=base64.b64decode(m1) #直接调用函数恢复出明文
print(m2)
就可以得出flag
4、维吉尼亚密码
维吉尼亚密码是一种使用多表代换的代换密码,是在凯撒密码的基础上扩展出来的多表密码。
维吉尼亚密码引入了“密钥”的概念,根据密钥来决定用哪一行的密表来进行替换,以此来对抗字频统计。
算法
现代维吉尼亚密码代换表如下,第一行为密钥,第一列为明文,某明文对应密钥加密产生的密文即为该行该列处的字母。
python
def encrypt(plaintext, key):
# 将明文和密钥转换为大写字母
plaintext = plaintext.upper()
key = key.upper()
# 将明文中的非字母字符去除
plaintext = "".join([i for i in plaintext if i.isalpha()])
# 生成密文
ciphertext = ""
for i in range(len(plaintext)):
# 计算移位量
shift = ord(key[i % len(key)]) - 65
# 对当前字符进行移位并添加到密文中
ciphertext += chr((ord(plaintext[i]) - 65 + shift) % 26 + 65)
return ciphertext
# 提示用户输入明文和密钥
plaintext = input("请输入明文:")
key = input("请输入密钥:")
# 加密并输出密文
ciphertext = encrypt(plaintext, key)
print("密文:", ciphertext)
例题
[NSSCTF 2022 Spring Recruit]classic
先进行凯撒解密,得到NSSCTF{NBQXMZK7MFPW42LDMVPXI4TZ_fakeflagtrybase}
发现不正确,小写字母中有trybase ,所以进行base32解密得到NSSCTF{have_a_nice_try}
5、仿射密码
仿射密码是一种单表代换的对称密码。明文中所有字母对应成数值,经过加密函数加密成新的数值,再对应到相应的字母,组成密文, 密文和明文一样经过解密函数恢复成明文。
加密函数:
解密函数:
其中,a与m互质,是a在群中的乘法逆元
明文空间一般为26个英文字母,任意两个不同的字母加密或解密后对应不用的字母,相同的字母加密或解密后对应相同的字母,所有仿射密码可以使用频率分析法破解。
python
# 构造字典,'A' --> 0 ...
def char_2_num(x):
list_s = []
list_num = []
for i in range(26):
c = chr(i + 65)
list_s.append(c)
list_num.append(i)
c_2_n = dict(map(lambda x, y: [x, y], list_s, list_num))
return c_2_n[f'{x}']
# 构造字典,0 ---> 'A' ...
def num_2_char(x):
list_s = []
list_num = []
for i in range(26):
c = chr(i + 65)
list_s.append(c)
list_num.append(i)
n_2_c = dict(map(lambda x, y: [x, y], list_num, list_s))
print(n_2_c[x],end='')
# 编码
def encode():
s = input('输入需要编码的字符: ')
print('编码后的结果为: ',end='')
for j in s:
if j.isspace():
print(' ',end='')
else:
ek = a * char_2_num(j) + b
result = ek % 26
num_2_char(result)
# 求模26下a的逆
def inv_(x):
for inv_a in range(1,26,2):
for j in range(27):
if x * inv_a == 26 * j + 1:
return inv_a
# 解码
def decode():
s = input('输入需要解码的字符: ')
print('解码后的结果为: ',end='')
for j in s:
if j.isspace():
print(' ',end='')
else:
dk = inv_(a) * (char_2_num(j) - b)
result = dk % 26
num_2_char(result)
# 输入指令
answer = input(f'请输入所需的操作:编码/E or 解码/D: ')
# 输入参数a,b
a = int(input('请输入a:'))
b = int(input('请输入b: '))
try:
if answer.upper() == 'E':
encode()
elif answer.upper() =='D':
decode()
else:
print('输入错误!')
except KeyError:
print('请正确输入大写字母!')
例题
[HNCTF 2022 Week1]爱妃
题目
from secret import flag from random import getrandbits from string import * def encrypt(message,a,b,m): return bytes([(i*a+b)%m for i in message]) a,b = getrandbits(4),getrandbits(8) print(f'c = {encrypt(flag,a,b,1<<8)}') # c = b'y\xba\xba\xea\xc7\x11\xc2\xc7\xcb\xd8ZV\xd8ZVp\xb1\xb1\xd8\x19\xa4V\xa4\x19\x8aM\xa83g\xd8&\x19\xdc'
仿射密码
先求a,b
r a in range(2**3,2**4): for b in range(2**7,2**8): if encrypt(b'NSSCTF',a,b,1<<8)==c[0:6]: print(a) print(b)
然后解密
from string import * import gmpy2 c = b'y\xba\xba\xea\xc7\x11\xc2\xc7\xcb\xd8ZV\xd8ZVp\xb1\xb1\xd8\x19\xa4V\xa4\x19\x8aM\xa83g\xd8&\x19\xdc' messaget=b'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-{}_' def encrypt(message,a,b,m): return bytes([(i*a+b)%m for i in message]) from Crypto.Util.number import * a=13 b=131 m=1<<8 def decrypt(message,a,b,m): return bytes([(i-b)*gmpy2.invert(a,m)%m for i in message]) print(decrypt(c,a,b,m)) NSSCTF{This_is_affine_encryption}