SouthParkMe

Hi.

This site tends to hold geeky things.

Retrieving the key from Vigenère Ciphertext

Retrieving the key from Vigenère Ciphertext

I have been working through how to break a Vigenère cipher. The last time I looked at this, I had established that a key length of 5 characters was used to encrypt this text:

LRPBB HKQBG WIYSA DEURQ LVFOT YEZKV
ELAIG DXADC TRSHB PBBZN TRTWF NSZRH
NXFCC ZVFVB DEXZS ZVABR ZRQTB CEXZG
SEFWF ZYDAB EXAWF TXZCG LRPMR EWMWQ
ASDHU ZWTCY OSGHL ZYDVN YHMBQ DAQOE
NVUSQ LXTCF LRPOE LQUGN ESZQR ZZQFP
ZQQPL PBMAC WISFH XFXWA RXAVV XWQZS
YIHSE ELQZR DWBCE ELAGF EVQHP SIPCH
ELUGU LRPOA OXTSS ZYDTE TIZRF CIBSN
EIPKV ELABR GSUQR ELQTB CQGZN OMOHN
EIPPL OEDHN RRMBN WPRCE ZRQCA PJAFN
WPFVN EWISY WRAKY PXGGR GIDMB YIDSG
TVQHB SMECJ YLAAR DEURQ LVFOT YEZOF
TJTSU LHPCA PRAHU TRSPH EGAAZ LRPOY
WLUGY TJQOA OEFHR YXUCA QSDTE ZQFVV
DQAAR YXISN CIMHS PYPKV ELFVR NEDRV
YEX

I have also previously worked out how to automate the solution of a Caesar shift.

If we know that that the key is 5 letters, then the first, sixth, eleventh (etcetera) letters are all shifted the same way. Similarly, the second, seventh, twelfth are shifted the same.

I can use the method of the Caesar solver to establish what each shift was, and then convert that shift back into the equivalent key letter.

If I do this, I get the key code:

What length key? 5   
The best guess of the key is: LEMON

I can then use this key to decrypt the text.

ANDNO WGENT LEMEN SAIDD ARTAG NANWI
THOUT STOPP INGTO EXPLA INHIS CONDU
CTTOP ORTHO SALLF ORONE ONEFO RALLT
HATIS OURMO TTOIS ITNOT ANDYE TSAID

“And now, gentlemen,” said d’Artagnan, without stopping to explain his conduct to Porthos, “All for one, one for all--that is our motto, is it not?”….

The code is posted below.

Links

Recent posts on this topic

More on Cryptography

The Code

# recover the key from a vigenere - you should already have keylength

import numpy as np
from math import sqrt

englishdata=[18374,3418,
             4678,11083,
             30430,4396,
             4571,17068,
             13877,223,
             1971,10235,
             5056,15131,
             17579,3353,
             245,12919,
             14424,21889,
             5826,1798,
             6737,225,
             4305,93]

toteng=0
for i in englishdata:
    toteng+=i

keylen=int(input('What length key?'))

print('\n The best guess of the key is: ',end='')

# grab the ciphertext
filetimetable = open("vigciphertext.txt","r")
lines=filetimetable.readlines()
filetimetable.close()

# let's make it all one string
working=""
for line in lines:
    for char in line:
        asc=ord(char)
        if (64 < asc < 91) or ( 96 < asc < 123):
            char=char.upper()
            working+=char

max=len(working)-1
for i in range(keylen):
    done=False
    shift=0
    lett=i
    data=np.full(26,0)
    while not done:
        data[ord(working[lett])-65]+=1

        shift+=keylen
        lett=i+shift
        if lett >= max:
            done=True
    # normalising the data
    tot=0
    for j in data:
        tot+=j
    if tot>0:
        for j in range(26):
            data[j]=data[j]*toteng/tot

    # now for each batch, find the best caesar shift
    error=[]
    maxerr=0
    for shift in range(26):
        err=0
        for k in range(26):
            err+=sqrt((data[k]-englishdata[(k+shift)%26])**2)
            maxerr+=err
        error.append(err)
    guess=0
    for k in range(26):
        if error[k]<maxerr:
            guess=k
            maxerr=error[k]
            
    # and print your guess. As I did the shifting
    # back to front. It's not worth fixing that logic
    # so I'll fix with simple arithmetic before 
    # printing
    # I also shift the ascii range and turn it 
    # into a char
    print(chr(91-guess),end='')

print()
Beaufort Cipher

Beaufort Cipher

Arecibo

Arecibo