Vigenère Cipher 函数实现

Vigenère Cipher function implementation

看完 this tutorial Vigenere Cipher 之后,我(希望)了解它的基本概念。我们想为字符串分配一个键,然后将字符串中的每个字母移动键中每个字母的(基于 0 的)字母表位置值。所以当使用培根作为键时,

Meet me in the park at eleven am
baco nb ac onb acon ba conbac on

变成

Negh zf av huf pcfx bt gzrwep oz

因为我是从零开始写Vigenere Cipher,所以我只知道第一步是将密钥分配给一个字符串。在执行此操作时,我想识别每个字符是否为 alpha,以便我可以保留字符串中的任何特殊字符(!、@、# 等)(如果有的话)。

text = input("Enter some text:")

def encrypt(text):

#key = bacon
encrypted = []
baconvalue = {'A':0, 'a':0, 'B':1, 'b':1, 'C':2, 'c':2, 'D':3, 'd':3, 'E':4, 'e':4, 'F':5, 'f':5, 'G':6, 'g':6, 'H':7, 'h':7, 'I':8, 'i':8, 'J':9, 'j':9, 'K':10, 'k':10, 'L':11, 'l':11, 'M':12, 'm':12, 'N': 13, 'n':13, 'O':14, 'o':14, 'P':15, 'p':15, 'Q':16, 'q':16, 'R':17, 'r':17, 'S':18, 's':18, 'T':19, 't':19, 'U':20, 'u':20, 'V':21, 'v':21, 'W':22, 'w':22, 'X':23, 'x':23, 'Y':24, 'y':24, 'Z':25, 'z':25 }


for letter in text:

#assign 'bacon' to text to get rotation value for each character
#preserve alpha characters

        if letter.isalpha():  
      
#character in string rotates x amount according to the corresponding value of char in bacon
        
            encrypted.append(letter, baconvalue)        

        else:    
    
            encrypted.append(letter)            
    
        return ''.join(encrypted)

print(encrypt(text,))

但是如您所见,就如何将 bacon 分配给字符串而言,我不知道从哪里开始。我至少在正确的轨道上吗?

使用用户输入的值作为键索引字符串的方法是创建一个变量 starting_index 并将其设置为 = 0。这样,迭代将从字符串中的第一个字符开始,您将能够使用之前创建的 alphabet_pos 字典生成 rotation 值。

使用您的 rotate 函数根据您创建的新旋转变量旋转字母。如果在您的字典中找到该字母,encrypt 函数将追加这个新字母并继续,直到您到达键中的最后一个索引值。然后它将加密的字母连接在一起。

alphabet_pos = {'A':0, 'a':0, 'B':1, 'b':1, 'C':2, 'c':2, 'D':3, 'd':3,
'E':4, 'e':4, 'F':5, 'f':5, 'G':6, 'g':6, 'H':7, 'h':7, 'I':8, 'i':8,
'J':9, 'j':9, 'K':10, 'k':10, 'L':11, 'l':11, 'M':12, 'm':12, 'N': 13,
'n':13, 'O':14, 'o':14, 'P':15, 'p':15, 'Q':16, 'q':16, 'R':17, 'r':17,
'S':18, 's':18, 'T':19, 't':19, 'U':20, 'u':20, 'V':21, 'v':21, 'W':22,
'w':22, 'X':23, 'x':23, 'Y':24, 'y':24, 'Z':25, 'z':25 }

def alphabet_position(letter):
    alphabet_pos = {'A':0, 'a':0, 'B':1, 'b':1, 'C':2, 'c':2, 'D':3,
'd':3, 'E':4, 'e':4, 'F':5, 'f':5, 'G':6, 'g':6, 'H':7, 'h':7, 'I':8,
'i':8, 'J':9, 'j':9, 'K':10, 'k':10, 'L':11, 'l':11, 'M':12, 'm':12,
'N': 13, 'n':13, 'O':14, 'o':14, 'P':15, 'p':15, 'Q':16, 'q':16,
'R':17, 'r':17, 'S':18, 's':18, 'T':19, 't':19, 'U':20, 'u':20, 'V':21,
'v':21, 'W':22, 'w':22, 'X':23, 'x':23, 'Y':24, 'y':24, 'Z':25, 'z':25
}
    pos = alphabet_pos[letter]
    return pos

def rotate(letter, rot):
    shift = 97 if letter.islower() else 65
    return chr((ord(letter) + rot - shift) % 26 + shift)

def encrypt(text, key):
    encrypted = []    
    starting_index = 0
    for letter in text:
    # if it's alphanumerical, keep it that way
    # find alphabet position
        rotation = alphabet_position(key[starting_index])
    # if it's a space or non-alphabetical character, append and move on
        if not letter in alphabet_pos:
            encrypted.append(letter)
        elif letter.isalpha():            
            encrypted.append(rotate(letter, rotation))             

    #if we've reached last index, reset to zero, otherwise + by 1
        if starting_index == (len(key) - 1): 
            starting_index = 0
        else: 
            starting_index += 1

    return ''.join(encrypted)    

text = input("Enter some text:")
key = input("Enter a key:")

print(encrypt(text,key))

我破译 Vigenère 密码的完整实现可能会帮助您和其他人(它使用具有自相关性的 Friedman 测试方法)理解该方法。

您可以在此处找到代码:https://github.com/ferreirafabio/vigenere-py

所以我的代码很长,但效果很好。希望对你有帮助

def VigenereCiphre(line, key):
    isupper = True
    key = key.strip(' ')
    key = key.upper()
    k = list(key)
    print(k)
    returnLine = []
    i = 0
    for char in list(line):

        # Check if current character is symbol. If true append it to encrypted line
        if ord(char) < 65 or ord(char) > 122:
            returnLine.append(char)
        elif ord(char) > 90 and ord(char) < 97:
            returnLine.append(char)
        else:
            # Checks if letter is capital. If it's not, stores isupper to false and make it uppercase
            if ord(char) > 90:
                isupper = False
                char = char.upper()

            else:
                isupper = True

            # Checks if key's index isn't out of range, if it is, set it back to 0
            print(isupper)
            if i == len(k):
                i = 0

            # create new character based on it's value

            c = ord(char) + ord(k[i]) - 65
            if c > 90:
                c = c - 25

            if isupper == False:
                print(c)
                c = c + 32
                print(c)

            returnLine.append(chr(c))

            i += 1

    a = ''
    return a.join(returnLine)
# Without import libraries
# Keep it simple

alph = 'abcdefghijklmnopqrstuvwxyz'

def encrypt_letter(char, key):
    if char.isalpha():
        shift = alph.index(char) 
        shifted_alph = alph[shift:] + alph[:shift] # rotate
        result = shifted_alph[key]
    else:
        result = char
    return result

def calculate_shifts(letter):
    return alph.index(letter)

def encrypt_text(txt, keyword):
    txt = txt.lower()
    en_ls = list()

# # >>> Method 1 for padding
#     keyword_times_in_txt = (int(len(txt) / len(keyword))+1) # round up
#     txt_padding_with_keyword = (keyword * keyword_times_in_txt)
#     txt_padding_with_keyword = txt_padding_with_keyword[:len(txt)] # slice at length of txt
# # <<< Method 1 for padding

# >>> Method 2 for padding
    txt_padding_with_keyword = list()
    for i in range(len(txt)):
        len_keyword = len(keyword)
        txt_padding_with_keyword.append(keyword[i % len_keyword])
# <<< Method 2 for padding    
    
    for i in range(len(txt)):
        key = calculate_shifts(txt_padding_with_keyword[i])
        char = txt[i]
        en_letter = encrypt_letter(char, key)
        en_ls.append(en_letter)
        
    result = "".join(en_ls)
    
    print(f"Keyword                 : {keyword}")
    print(f"Text                    : {txt}")
    print(f"Padded text with keyword: {''.join(txt_padding_with_keyword)}")

    return result 

# in_txt = input("Which text should be encrypted?")
# in_keyword = input("Which keyword should be used?")

in_txt = "Python is Really Beautiful!"
in_keyword  = "Random"

in_txt = in_txt.lower()
in_keyword = in_keyword.lower()

print(f"Encrypted text          : {encrypt_text(in_txt, in_keyword)}")

# Output:
# Keyword                 : random
# Text                    : python is really beautiful!
# Padded text with keyword: randomrandomrandomrandomran
# Encrypted text          : gygkcz if fqrlyb nvahwwrll!