vigenere-like cipher

vigenere-like cipher

设密文为 c c c,密钥为 k k k,则密文为 c ⊕ k c \oplus k ck

首先,题干中所说的维吉尼亚-like是指将密钥复制为和明文一样长(多出来的删除掉),然后进行异或运算。

因此,结合one-time pad的思想,可知利用密钥和密文进行异或,便得到明文。

题干中提到“明文包含大写字母、小写字母、标点符号和空格,但不包含数字”,因此可以枚举密钥,然后将密钥和密文进行异或,得到的结果中,如果有数字,则说明该密钥不正确。据此暴力找出密钥。

c = "F96DE8C227A259C87EE1DA2AED57C93FE5DA36ED4EC87EF2C63AAE5B9A7EFFD673BE4ACF7BE8923CAB1ECE7AF2DA3DA44FCF7AE29235A24C963FF0DF3CA3599A70E5DA36BF1ECE77F8DC34BE129A6CF4D126BF5B9A7CFEDF3EB850D37CF0C63AA2509A76FF9227A55B9A6FE3D720A850D97AB1DD35ED5FCE6BF0D138A84CC931B1F121B44ECE70F6C032BD56C33FF9D320ED5CDF7AFF9226BE5BDE3FF7DD21ED56CF71F5C036A94D963FF8D473A351CE3FE5DA3CB84DDB71F5C17FED51DC3FE8D732BF4D963FF3C727ED4AC87EF5DB27A451D47EFD9230BF47CA6BFEC12ABE4ADF72E29224A84CDF3FF5D720A459D47AF59232A35A9A7AE7D33FB85FCE7AF5923AA31EDB3FF7D33ABF52C33FF0D673A551D93FFCD33DA35BC831B1F43CBF1EDF67F0DF23A15B963FE5DA36ED68D378F4DC36BF5B9A7AFFD121B44ECE76FEDC73BE5DD27AFCD773BA5FC93FE5DA3CB859D26BB1C63CED5CDF3FE2D730B84CDF3FF7DD21ED5ADF7CF0D636BE1EDB79E5D721ED57CE3FE6D320ED57D469F4DC27A85A963FF3C727ED49DF3FFFDD24ED55D470E69E73AC50DE3FE5DA3ABE1EDF67F4C030A44DDF3FF5D73EA250C96BE3D327A84D963FE5DA32B91ED36BB1D132A31ED87AB1D021A255DF71B1C436BF479A7AF0C13AA14794"
cArr = [int(c[i:i+2], 16) for i in range(0, len(c), 2)] # 16进制转10进制:[249, 109, ...]
print(len(cArr))

correctChar = []
for x in range(32,126):
    correctChar.append(x)
for x in range(48, 58): # 不包含数字
    correctChar.remove(x)

def findindexkey(subarr): # 该函数可以找出将密文subarr解密成可见字符的所有可能值
    test_keys=[]# 用于测试密钥
    ans_keys=[]# 用于结果的返回
    for x in range(0x00,0xFF):# 枚举密钥里所有的值
        test_keys.append(x)
        ans_keys.append(x)
    for i in test_keys: # 对于0x00~0xFF里的每一个数i和subarr里的每个值s异或
        for s in subarr:
            if s^i not in correctChar: # 用i解密s,如果解密后明文不是可见字符,说明i不是密钥
                ans_keys.remove(i) # 去掉ans_keys里测试失败的密钥
                break
    return ans_keys
def findKeySpace(maxLen=14):
    keySpace = []
    for keylen in range(1,maxLen): # 枚举密钥的长度1~14
        for index in range(0,keylen): # 对密钥里的第index个进行测试
            subarr=cArr[index::keylen] # 每隔keylen长度提取密文的内容,提取出来的内容都被密文的第index个加密
            ans_keys=findindexkey(subarr) # 找出密钥中第index个的可能的值
            if ans_keys:
                print('keylen=',keylen,'index=',index,'keys=',ans_keys)
                keySpace.append(ans_keys) # 将所有可能的值存入keySpace
    return keySpace
# 得出结论,密钥长度为 7
keySpace = findKeySpace()
cnt = 1
for i in range(len(keySpace)):
    print('in index ', i, 'key space size is ', len(keySpace[i]))
    cnt *= len(keySpace[i])
print('total key space size is ', cnt)
# 结果是 497664,可以暴力枚举
# 枚举所有可能的密钥,长度为 7 
hh = []
def enumKey(keySpace):
    for i in keySpace[0]:
        for j in keySpace[1]:
            for k in keySpace[2]:
                for l in keySpace[3]:
                    for m in keySpace[4]:
                        for n in keySpace[5]:
                            for o in keySpace[6]:
                                key = [i,j,k,l,m,n,o]
                                hh.append(key)
enumKey(keySpace)
ansSpace = []
for key in hh:
    ansSpace.append(''.join([chr(cArr[i]^key[i%7]) for i in range(len(cArr))]))
# 输出为txt文件
with open('ans.txt', 'w') as f:
    for ans in ansSpace:
        f.write(ans+'\n')
import string
# 不妨缩小一下明文范围:大写字母,小写字母,空格,逗号,句号,问号,感叹号
testString = string.ascii_letters + ' ,.?!'
correctChar = [ord(x) for x in testString]
keySpace = findKeySpace()

# 此时解唯一,密钥为:[186, 31, 145, 178, 83, 205, 62]
# 解密时刻
keyLen = 7
for i in range(len(cArr)):
    print(chr(cArr[i] ^ keySpace[i % keyLen][0]), end='')
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值