类维吉尼亚破解
题目要求:将维吉尼亚中移位的加密方式换成了异或,要求对密文进行破解。
解法:遍历key
的长度,需要满足将明文分组后,每组相同位置处异或key
的结果都要为合法字符。得到可能的长度与相对应的字符集。依此条件排除了不可能的长度,也分别求出了每一位上的可选字符。
import string
#valid=string.ascii_letters+string.punctuation+' '
valid=string.ascii_letters+",. "
cipher0='F96DE8C227A259C87EE1DA2AED57C93FE5DA36ED4EC87EF2C63AAE5B9A7EFFD673BE4ACF7BE8923CAB1ECE7AF2DA3DA44FCF7AE29235A24C963FF0DF3CA3599A70E5DA36BF1ECE77F8DC34BE129A6CF4D126BF5B9A7CFEDF3EB850D37CF0C63AA2509A76FF9227A55B9A6FE3D720A850D97AB1DD35ED5FCE6BF0D138A84CC931B1F121B44ECE70F6C032BD56C33FF9D320ED5CDF7AFF9226BE5BDE3FF7DD21ED56CF71F5C036A94D963FF8D473A351CE3FE5DA3CB84DDB71F5C17FED51DC3FE8D732BF4D963FF3C727ED4AC87EF5DB27A451D47EFD9230BF47CA6BFEC12ABE4ADF72E29224A84CDF3FF5D720A459D47AF59232A35A9A7AE7D33FB85FCE7AF5923AA31EDB3FF7D33ABF52C33FF0D673A551D93FFCD33DA35BC831B1F43CBF1EDF67F0DF23A15B963FE5DA36ED68D378F4DC36BF5B9A7AFFD121B44ECE76FEDC73BE5DD27AFCD773BA5FC93FE5DA3CB859D26BB1C63CED5CDF3FE2D730B84CDF3FF7DD21ED5ADF7CF0D636BE1EDB79E5D721ED57CE3FE6D320ED57D469F4DC27A85A963FF3C727ED49DF3FFFDD24ED55D470E69E73AC50DE3FE5DA3ABE1EDF67F4C030A44DDF3FF5D73EA250C96BE3D327A84D963FE5DA32B91ED36BB1D132A31ED87AB1D021A255DF71B1C436BF479A7AF0C13AA14794'
cipher='Sy l nlx sr pyyacao l ylwj eiswi upar lulsxrj isr sxrjsxwjr, ia esmm wctjsxsza sj wmpramh, lxo txmarr jia aqsoaxwa sr pqaceiamnsxu, ia esmm caytra jp famsaqa sj. Sy, px jia pjiac ilxo, ia sr pyyacao rpnajisxu eiswi lyypcor l calrpx ypc lwjsxu sx lwwpcolxwa jp isr sxrjsxwjr, ia esmm lwwabj sj aqax px jia rmsuijarj aqsoaxwa. Jia pcsusx py nhjir sr agbmlsxao sx jisr elh. -Facjclxo Ctrramm'
for j in range(len(cipher0)//2):
cipher+=chr(int(cipher0[j*2:j*2+2],16))
cipher=''
def find_key_pool(cipher):
# 分组后相同位置的十六进制异或key都要为valid
key_pool=[i for i in range(0xff+1)]
ret=key_pool.copy()
for i in key_pool:
for ch in cipher:
if chr(i^ord(ch)) not in valid:
ret.remove(i)
break
return ret
for length in range(1,14):
key=[]
new_key=None
for block_index in range(len(cipher)//length):
new_key=find_key_pool(cipher[block_index::length])
if not new_key:
break
key.append(new_key)
print(length)
if new_key:
print('len=',length,'key=',set(key))
key=[186,31,145,178,83,205,62]
m=''.join([chr(key[i%7]^ord(cipher[i]))for i in range(len(cipher))])
print(m)
密码挑战
地址
目标:破解一次多密。
过程:算出不同长度下的汉明距离,使汉明距离最小的值就是密钥长度,根据前文类似方法进行破解。
from base64 import b64decode
from string import *
def bit_count(num):
count=0
for i in range(8):
# 一个字节最多有8个1
count+=num&1
num=num>>1
return count
def distance(s1,s2):
num=0
for i in range(len(s1)):
number=ord(s1[i])^ord(s2[i])
num+=bit_count(number)
return num
def fixed_xor(s1,s2):
xor_str=''
for i in range(len(s1)//2):
xor_str+=hex(int(s1[2*i:2*i+2],16)^int(s2[2*i:2*i+2],16))[2:]
return xor_str
def hexlify(cipher0):
# 将cipher0从16进制转为char
cipher=''
for j in range(len(cipher0)//2):
cipher+=chr(int(cipher0[j*2:j*2+2],16))
return cipher
def unhexlify(cipher):
# 将cipher0从char转为16进制
cipher_hex=''
for index in range(len(cipher)):
cipher_hex+='%02x'%(ord(cipher[index]))
return cipher_hex
def find_message(cipher):
# 单字节爆破
for key in range(0xff+1):
m=''
flag=1
for index in range(len(cipher)):
if chr(ord(cipher[index])^key) in ascii_letters+',.\' \n-!'+digits:
m+=chr(ord(cipher[index])^key)
else:
flag=0
break
if flag:
return m
with open('6.txt','r') as f:
cipher=b64decode(f.read().replace('\n','').encode()).decode()
distances=[]
for length in range(2,41):
distance_current=0
for block_index in range(len(cipher)//length-1):
distance_current+=distance(cipher[block_index*length:(block_index+1)*length],cipher[(block_index+1)*length:(block_index+2)*length])/length
distances.append(distance_current/(len(cipher)//length-1))
key_len=3
distance_min=distances[1]
for length,distance_current in enumerate(distances):
if distance_current<distance_min:
key_len=length+2
distance_min=distance_current
block=[]
for block_index in range(key_len):
temp=find_message(cipher[block_index::key_len])
if temp:
block.append(temp)
message=''
for index in range(key_len):
message+=''.join(item[index] for item in block)
print(message)
print('key:',hexlify(fixed_xor(unhexlify(message[:29]), unhexlify(cipher[:29]))))
破解sha-1散列的密码
题目给出了键盘按键和密码散列后的结果,要求找出密码。
上网学习键盘对应的字符,列出可能的字符集合进行爆破。大胆猜测每个按键只按一次,再大胆猜测密码长度是8
from itertools import combinations, permutations
# from multiprocessing import Pool
from time import time
from hashlib import sha1
select0='+*=(%245680qQwWIiNn'
perm=combinations(select0,8)
start=time()
for i in perm:
for j in permutations(i):
temp=''.join(z for z in j)
if sha1(temp.encode()).hexdigest()=='67ae1a64661ac8b4494666f58c4822408dd0a3e4':
print(temp)
end=time()
print(end-start,'s')
break
填充攻击
题目要求:客户端发送密文,服务器进行解密,若解出的明文不符合填充规则,返回不能解密,否则返回成功。密文格式:密文块数 | 初始向量 | 第一块加密结果 | …
要求根据给出的IV和两个密文块解出明文。
过程:通过对IV的爆破观察解密情况,若成功解密说明填充成功。使得明文填充依次为1-0x10,这时我们便获得了两个中间值,从而得到了明文。
from pwn import *
if args.G:
p=remote("128.8.130.16", 49101)
else:
pass
# context(os='linux',arch='amd64',log_level='debug')
s = lambda data :p.send(str(data))
mask=lambda n:n*('%02x'%(n))
def hexlify(cipher0):
cipher=''
for j in range(len(cipher0)//2):
cipher+=chr(int(cipher0[j*2:j*2+2],16))
return cipher
def fill(num):
return '%02x'%(num)
def fixed_xor(s1,s2):
xor_str=''
if len(s1)>len(s2):
for i in range(len(s2)//2):
xor_str+=fill(int(s1[2*i:2*i+2],16)^int(s2[2*i:2*i+2],16))
return xor_str
else:
for i in range(len(s1)//2):
xor_str+=fill(int(s1[2*i:2*i+2],16)^int(s2[2*i:2*i+2],16))
return xor_str
def re(hex_str):
s=''
for i in range(len(hex_str)//2):
s+=chr(int(hex_str[2*i:2*i+2],16))
s=s[::-1]
ret=''
for i in s:
ret+=fill(ord(i))
return ret
blocks=[
'9F0B13944841A832B2421B9EAF6D9836',
'813EC9D944A5C8347A7CA69AA34D8DC0',
'DF70E343C4000A2AE35874CE75E64C31'
]
def blast(cipher):
#iv=''
#mid='16f6'
#iv='14'
mid=''
iv=''
try:
for index in range(1,17):
for i in range(0x1,0xff+1):
sleep(0.1)
log.info((iv+fill(i)).ljust(32,'0'))
s('\x02'+hexlify(re((iv+fill(i)).ljust(32,'0')))+hexlify(cipher)+'\0')# block,fake iv
if '0' in p.recv():
continue
else:
print 'hhh'
mid+=fill(i^(index))
log.info('mask: '+mask(index))
log.info('mid: '+mid)
iv=fixed_xor(mid[:index*2],mask(index+1))
log.info('iv: '+iv)
break
except EOFError:
log.info('mid: '+mid)
return mid
mid1=blast(blocks[1])
# mid1='16f60c8fea7e259247c71868b56a6ac6'
m1=fixed_xor(re(mid1),blocks[0])
# mid2=blast(blocks[2])
# mid2='cb8646a891ad77713fc3ae6de4e910c0'
m2=fixed_xor(blocks[1],re(mid2))
log.info('mid1: '+mid1)
# log.info('mid2: '+mid2)
print hexlify(m1+m2)
这玩意儿太艰辛了我一定要放张截图
密码挑战
Byte-at-a-time ECB decryption(harder)
import base64
import Crypto.Random
import Crypto.Random.random
from Crypto.Cipher import AES
def G(key_length):
return Crypto.Random.get_random_bytes(key_length)
def xor_string(input_bytes_1,input_bytes_2):
return bytes([x^y for x,y in zip(input_bytes_1,input_bytes_2)])
def same_length(b1,b2):
count=0
xor = xor_string(b1,b2)
for i in xor:
if i==0:
count+=1
else:
break
return count
def pad(data,block_size):
padding_size = block_size - len(data)%block_size
if padding_size == 0:
padding_size = block_size
padding = (chr(padding_size)*padding_size).encode()
return data+padding
def AES_ECB_encode(plaintext_b, key_b):
cipher = AES.new(key_b, AES.MODE_ECB)
ciphertext = cipher.encrypt(plaintext_b)
return ciphertext
def determine_block_size():
data = b''
initial_length = len(enc(data))
while True:
data += b'A'
result_length = len(enc(data))
if result_length != initial_length:
break
block_size = result_length - initial_length
return block_size
def enc(data):
s = '''Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWctdG9wIGRvd24gc28gbXkg
aGFpciBjYW4gYmxvdwpUaGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBq
dXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5vLCBJIGp1c3QgZHJvdmUg
YnkK'''
suffix = base64.b64decode(s.encode())
data_to_encrypt = pad(pre + data + suffix, block_size)
ciphertext = AES_ECB_encode(data_to_encrypt, key)
return ciphertext
def find_padding_size(block_size):
data = b''
cipher_of_pre = enc(data)
data += b'A'
block_num = same_length(cipher_of_pre,enc(data))//block_size
while True:
data+=b'A'
cipher_of_A = enc(data)
same_block_num = same_length(cipher_of_pre, cipher_of_A)//block_size
if same_block_num != block_num:
break
else:
cipher_of_pre = cipher_of_A
return same_block_num*block_size-len(data)+1
def decrypt_byte(block_size, presize, decrypted_message):
length = block_size - ((1 + len(decrypted_message)+presize) % block_size)
try_length = presize + length + (len(decrypted_message) + 1)
dict = {}
for chr in range(256):
test_data = b"A"*(length) + decrypted_message + bytes([chr])
c = enc(test_data)
dict[c[:try_length]] = chr
compare = enc(b"A"*(length))[:try_length]
m = bytes([dict.get(compare, 0)])
return m
def func():
block_size = determine_block_size()
size = find_padding_size(block_size)
print("assume_block_size: {}".format(block_size))
print("prefix_padding_size: {}".format(size))
length = len(enc(b''))
found_string = b''
for i in range(length):
found_string += decrypt_byte(block_size, size, found_string)
print(found_string.decode())
block_size = AES.block_size
key = G(16)
pre = G(Crypto.Random.random.randint(1,32))
func()
PKCS#7 padding validation
检查字符串是否为有效的PKCS#7填充。
def PaddingError(Exception):
pass
def check_pad(s):
for num in range(1,17):
if s[-1]==chr(num):
if s[-num:]==num*chr(num):
return True
else:
raise PaddingError
raise PaddingError
s='s'+'\x0f'*0xf
print(check_pad(s))
CBC bit flipping attacks
import Crypto
from Crypto.Cipher import AES
import re
prepend = b"comment1=cooking%20MCs;userdata="
append = b";comment2=%20like%20a%20pound%20of%20bacon"
class PaddingError(Exception):
pass
def pad(m, size):
if len(m) % size == 0:
return m
padding = size - len(m) % size
padValue = bytes([padding]) * padding
return m + padValue
def valid(padded, block_size):
if len(padded) % block_size != 0:
# 填充长度不正确
return False
ch = padded[-1]
if ch >= block_size:
return False
padding = bytes([ch]) * ch
if padded[-ch:] != padding:
return False
if not padded[:-ch].decode('ascii').isprintable():
return False
return True
def unpad(padding, block_size):
if not valid(padding, block_size):
raise PaddingError
ch = padding[-1]
m = padding[:-ch]
return m
punctuation = {b';': b'%3B', b'=': b'%3D'}
KEY = Crypto.Random.new().read(AES.block_size)
IV = bytes(AES.block_size)
def cbc_encrypt(m):
for key in punctuation:
m = re.sub(key, punctuation[key], m)
plaintext = prepend + m + append
plaintext = pad(plaintext, AES.block_size)
cipher = AES.new(KEY, AES.MODE_CBC, IV)
ciphertext = cipher.encrypt(plaintext)
return ciphertext
def check(ciphertext):
cipher = AES.new(KEY, AES.MODE_CBC, IV)
plaintext = cipher.decrypt(ciphertext)
print(f"Plaintext: { plaintext }")
if b";admin=true;" in plaintext:
return True
return False
text = b'A' * AES.block_size * 2
print(AES.block_size)
c = cbc_encrypt(text)
print(len(c))
q = pad(b";admin=true;", AES.block_size)
i = bytes([r ^ ord('A') for r in q])
extra = len(c) - len(i) - len(prepend)
i = bytes(2 * AES.block_size) + i + bytes(extra)
ret = bytes([x ^ y for x, y in zip(c, i)])
if check(ret):
print("Admin Found")
else:
print("Admin Not Found")
MTC3 AES key
from hashlib import *
from binascii import *
from base64 import *
from Crypto.Util.number import *
from Crypto.Cipher import AES
def unhexlify(cipher):
cipher_hex=''
for i in range(len(cipher)):
cipher_hex+='%02x'%(ord(cipher[i]))
return cipher_hex
def calc(x):
d=[]
s=bin(int(x,16))[2:]
for i in range(0,len(s),8):
d.append(s[i:i+7])
if (s[i:i+7].count("1"))%2 == 0:
d.append('1')
else :
d.append('0')
ret=hex(int(''.join(d),2))
return ret[2:]
passport='12345678<8<<<1110182<111116?<<<<<<<<<<<<<<<4'
cipher=b'9MgYwmuPrjiecPMx61O6zIuy3MtIXQQ0E59T3xB6u0Gyf1gYs2i3K9Jxaa0zj4gTMazJuApwd6+jdyeI5iGHvhQyDHGVlAuYTgJrbFDrfB22Fpil2NfNnWFBTXyf7SDI'
cipher=b64decode(cipher)
a=passport[21:27]
b=[7,3,1]
mid=0
for i in range(len(a)):
mid += int(a[i]) * b[i%3]
mid %= 10
passport=passport[:27] + str(mid) + passport[28:]
temp=passport[:10] + passport[13:20] + passport[21:28]
seed=sha1(temp.encode()).hexdigest()[:32]
seed += '00000001'
key=sha1(unhexlify(seed)).hexdigest()
key1=calc(key[:16])
key2=calc(key[16:32])
key=unhexlify(key1+key2)
aes=AES.new(key,iv=b'\x00'*16,mode=AES.MODE_CBC)
print(aes.decrypt(cipher))