Search code examples
pythonencryptionvigenere

Vigenere encryption using key as plaintext


I'm trying to write a variant of a Vigenere decryption in which my encryption key is the plaintext. For this we assume that we know the first letter of the key, suppose it is a0, then the code must use a0 to decrypt the next letter of the key a1, to decrypt a2 it must use a1, and so on... to decrypt the an letter an of the key an-1 is used.

I currently have the following code to encrypt and decrypt using the usual Vigenere method. I would like to take advantage of this code to perform the variant that I mentioned at the beginning.

from random import sample
from itertools import product as col
  def generator(key,char,length):
    char_len = key.count(char)   
    key_piece = key[:length - char_len:]

list_keys = [key_piece+"".join(i) for i in list(col([chr(i) for i in range(65, 65+26)], repeat=char_len))]
    return list_keys
    `def vigenere(x,key):
    lst_final = []
    code = list(x)
    j = 0
    for i,char in enumerate(code):
        if char.isalpha():
            code[i] = key[(i+j)%len(key)]
            if cifrar:
              lst_final.append((ord(x[i]) + ord(code[i]) - 65 * 2) % 26)
      else:
lst_final.append((ord(x[i]) - ord(code[i])) % 26)

        else:
          lst_final.append(ord(char))
           j -=1
    for i,char in enumerate(code):
        if char.isalpha():
            lst_final[i] = chr(lst_final[i] + 65)
        else:
            lst_final[i] = chr(lst_final[i])
              return ''.join(lst_final)

print("Bienvenido al cifrado Vigenere")
   if input('Cifrar o Descifrar : ').lower() == 'cifrar':
    x = input('Ingrese el texto : ').upper()
    key = input('Ingrese la clave : ').upper()
    cifrar = True 
    print(vigenere(x,key))  
else:
    x = input('text : ').upper()
    cifrar = False
    if input('Tiene la clave? (y/n) : ') == "y":
        key = input('Ingrese la clave : ').upper()
        print(vigenere(x,key))

Note that the program works in Spanish. I must say that I am a mathematician and my skills as a programmer leave a lot to be desired (I even struggled to write the code above), it is for this reason that I feel somewhat lost, I hope someone can help me by giving me a hint or something similar.

Edit: Advised by the comments I have searched for information on autoclave ciphers. Now I have new doubts and I think I should be more specific in my question, I will do it by means of an example

This is a made up example. Suppose we have the encrypted text JLPWZ and we know that the first letter of the key is Q. So I search that, using the Vigenere method (Vigenere table) Q and J decrypt the letter H, now using H and L decrypt E, then E and P decipher L, with L and W get L, then with L and Z get O; in order to finally obtain the plain text HELLO


Solution

  • single character seeded autokey decryption illustrated with javascript

    interpretation

    My understanding of this problem is that the first character of a given plain text (PT) is used as the Vigenere key to encipher that character to give the first cipher text (CT) character. The first PT character is then used again as the key to encipher the second character. For each subsequent character, the previous PT character is used as the encryption key.

    Thus, a function to perform the encryption step, has to begin with using the first PT character as a key twice, before advancing a single character for each subsequent encryption key.

    Here is a working snippet of a simple javascript encryption routine using this method.

    Encryption function (javascript):

    PT = "KEEPTHISMESSAGEPRIVATE";
    key = PT.charAt(0);
    
    console.log(encryptVigenere(PT,key));
    
    function encryptVigenere(PT,key,alphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZ") {
    let CT = "";
    
      for (let i=0; i<PT.length; i++) {
        CT += alphabet.charAt((alphabet.indexOf(key)+alphabet.indexOf(PT.charAt(i)))%26);
        key = PT.charAt(i);
      } // next PT char;
    
    return CT;
    } // end function encryptVigenere;

    The for-next loop includes a one-line algorithm that can be understood and derived by inspecting the intersections of a Vigenere tabula recta if the letter positions are thought of as distances between the relative parts of the alphabets. See e.g: https://www.britannica.com/topic/Vigenere-cipher.

    sketch of algorithm

    remainder division by 26 %26 is used to ensure the character position is always in the range of the alphabet (which has a 'distance'/length of 26 characters). The key is also advanced one character for each iteration of the loop (at the end, allowing the first iteration to use the same key as the second).

    Decryption function (javascript):

    The decryption process requires that the character required to decrypt the first CT character is exchanged with the recipient and it must be the first character of the known PT.

    const CT = "UOITIAPAEQWKSGKTGZDVTX";
    let key = "K";
    
    console.log(decryptVigenere(CT,key));
    
    function decryptVigenere(CT,key,alphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZ") {
    let PT = "";
    
      for (let i=0; i<CT.length; i++) {
        key = alphabet.charAt((alphabet.indexOf(CT.charAt(i))-alphabet.indexOf(key) +26)%26);
        PT += key;
      } // next CT char;
    
    return PT;
    } // end function decryptVigenere;

    Again, the algorithm is explicable by inspection of distances between letters on a Vigenere table. Because the decryption requires subtraction of letter distances, an adjustment by adding 26 before a final remainder division by 26 is used to ensure the character is always within the length (26) of the alphabet.

    The important part is that each loop resets the key to the current plain text result of the decryption.

    In both functions it is possible to send a modified alphabet as an alternative to the default A-Z.

    applying the principle to python

    Assuming python has string methods that identify characters at known positions, and that can find the position of known characters, the algorithm used here ought be directly transferable to python. Each part of the process is a number relating to a position and/or distance to other positions.