3190 - Vigenere

De la Universitas MediaWiki

Vigenere

La fel ca cifrul Cezar, cifrul Vigenere deplasează literele, dar acesta folosește o deplasare multiplă. Cheia este constituită din câțiva întregi ki, unde 0 ≤ ki ≤ 25. Aceşti întregi pot fi, de exemplu, k = (21, 4, 2 19, 14, 17). Această cheie ar provoca deplasare primei litere cu 21, c1 = p1 + 21 (mod 26), a celei de-a doua cu 4, c2 = p2 + 4 (mod 26), ş.a.m.d. până la sfârşitul cheii și apoi de la început, din nou.

Pentru o memorare mai ușoară cheia este de regulă dată printr-un cuvânt – cheia de mai sus corespunde cuvântului vector, litera 'v'” corespondând numărului 21 (numerotarea începe de la 0), litera 'e' cu 4, etc. Un exemplu de cifru Vigenere:

Textul clar: thisisanexampleofthevigenerecipher

Cheia: vector

Textul cifrat: olklwjvrgqodkpghtkcixbuviitxqzklgk

Cerinţa

Se citesc două texte a și b cu lungimea maximă de 255 de caractere. Să se afișeze textul după 
aplicarea cifrului Vigenere la textul a cu cheia b.

Date de intrare

Fișierul de intrare vigenerein.txt conține pe prima linie textul a iar pe a doua linie textul b.

Date de ieșire

Fișierul de ieșire vigenereout.txt va conține pe prima linie rezultatul criptării.

Restricţii şi precizări

  • lungimea lui b ⩽ Lungimea lui a ⩽ 255;
  • cele două șiruri vor conține doar litere mici din alfabetul englez.

Exemplu 1

vigenerein.txt
pbinfo
dio
vigenereout.txt
Datele de intrare corespund restrictiilor impuse
sjwqnc


Exemplu 2

vigenerein.txt
abc123
vigenereout.txt
Datele de intrare nu corespund restrictiilor impuse


Explicatie

În Cifrul Vigenere începem numărătoarea caracterelor din cheie de la 0, astfel, caracterul 'd' din cheie deplasează caractrrul corespunzător din text cu 3 caractere; astfel, 'p' devine 's'. Acest procedeu se repetă și pentru restul șirului.

Rezolvare

def vigenere(a, b, c):
    # Aplică cifrul Vigenere pe textul a cu cheia b
    alfabet = 'abcdefghijklmnopqrstuvwxyz'
    if c == 1:
        return ''.join([alfabet[(alfabet.index(a[i]) + alfabet.index(b[i % len(b)])) % 26] for i in range(len(a))])
    else:
        return ''.join([alfabet[(alfabet.index(a[i]) - alfabet.index(b[i % len(b)])) % 26] for i in range(len(a))])


def main():
    with open('vigenerein.txt', 'r') as fin, open('vigenereout.txt', 'w') as fout:
        a = fin.readline().strip()
        b = fin.readline().strip()

        # Verifică dacă textele respectă restricțiile
        if len(a) > 255 or len(b) > len(a) or not a.islower() or not b.islower():
            fout.write("Datele de intrare nu corespund restrictiilor impuse\n")
            return

        fout.write("Datele de intrare corespund restrictiilor impuse\n")

        # Aplică cifrul Vigenere pe textul a cu cheia b și scrie rezultatul în fișierul de ieșire
        fout.write(vigenere(a, b, 1) + '\n')


if __name__ == "__main__":
    main()