2.Python实现Base64
搜索Base64算法资料,详细解释该算法。用Python实现它,把自己的学号(字母大写)用Base64编码输出。并且把上面的源代码文件编译成pyc文件。(不要抄袭)
代码:
#Base64的索引与对应字符的关系
Base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
#待编码字符
STR="E41614018"
#转化成list方便处理缺失字节情况
Str=list(STR)
print("明文: "+STR)
print("Base64:", end='')
#每组三个字符即3*8=24bit,转换为
for i in range(0,len(Str),3):
a=ord(Str[i])
#若缺2字节
if len(Str)-1==i:
b=0;
else:
b=ord(Str[i+1])
#若缺1or2字节
if (len(Str)-1==i)|(len(Str)-2==i):
c=0;
else:
c=ord(Str[i+2])
#拆成4个6bit,计算各自的索引号
A= a>>2
B=((a&0b00000011)<<4)+((b&0b11110000)>>4)
C=((b&0b00001111)<<2)+((c&0b11000000)>>6)
D= c&0b00111111
#根据索引在Base64寻找,并输出对应字符
#若缺2字节
if len(Str)-1==i:
print(Base64[A]+Base64[B]+'==', end='')
else:
#若缺1字节
if (len(Str)-2==i):
print(Base64[A]+Base64[B]+Base64[C]+'=', end='')
else:
#若不缺字节
print(Base64[A]+Base64[B]+Base64[C]+Base64[D], end='')
print("\n")
运行结果:
输出内容:
明文: E41614018
Base64:RTQxNjE0MDE4
小结与讨论:
Base64编码算法能够将任意的字节数组数据,通过算法参照“Base64编码索引表”生成只有“大小写英文字母、数字、+、/”(共64个字符)内容表示的字符串数据,即将任意的内容转换为可见的字符串形式。
Base64算法在编码时将数据按照3个字节一组的形式进行处理,每3个字节在编码之后被转换为4个字节。而当数据的长度无法满足3的倍数的情况下,最后的数据需要进行填充操作,即补“=” (这里“=”是填充字符表示没有数据,而不是上述64个字符中包含的字符)。
这里需要注意的是:Base64是编码算法而不是加密算法,只是用来编码字节数组形成字符串的。Base64算法提供了解码功能,并且任何人都可以将Base64的编码结果解码成唯一的原文。
3.反编译
找班上学号和你相邻的一位同学要一下上面的pyc文件(不是源代码文件),然后搜索相关反编译工具把pyc反编译成Python源代码,最好能多找几种工具或者途径达到反编译的目的。
①在线反编译平台:https://tool.lu/pyc/:
②Python反编译工具---Easy Python Decompiler:
反编译失败,系统提示:Magic value mismatch魔法值不匹配。这是因为它只支持python2.7与python3.4以下的版本。
③在线反编译平台http://tools.bugscaner.com/decompyle/
4.Cracking SHA1-Hashed Passwords
去https://www.mysterytwisterc3.org/用组长的学号注册一个账号(字母大写),
完成关卡Cracking SHA1-Hashed Passwords。
https://www.mysterytwisterc3.org/en/challenges/level-ii/cracking-sha1-hashed-passwords
代码:
import hashlib
import copy
#递归求解1-8的全排列
def permutation(lst,k):
result = []
length = len(lst)
tmp = [0]*k
def next_num(a,ni=0):
if ni == k:
result.append(copy.copy(tmp))
return
for lj in a:
tmp[ni] = lj
b = a[:]
b.pop(a.index(lj))
next_num(b,ni+1)
c = lst[:]
next_num(c,0)
return result
P=permutation([1,2,3,4,5,6,7,8],8)
SS = [[0 for i in range(4)] for i in range(9)]
S = [[0 for i in range(4)] for i in range(9)]
#放入所有可能选择
SS[1][1]="Q"
SS[1][2]="q"
SS[2][1]="W"
SS[2][2]="w"
SS[3][1]="I"
SS[3][2]="i"
SS[4][1]="N"
SS[4][2]="n"
SS[5][1]="%"
SS[5][2]="5"
SS[6][1]="("
SS[6][2]="8"
SS[6][3]="["
SS[7][1]="="
SS[7][2]="0"
SS[7][3]="}"
SS[8][1]="*"
SS[8][2]="+"
SS[8][3]="~"
flag=0;
#print(len(P),len(P[1]))
#遍历每一种排列情况
for i in range(len(P)):
if flag==1:
break;
#根据排列组成S
for j in range(len(P[1])):
if flag==1:
break;
S[j+1]=SS[P[i][j]]
sha1=""
#print(S)
#对于每种排列,每个键又有2、3种选择
#遍历所有选择
for a in range(1,4):
#已经找到则退出
if flag==1:
break;
#遇到为0的选项则跳过该可能
if S[1][a]==0:
continue
for b in range(1,4):
if flag==1:
break;
if S[2][b]==0:
continue
for c in range(1,4):
if flag==1:
break;
if S[3][c]==0:
continue
for d in range(1,4):
if flag==1:
break;
if S[4][d]==0:
continue
for e in range(1,4):
if flag==1:
break;
if S[5][e]==0:
continue
for f in range(1,4):
if flag==1:
break;
if S[6][f]==0:
continue
for g in range(1,4):
if flag==1:
break;
if S[7][g]==0:
continue
for h in range(1,4):
if flag==1:
break;
if S[8][h]==0:
continue
string=S[1][a]+S[2][b]+S[3][c]+S[4][d]+S[5][e]+S[6][f]+S[7][g]+S[8][h]
#计算sha1值
sha1=hashlib.sha1(string.encode('utf-8'))
#print(sha1.hexdigest())
#若相同则输出对应密码
if sha1.hexdigest()=='67ae1a64661ac8b4494666f58c4822408dd0a3e4':
print('We found it : '+S[1][a]+S[2][b]+S[3][c]+S[4][d]+S[5][e]+S[6][f]+S[7][g]+S[8][h])
print(sha1.hexdigest())
flag=1
运行结果:
结果验证:
密码:(Q=win*5
将密码提交到网站上,提示已经成功解题:
小结与讨论:
本题我们求解的基本思路还是暴力破解。仔细观察题目所给输入密码的键盘图:
考虑到题目应是短时间内可解的,所以我们做出如下的假设来减少计算量(后来得出的密码也证明假设是合理的)
(1)真正作为密码输入的应该只有Q、W、5、8、0、I、N、+这8个键(当然每个键会有不同的输入),shift键、方向键和右侧数字键都只做到控制作用,并没有实际的字符输入;
(2)不考虑重复按键的情况,否则该问题将无法求解。
于是,我们可以得到如下思路:
①由于我们未知这8个键的敲击顺序,我们要找出其全排列,易知为8的阶乘种;
②其次对于每一种排列情况又会有不同的字符组合,同一个键,如+键,可以输入“+”、“-”、“*”这3种字符。即使对Q之类的字母键也会有“Q”与“q”的区别,所以我们要对这些不同的字符组合进行遍历;
③对于每一种字符组合我们利用hashlib库来计算其sha1值与我们的目的sha1值进行比较,若相同则说明密码已经找到,即破解成功。
hint:密码长度为5
代码:
import hashlib
import copy
#递归求解0-4的全排列
def permutation(lst,k):
result = []
length = len(lst)
tmp = [0]*k
def next_num(a,ni=0):
if ni == k:
result.append(copy.copy(tmp))
return
for lj in a:
tmp[ni] = lj
b = a[:]
b.pop(a.index(lj))
next_num(b,ni+1)
c = lst[:]
next_num(c,0)
return result
flag=0;
P=permutation([0,1,2,3,4],5)
#print(P)
#所有字符
SS=['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9']
#通过五次循环从字符池中挑选出5个字符(因为题目给出密码为5位)
for a in range(len(SS)-4):
if flag==1:
break
for b in range(1,len(SS)-3):
if flag==1:
break
for c in range(2,len(SS)-2):
if flag==1:
break
for d in range(3,len(SS)-1):
if flag==1:
break
for e in range(4,len(SS)):
if flag==1:
break
S=SS[a]+SS[b]+SS[c]+SS[d]+SS[e]
#对于挑选出的5个字符,进行全排列
for i in range(len(P)):
s=S[P[i][0]]+S[P[i][1]]+S[P[i][2]]+S[P[i][3]]+S[P[i][4]]
sha1=hashlib.sha1(s.encode('utf-8'))
#print(sha1.hexdigest())
#若相同则输出对应密码
if sha1.hexdigest()=='4b58475789e60dbf1a28d638b556a938134644c8':
print('We found it : '+s)
print(sha1.hexdigest())
flag=1
break
运行结果: