[BSidesSF2020]decrypto-1
题目
Kerckhoffs’s principle states that “A cryptosystem should be secure even if everything about the system, except the key, is public knowledge.” So here’s our unbreakable cipher.
import sys
import json
import hashlib
class Crypto:
def __init__(self, key):
if not isinstance(key, bytes):
raise TypeError('key must be of type bytes!')
self.key = key
self._buf = bytes()
self._out = open("/dev/stdout", "wb")
def _extend_buf(self):
self._buf += self.key
def get_bytes(self, nbytes):
while len(self._buf) < nbytes:
self._extend_buf()
ret, self._buf = self._buf[:nbytes], self._buf[nbytes:]
return ret
def encrypt(self, buf):
if not isinstance(buf, bytes):
raise TypeError('buf must be of type bytes!')
stream = self.get_bytes(len(buf))
return bytes(a ^ b for a, b in zip(buf, stream))
def set_outfile(self, fname):
self._out = open(fname, "wb")
def encrypt_file(self, fname):
buf = open(fname, "rb").read()
self._out.write(self.encrypt(buf))
class JSONCrypto(Crypto):
def encrypt_file(self, fname):
buf = open(fname, "r").read().strip()
h = hashlib.sha256(buf.encode('utf-8')).hexdigest()
data = {
"filename": fname,
"hash": h,
"plaintext": buf,
}
outbuf = json.dumps(data, sort_keys=True, indent=4)
self._out.write(self.encrypt(outbuf.encode("utf-8")))
def main(argv):
if len(argv) not in (3, 4):
print("%s <key> <infile> [outfile]" % sys.argv[0])
return
argv.pop(0)
key = argv.pop(0)
inf = argv.pop(0)
crypter = JSONCrypto(key.encode("utf-8"))
if sys.argv:
crypter.set_outfile(argv.pop(0))
crypter.encrypt_file(inf)
if __name__ == '__main__':
main(sys.argv)
flag.txt.enc
:TL\Z\QETVRQ
SIH fGNV\\\ETV[UVQU
] A_]UC^ QWZC _RY@QYRU_[@^^[CfGNVDQ
] U@VE-d2OM N8
_@boFbC 1SMM[L:
解题
科克霍夫斯原理声明“密码系统应该是安全的,即使系统的所有内容,除了密钥,都是公共知识。”所以这里是我们的牢不可破的密码。
牢不可破的密码,那就可能是一次一密了。
先读程序:
sys.argv[]是一个从程序外部获取参数的桥梁,因为我们从外部取得的参数可以是多个,所以获得的是一个列表,也就是说sys.argv其实可以看作是一个列表,所以才能用[]提取其中的元素。其第一个元素是程序本身,sys.argv[0]表示代码本身文件路径,随后才依次是外部给予的参数。
pop() 函数用于移除列表中的一个元素(默认最后一个元素),并且返回该元素的值。
hash.hexdigest() 返回摘要,作为十六进制数据字符串值。
json.dumps()将一个Python数据结构转换为JSON对象,indent:参数根据数据格式缩进显示,读起来更加清晰,skipkeys:默认值是False,如果dict的keys内的数据不是python的基本类型(str,unicode,int,long,float,bool,None),设置为False时,就会报TypeError的错误。此时设置成True,则会跳过这类key 。
import json
data = {
"filename": 'flag.txt',
"hash": 'h',
}
outbuf = json.dumps(data, sort_keys=True, indent=4)
cipher_pre=open('flag.txt.enc','rb').read()
for i in range(43):
print(chr(cipher_pre[i]^ord(outbuf[i])))
#得到key
key='n0t4=l4g'
for i in range(8):
key+=key
#使key足够长.
flag=''
for i in range(len(cipher_pre)):
flag+=chr(ord(key[i])^cipher_pre[i])
print(flag)
运行得到:
{
"filename": "flag.txt",
"hash": "2f98b8afa014bf955533a3e72cee0417413ff744e25f2b5b5838f5741cd69547",
"plaintext": "CTF{plz_dont_r0ll_ur_own_crypto}"
}
答案
flag{plz_dont_r0ll_ur_own_crypto}