Vigenere密码,如何处理超出字符值范围的序数值

时间:2015-12-10 10:15:41

标签: python encryption vigenere

我是一名学生正在完成我的课程,我们必须制作一个Vigenere密码程序。 我知道我的程序很复杂,但我不知道有任何其他方法可以解决这个问题。 我似乎有一个问题,当我添加消息和关键字的序数值时,新的序数值超出了正常的字母值范围。所以它打印出这样奇怪的字母ÐÑÐÑÐÑÐÑÐÑÐÑÐÑÐÑ。

这是我的代码:

newmessage1 = []
stringposition = 0
number1 = 0
mesletter = 0
keyletter = 0
output =[]
keylist = []
stringofnumbs = []
question = input('Would you like to encrypt, decrypt a message or quit?')
encdec=[]
if question == 'encrypt'or'encrypt a string'or'ENCRYPT'or'encrypt_a_message'or'Encrypt':
    message1 = input('Please input a message to encrypt')
    keyword1 = input('Please input a keyword ')
    if message1.isalpha and keyword1.isalpha:#this check if the message and the keyword only contains letters
        messagelength=len(message1)#this sets the variable 'messagelength' to the length of message1
        newkeyword=''#this is an empty variable used to insert the length of the new keyword
        while len(keyword1)<=len(message1):#this will loop checks that the length of keyword1 is smaller thasn the length of message1.
            keyword1+=keyword1#this will repeat the keyword to fit the length of the message
            newkeyword=keyword1[:len(message1)]
            #this set the 'newkeyword' variable to the length of the new keyword
            #(the new keyword is the keyword repeated to fit the length of the message.) 

            for mesletter in message1:
                mesnumber = ord(mesletter)#what it does is it takes every letter in message1 and puts it into its unicode form.
                stringofnumbs.append(mesnumber)#once one letter has been put in its unicode value it will append that unicdoe from of that
                #letter in the variable 'stringofnumbs',it will do this process for every letter in the message. 

            for keyletter in keyword1:
                keynumber = ord(keyletter)#what it does is it takes every letter in keyword1 and puts it into its unicode form.
                keylist.append(keynumber)#once one letter has been put in its unicode value it will
                #append that unicdoe from of that letter in the variable 'stringofnumbs',it will do this process for every letter in the message.

                temp1 = int(stringofnumbs[stringposition])#temp1 is a variable that holds the ordinal values of letters in message1
                temp2 = int(keylist[stringposition-1])#and temp2 is a variable that holds the ordinal values of letters in the keyword1
                temp3 = temp2+temp1#temp3 then adds these ordinal values togther 
                encdec.append(temp3)#the ordinal values added togther are appended to the encdec variable

            for number1 in encdec:
                newletter1=chr(number1)#this for loop takes every letter in encdec and puts the ordinal values back into charcters
                newmessage1.append(newletter1)#then every letter that has been changed to a charcater value is appended to the varibale newmessage1
            print (' ')#this leaves a bit of space to make the encoded text clear    
            print ('the endcoded text is:')#this is just a bit of text to make the encoded text clear to the user
            print (''.join(newmessage1))#here the encoded message is printed
    else:
        ('The message or keyword is invalid please use only numbers')#this will print only if the keyword or message doesnt only contain letters and spaces

2 个答案:

答案 0 :(得分:0)

我认为对你来说最常见的解决方案是再次“包裹”数字。也就是说,如果除以想要允许的最大有效序数,则改为使用余数。

例如,使用chr作为ord的反转:

In [0]: chr(122)    # I guess this is the last valid character you want?
Out[0]: 'z'

In [1]: chr(123)    # Because now we go into symbols
Out[1]: '{'

In [2]: 234%122    # We can take the remainder using modulo division
Out[2]: 112

In [3]: chr(234)    # Not what you want?
Out[3]: 'ê'

In [4]: chr(234%122)    # What you want?
Out[4]: 'p'

In [5]: chr(0) # On further inspection, you also need to add a constant when you divide
Out[5]: '\x00'

In [6]: chr(49)    # Try adding 49 after modulo dividing, and that should keep you alphanumeric.
Out[6]: '1'

我实际上并不知道这会影响你之后的解密,我没有调查过,但你可能想要考虑它。

答案 1 :(得分:0)

通过使用序数,您不必要地为自己制造麻烦。实际上,您正在使用&#34;字母表&#34;有256个符号,而你只对26感兴趣。

理想情况下,您只希望符号的数字范围为0到25,一旦达到26,您就会再次扭曲为0。您可以使用序数来实现此目的,但必须使用正确的偏移量。

现在,我们假设您只使用大写字母。它们的序数从65到90不等。所以一旦你达到91,你想要扭转到65左右。

temp1

另一个问题是,您只需添加temp2temp1即可。 temp2可以保留为65到90之间的数字,但temp2应该是关键偏移量,范围从0到25.因此,当您计算temp2 = int(keylist[stringposition-1]) - 65 时,您应该真的是这样做

while len(keyword1)<=len(message1):
    keyword1+=keyword1
newkeyword=keyword1[:len(message1)]

for mesletter in message1:
    keynumber = ord(keyletter)
    stringofnumbs.append(mesnumber)

for keyletter in newkeyword:
    keynumber = ord(keyletter)
    keylist.append(keynumber)

    temp1 = int(stringofnumbs[stringposition])
    temp2 = int(keylist[stringposition]) - 65
    temp3 = temp2+temp1
    if temp3 > 90:
        temp3 -= 26
    encdec.append(temp3)

    stringposition += 1

etc

这在概念上会解决您的问题,但您的算法仍然不正确。 while循环的目的是将关键字的长度扩展为至少与消息的长度一样长。其他所有内容必须在左侧缩进4个空格,因此它们不是循环的一部分。明确地,

newkeyword

在上面的代码块中,我想指出我纠正的更多错误。您应该迭代keyword1,而不是stringposition,并且您还需要在每个字母上增加if message1.isalpha() and keyword1.isalpha(): message1 = message1.upper() keyword1 = keyword1.upper() if len(keyword1) < len(message1): keyword1 = keyword1 * (len(message1) / len(keyword1)) + keyword1 keyword1 = keyword1[:len(message1)] for m, k in zip(message1, keyword1): encrypted = ord(m) + (ord(k) - 65) if encrypted > 90: encrypted -= 26 encdec.append(chr(encrypted)) print ('\nThe endcoded text is:') print (''.join(encdec)) 个计数器。

要获得更高效,更简单的算法,请考虑将代码发布到Code Review,以及审核,并从您获得的反馈中学习。

虽然不是编写代码的最佳方法,但在保持代码相同的同时,仍然可以进行一些基本的整理。基本上,一旦你的消息和关键字长度相同,你就可以迭代这对字母并在运行中计算加密的字母,这样就可以将它存储在一个列表中。没有理由存储中间步骤,例如将消息和关键字转换为数字列表。


Create table New_table as
  select * from Old_table where 1=2 ;