攻防世界 CRYPTO Railfence python脚本

题目为栅栏密码的W变种,原理如下

W变种

1 2 3 4 5 6 7 8 9 0 # key=3 Rail-fence Cipher

1 .. .. .. 5 .. .. .. 9 .. ↘            ↗            ↗

.. 2 .. 4 .. 6 .. 8 .. 0     ↘    ↗    ↘    ↗    ↘

.. .. 3 .. .. .. 7 .. .. ..         ↘            ↘

结果为 1 5 9 2 4 6 8 0 3 7

代码

码是自己边想边写的,调bug调了整一天... 应该是没有什么致命的bug了,至少解题是没问题的。

思路主要是以如“1234”“5678”这样的V字为循环体,先按行拆解成列表形式,再进行拼接。

比较关键的点是根据最后一个可能不完整的“V”,如“90”,进行分类讨论。

大概不是最优的解法吧... 有dalao路过的话,看看有没有什么更好的思路吧。

# D:\Work\code_of_python3.9.7\栅栏密码_W.py

# 解密函数,形参为密文和秘钥(可重复尝试秘钥进行爆破)
def Railfence_W_Decode(str, key):
    # 解密关键思路:
    # 密文中的每个“V”的字节长度为2key-2

    tmp = ''

    # 先算出一些关键的数据
    len_of_v = 2 * key - 2
    len_of_str = len(str)
    num_of_v = len_of_str // len_of_v # 密文一共包含了几个完整的V,也就是第一行的长度(除了最后一个v)
    len_of_last_v = len_of_str % len_of_v # 最后一个V的长度
    
    # 先把每一行抽出来
    list = [''] * key
    
    # 第一行
    if len_of_last_v > 0: # 判断一下最后一个不完整的“V”到底存不存在
        len_of_hang_i = num_of_v + 1
        list[0] = str[0:len_of_hang_i]
    else:
        len_of_hang_i = num_of_v
        list[0] = str[0:len_of_hang_i]

    # 第二行到第n-1行
    if len_of_last_v <= key: # 分类讨论:最后一个“V”有没有反折,会影响中间第二至第n-1行的长度
        for i in range(1, key - 1):
            if i < len_of_last_v: 
            # 在最后一个“V”不反折的情况下,受到影响的几行要从密文中多拿1位
                len_of_hang_i1 = 2 * num_of_v + 1
            else:
                len_of_hang_i1 = 2 * num_of_v
            
            list[i] = str[len_of_hang_i:len_of_hang_i + len_of_hang_i1] # 扣出第i行字符串
            len_of_hang_i += len_of_hang_i1 # 把下标放到下一次循环的开始
    else:
        for i in range(1, key - 1):
            if len_of_v - i < len_of_last_v: 
            # 在最后一个“V”反折的情况下,受到一次影响的几行要从密文中多拿1位,受到两次影响的要多拿2位
                len_of_hang_i1 = 2 * num_of_v + 2
            else:
                len_of_hang_i1 = 2 * num_of_v + 1

            list[i] = str[len_of_hang_i:len_of_hang_i + len_of_hang_i1] # 同上
            len_of_hang_i += len_of_hang_i1 # 同上

    # 第n行
    list[key - 1] = str[len_of_hang_i:]

    # 正式开始解密,把得出的V一个一个拼上去
    # 忽略最后一个“V”的越界问题,用try解决
    for i in range(num_of_v + 1):
        try:
            tmp += list[0][i]
        except IndexError:
            pass
        for l in range(1, key - 1):
            try:
                tmp += list[l][2 * i]
            except IndexError:
                pass
        try:
            tmp += list[key-1][i]
        except IndexError:
            pass
        for l in range(1, key - 1):
            try:
                tmp += list[key - 1 - l][2 * i + 1]
            except IndexError:
                pass

    return tmp

# 加密函数,形参为密文和秘钥(可重复尝试秘钥进行爆破)
def Railfence_W_Encode(str, key):
    tmp = ''
    list = [''] * key
    len_of_v = 2 * key - 2 # 老样子,计算一个“V”的长度

    # 拆分为list:双指针取数,第一个指针确定区第几行,第二个指针在每一行进行移动取数
    # 第一行
    index = 0
    while index < len(str): 
        list[0] += str[index]
        index += len_of_v

    # 第二行到第n-1行
    for i in range(1, key - 1):
        index = i
        while index < len(str): 
            list[i] += str[index]
            index_2 = (index - i) + (len_of_v - i)
            if index_2 < len(str): 
            # 防止在最后一个“V”越界
                list[i] += str[index_2]
            index += len_of_v
    
    # 最后一行
    index = key - 1
    while index < len(str): 
        list[key - 1] += str[index]
        index += len_of_v

    # list再拼接成tmp
    for i in range(key):
        tmp += list[i]

    return tmp

# 下面是自由调整部分

# 解密
# str_code = '1592468037'
# key_code = 3
str_code = r'ccehgyaefnpeoobe{lcirg}epriec_ora_g'
key_code = 5
tmp_decode = Railfence_W_Decode(str_code, key_code)
print(tmp_decode)

# 爆破
# for i in range(2, len(str_code) + 1):
#     tmp_decode = Railfence_W_Decode(str_code, i)
#     print(tmp_decode)

# 加密
str = r'cyberpeace{railfence_cipher_gogogo}'
key = 5
# str = '1234567890'
# key = 3
tmp_encode = Railfence_W_Encode(str, key)
print(tmp_encode)

# 爆破(虽然加密并不怎么需要爆破)
# for i in range(2, len(str) + 1):
#     tmp_encode = Railfence_W_Encode(str, i)
#     print(tmp_encode)

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值