密码学基础
密码学研究加密、解密、在存在窃听环境中通信、在存在篡改环境中通信。
常见的对称加密
对称加密算法的分类:
- 流密码/序列密码,用随机生成的序列,对每个字节(或二进制位)作用。安全性依赖于随机序列的随机数生成器。
- 块密码/分组密码,将明文分块(如16字节128位),每个块和秘钥作用,再拼接出看似随机的序列。安全性依赖于块密码算法。
常见对称加密算法
- AES,分组密码
- DES/3DES,分组密码
- RC4,序列密码
非对称加密算法
非对称加密算法,加密秘钥和解密秘钥不同,且无法互相推导。用公钥加密、私钥解密,可以实现用同一个私钥处理其他人发来的消息。用私钥加密、公钥解密,可以实现数字签名,只有用你的私钥加密的信息才能被正确的解密出来。
常见非对称加密算法
- RSA,依赖于大整数分解的困难性
- DSA,依赖于整数离散对数的困难性
- ECDSA,依赖于椭圆曲线上离散对数的困难性
对称加密和非对称加密的应用
对称加密安全性依赖于混淆、扩散等操作。非对称加密安全性依赖于无法在可接受时间内求解的数学问题。对称加密的效率通常高于非对称加密,实际应用场景通常先通过非对称加密方式加密对称加密的秘钥,再用对称秘钥加密大量数据。
古典密码学
古典密码安全性依赖于算法的保密。对现代计算机来说古典密码学都比较容易破解。
密码学前沿
零知识认证:如何向别人证明,你拥有满足特定条件的信息,同时不泄露次信息。
安全多方计算:如何用多个人的秘密共同计算出一个结果,同时不泄露秘密。
量子密码学:量子计算机无法破解的密码学算法。
CTF密码学攻击方法
待完善。
抄错的字符
题目链接。描述: 老师让小明抄写一段话,结果粗心的小明把部分数字抄成了字母,还因为强迫症把所有字母都换成大写。你能帮小明恢复并解开答案吗:QWIHBLGZZXJSXZNVBZW 。看来有可能把数字抄成字母的有 O:0、I:1、L:1、Z:2、S:5、B:6、G:9、Q:9(这里值列举出大写字母对应数字的情况)。那么就可以爆破一下,猜测爆破之后还要base64转码一下,代码如下。
# -*- coding : utf-8 -*-
import base64
def resolve(s):
# 可能抄错的数字和对应字母
d = {'O': 0, 'I': 1, 'L': 1, 'Z': 2, 'S': 5, 'B': 6, 'G': 9, 'Q': 9}
sdict = []
# 每个字符都可能是大小写和原本的数字
for c in s:
sdict.append(c + c.lower() + (str(d.get(c)) if d.get(c) else ''))
# 把可能的原来字符串都列出来
result = ['']
for sd in sdict:
temp = []
for sr in result:
for c in sd:
temp.append(sr + c)
result = temp
# 把可能的base64编码都搞出来
b64result = []
err = []
for i, sr in enumerate(result):
try:
#
s1 = base64.b64decode(sr.encode('utf-8'))
s1 = s1.decode('utf-8')
b64result.append(s1)
except:
try:
sr = sr + '='
s1 = base64.b64decode(sr.encode('utf-8'))
s1 = s1.decode('utf-8')
b64result.append(s1)
except:
try:
sr = sr + '=='
s1 = base64.b64decode(sr.encode('utf-8'))
s1 = s1.decode('utf-8')
b64result.append(s1)
except:
err.append(sr)
return b64result
def main():
# base64 因此将密文分成4个一组
m = 'QWIHBLGZZXJSXZNVBZW'
mseg = []
for i in range(0, len(m), 4):
mseg.append(m[i:i + 4])
print(mseg)
# 遍历所有的字符串片段,拼接到一起
flines = ['']
for s in mseg:
b64seg = resolve(s)
temp = []
for sf in flines:
for sg in b64seg:
temp.append(sf + sg)
flines = temp
# 每行都加上换行符
for i, s in enumerate(flines):
flines[i] = s + '\n'
# 输出到文件
f = open('抄错的字符.txt', 'w', encoding='utf-8')
f.writelines(flines)
f.close()
if __name__ == '__main__':
main()
因为题目作者叫Aman,所以从爆破结果里找能读懂的字符串 flag{Aman_very_cool}
/.-【莫斯密码】
题目链接。很明显的摩斯密码。用随波逐流的摩斯码解密之后,全部转为小写即可。
描述: ..-./.-../.-/--./----.--/-../...--/..-./-.-./-.../..-./.----/--.../..-./----./...--/----./----./...../-----/....-/-----.-
FLAG{D3FCBF17F9399504}
flag{d3fcbf17f9399504}
[+-<>]【BrainFuck编码】
题目链接。描述: +++++ +++++ [->++ +++++ +++<] >++.+ +++++ .<+++ [->-- -<]>- -.+++ +++.< ++++[ ->+++ +<]>+ +++.< +++++ +++[- >---- ----< ]>--- ----- ---.< +++++ ++[-> +++++ ++<]> +++.< +++++ +[->- ----- <]>-- ----- -.--. ----. --.++ +++++ +.<++ ++++[ ->+++ +++<] >++++ +.++. <++++ ++[-> ----- -<]>- ----- ----. -.<++ +++++ [->++ +++++ <]>+. ----. ++++. <++++ +++[- >---- ---<] >---- .+.<+ +++++ ++[-> +++++ +++<] >++++ +++++ ++.<
BrainFuck解码得到 flag{0d86208ac54fbf12}
聪明的小羊【栅栏密码】
题目链接。描述: 一只小羊翻过了2个栅栏 fa{fe13f590lg6d46d0d0}。
栅栏密码解码,分为2栏时,解密结果为:flag{6fde4163df05d900}
把猪困在猪圈里【base64、猪圈密码】
题目链接。描述: flag{}。附件是 把猪困在猪圈里.txt,打开发现仅一行,以=结尾,猜测为base64编码。base64转码输出二进制文件,观察前16字节有0xFFDB为jpg的magic。代码如下。
# -*- coding:utf8 -*-
import base64
# 读取base64密文
f1 = open('把猪困在猪圈里.txt', 'r', encoding='utf-8')
c = f1.readline()
f1.close()
# base64解码,查看16个字节有没有magic
m = base64.b64decode(c)
print(m[0:16])
# 输出到二进制文件
f = open('把猪困在猪圈里.bin', 'wb')
f.write(m)
f.close()
猪圈密码(注意猪圈密码的画法)解密为 flag{thisispigpassword}
你喜欢下棋吗
题目链接。描述: 密码全为小写,格式bugku{}。附件有个 解压密码.txt 和 flag.zip。
你喜欢下棋吗?
解压密码为小写
4423244324433534315412244543
下棋,polybius密码也叫棋盘密码,解密得到thisispolybius,这是压缩包的密码。也可以用随波逐流。
"""
polybius密码,也叫棋盘密码
"""
TAB = [
['a', 'b', 'c', 'd', 'e'],
['f', 'g', 'h', 'ij', 'k'],
['l', 'm', 'n', 'o', 'p'],
['q', 'r', 's', 't', 'u'],
['v', 'w', 'x', 'y', 'z']]
def resovle(s):
ms = ['']
for i in range(0, len(s), 2):
line, col = int(s[i]), int(s[i + 1])
if 1 <= line <= 5 and 1 <= col <= 5:
temp = []
for m in ms:
if line == 2 and col == 4:
temp.append(m + 'i')
temp.append(m + 'j')
else:
temp.append(m + TAB[line - 1][col - 1])
ms = temp
else:
raise IndexError(str(line) + ',' + str(col))
return ms
def main():
c = '4423244324433534315412244543'
m = resovle(c)
for s in m:
print(s)
pass
if __name__ == '__main__':
main()
一种5bit的编码
bugku里面的内容为小写
bugku{11111 11001 00011 00111 01001 11011 10110 11111 10000 01110 11011 10110 11111 01001 00001}
这里用到了博多密码(Baudot Code),解密代码如下,也可以随波逐流解码 。解码后根据描述转成小写得到 flag{baud0tc0de}
# -*- coding:utf8 -*-
"""
Baudot Code 一种5bit编码,比ASCII还要古老
0x00 是ascii的NULL
0x0A 是ascii的LF
0x0D 是ascii的CR
0x05 是ascii的ENQ
0x07 是ascii的BELL
"""
LETTERS = [chr(0x00), 'E', chr(0x0A), 'A', ' ', 'S', 'I', 'U', chr(0x0D), 'D',
'R', 'J', 'N', 'F', 'C', 'K', 'T', 'Z', 'L', 'W', 'H', 'Y', 'P', 'Q',
'O', 'B', 'G', 'Figures', 'M', 'X', 'V', 'Letters']
FIGURES = [chr(0x00), '3', chr(0x0A), '-', ' ', '\'', '8', '7', chr(0x0D),
chr(0x05), '4', chr(0x07), ',', '!', ':', '(', '5', '+', ')', '2',
'$', '6', '0', '1', '9', '?', '&', 'Figures', '.', '/', ';',
'Letters']
def dec(c):
tab = LETTERS
m = ''
for i in c:
if LETTERS[i] == 'Letters':
tab = LETTERS
elif LETTERS[i] == 'Figures':
tab = FIGURES
else:
m += tab[i]
return m
def main():
c = [0b11111, 0b11001, 0b00011, 0b00111, 0b01001, 0b11011, 0b10110, 0b11111,
0b10000, 0b01110, 0b11011, 0b10110, 0b11111, 0b01001, 0b00001]
m = dec(c)
print(m)
if __name__ == '__main__':
main()
ok
题目链接。描述: Ook.。那就Ook解码一下,github上有个项目gil9red/Ook: Ook! Interpreter (Python),推荐使用。解码得到 flag{0a394df55312c51a}
小山丘的秘密
题目链接。描述: hill能有什么秘密呢。附件有2个。flag.txt的内容如下,小山丘的秘密.jpg图片如下
bugku{PLGTGBQHM}
其中A=1,flag全为小写
hill音译为希尔,也就是希尔密码。密文为PLGTGBQHM,加密矩阵如棋盘,通过如下代码可以解密,自己转小写即可 bugku{whatahill}
"""
希尔密码是运用基本矩阵论原理的替换密码,由Lester S. Hill在1929年发明。
每个字母当作26进制数字:A=0, B=1, C=2... 一串字母当成n维向量,跟一个n×n的矩阵相乘,再将得出的结果模26。
(注意用作加密的矩阵(即密匙)在 必须是可逆的,否则就不可能解码。只有矩阵的行列式和26互质,才是可逆的。)
"""
import numpy as np
def string_to_array(string, size, offset):
string = string.upper()
blocks = [string[i:i + size] for i in range(0, len(string), size)]
if len(blocks[-1]) != size: # 补齐成矩阵
blocks[-1] = blocks[-1].ljust(size, chr(ord('A') - offset))
arr = np.array([list(map(ord, block)) for block in blocks]) - ord(
'A') + offset
return arr
def encode(encryptor, string, offset=0):
'''
希尔加密
:param encryptor: 加密矩阵
:param string: 明文
:param offset: 默认A=0
:return: 密文
'''
assert encryptor.ndim == 2 and encryptor.shape[0] == encryptor.shape[1]
arr = string_to_array(string, encryptor.shape[0], offset) # 字符串转数字矩阵
result = (encryptor @ arr.T).T % 26 + ord('A') - offset # 算法
result = ''.join(map(chr, result.ravel())) # 数字矩阵转字符串
return result
def decode(decryptor, string, offset=0):
'''
希尔解密,算法和加密一样
:param decryptor: 解密矩阵
:param string: 密文
:param offset: 默认A=0
:return: 明文
'''
assert decryptor.ndim == 2 and decryptor.shape[0] == decryptor.shape[1]
arr = string_to_array(string, decryptor.shape[0], offset) # 字符串转数字矩阵
result = (decryptor @ arr.T).T % 26 + ord('A') - offset # 算法
result = ''.join(map(chr, map(int, result.ravel()))) # 数字矩阵转字符串
return result
if __name__ == '__main__':
en_matrix = np.array([[1, 2, 3], [0, 1, 4], [5, 6, 0]])
de_matrix = np.array(np.linalg.inv(en_matrix), dtype=int)
c_msg = 'PLGTGBQHM'
m_msg = decode(de_matrix, c_msg, offset=1) # Bugku题目说A=1,就是offset=1
print(m_msg)
next
题目链接。