三铁解密

时间:2013-10-03 00:00:24

标签: python

我在试图找出如何让我的解密功能工作时遇到了很多麻烦。它适用于msg可以被3整除的理想情况,但之后我完全迷失了。我对我必须做的事情有一个模糊的想法,因为我能够使用两个轨道来实现这一点,但是有三个轨道的可能性更大。我很丢失:(所有那些印刷声明只是试图帮我弄清楚我的程序中发生了什么。

import sys

def main():
    plaintext="abcdefgh"
    print(threeRailEncrypt(plaintext))
    print(threeRailDecrypt(threeRailEncrypt(plaintext)))


def threeRailEncrypt(plaintext):
    ciphertext=""
    rail1=""
    rail2=""
    rail3=""

    for i in range(len(plaintext)):
        if i%3 == 0:
            rail1=rail1+plaintext[i]
        elif i%3 == 1:
            rail2=rail2+plaintext[i]
        else:
            rail3=rail3+plaintext[i]

    ciphertext=rail1+rail2+rail3

    return(ciphertext)

def threeRailDecrypt(msg):
    if len(msg)%3==0:
        third=len(msg)//3
        print(third)
        rail1=msg[:third]
        rail2=msg[third:third*2]
        rail3=msg[third*2:]
        print(rail1,rail2,rail3)
        dm=""
        for i in range(third):
            dm=dm+rail1[i]
            dm=dm+rail2[i]
            dm=dm+rail3[i]
    else:
        third=(len(msg)//3)+1
        print(third)
        rail1=msg[:third]
        rail2=msg[third:third*2]
        rail3=msg[third*2:]
        print(rail1,rail2,rail3)
        dm=""
        for i in range(third):
            dm=dm+rail1[i]
            print(dm)
            dm=dm+rail2[i]
            print(dm)
            dm=dm+rail3[i]
            print(dm)
            if  len(rail2)>len(rail3):
                dm=dm+rail2[-1]
        return(dm)
main()

进展 -

def threeRailDecrypt(cypher, rails = 3):
    length = len (cypher)
    for i in range(rails):
        lens=(length//rails)
        if length % rails > i:
            lens=lens+1
        print(lens)

3 个答案:

答案 0 :(得分:1)

你必须像在加密函数中那样再次拆分字符串,然后迭代它们以将每个字符放回到它的真实位置。

def decrypt(crypt):
    rails = []
    result = ""
    rails.append(crypt[:(len(crypt)+2)/3])
    rails.append(crypt[(len(crypt)+2)/3:-(len(crypt)-2)/3])
    rails.append(crypt[-(len(crypt)/3):])
    for x in range(len(crypt)):
        result += rails[x%3][:1]
        rails[x%3] = rails[x%3][1:]
    return(result)

我认为Hyperboreus第二种解决方案虽然更酷!

OLD (有趣的想法与评论相关,但是对于较长的字符串,这些效果并不正常):

你只需要反转你在加密中做的事情,所以在加密中你通过用模3分解文本来加扰文本。再次获得明文的最简单方法就是简单地运行加密方法字符串减去加密字符串的两次,它将返回纯文本。

def threeRailDecrypt(crypt):
    for i in range(len(crypt)-2):
        crypt = threeRailEncrypt(crypt)
    return(crypt)

Hyperboreus解决方案是正确的,但我认为这有点简单了。

字符串测试示例:

  

测试 - 未触动

     

ttes - 第一次迭代(加密)

     

tste - 第二次迭代

     

测试 - 第三次迭代

答案 1 :(得分:1)

我将使用完全不同的方法和更明确的代码添加第二个答案:

def dec2 (cypher):
    length = len (cypher)
    if length < 4: return cypher
    third = length // 3 + (1 if length % 3 else 0)
    cypher = list (cypher)
    if length % 3 == 1: cypher.insert (third * 2 - 1, '')
    return ''.join (''.join (cypher [i::third] ) for i in range (third) )

或者只是震惊你的老师:

enc = lambda p:''.join(p[_::3]for _ in range(3))
dec = lambda c:c if len(c)<4 else(lambda *a:(lambda c,t:
''.join(''.join(c[i::t])for i in range(t)))((lambda c,t,
l:c[:t*2-1]+(['']if l%3==1 else[])+c[t*2-1:])(*a),a [2])
)(*(lambda c:(list(c),len(c),len(c)//3+(1 if len(c)%3
else 0)))(c))

答案 2 :(得分:0)

这应该有效。您只需要弄清楚不同的导轨有多长:

from itertools import zip_longest as zip

def enc (plain, rails = 3):
    return ''.join (plain [i::rails] for i in range (rails) )

def dec (cypher, rails = 3):
    length = len (cypher)
    lens = [length // rails + (1 if length % rails > i else 0) for i in range (rails) ]
    paths = [cypher [sum (lens [:i] ):sum (lens [:i + 1] ) ] for i in range (rails) ]
    return ''.join (''.join (x for x in x if x) for x in zip (*paths) )

plain = 'abcdefghijk'
for i in range (10):
    a = plain [:i]
    b = enc (a)
    c = dec (b)
    print (a, b, c)

应该使用任意(> 0)个数量的轨道。


编辑:没有zip_longest:

def enc (plain, rails = 3):
    return ''.join (plain [i::rails] for i in range (rails) )

def dec (cypher, rails = 3):
    length = len (cypher)
    lens = [length // rails + (1 if length % rails > i else 0) for i in range (rails) ]
    paths = [cypher [sum (lens [:i]):sum (lens [:i + 1] ) ] for i in range (rails) ]
    maxLen = len (paths [0] )
    paths = [list (path) + ( [] if len (path) == maxLen else [''] ) for path in paths]
    return ''.join (''.join (x) for x in zip (*paths) )

解密说明:

length = len (cypher)

为方便起见,将密文的长度存储在局部变量中。

lens = [length // rails + (1 if length % rails > i else 0) for i in range (rails) ]

现在我们计算每个铁轨的长度。每个轨道的长度是密文的长度除以轨道的数量(在您的情况下为3),如果长度不完全可分,则可能(if部分)加1

paths = [cypher [sum (lens [:i] ):sum (lens [:i + 1] ) ] for i in range (rails) ]

现在根据我们刚刚计算的轨道长度将密文文本切成不同的轨道。

maxLen = len (paths [0] )

导轨的最大长度等于第一根导轨的长度。

paths = [list (path) + ( [] if len (path) == maxLen else [''] ) for path in paths]

现在在每个导轨末端添加一个空字符太短,所以所有导轨都有相同的长度并且可以压缩。

return ''.join (''.join (x) for x in zip (*paths) )

压缩rails,将每个生成的元组连接成一个字符串,然后将所有这些字符串连接成一个长字符串并返回它。