现代密码学实验

类维吉尼亚破解

题目要求:将维吉尼亚中移位的加密方式换成了异或,要求对密文进行破解。
解法:遍历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))
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值