CoCalc Public FilesMisc / Kryptos.ipynbOpen with one click!
Author: Gabriel Chênevert
Views : 187
Description: Jupyter notebook Misc/Kryptos.ipynb
Compute Environment: Ubuntu 18.04 (Deprecated)

Pré-Kryptos 2017

I) César de base

In [1]:
m = "SXYVVHUTUSUIQHJHUILEYHUJHEFSBQIIYGKUIKHLYD\nWJIYNBUJJHUIJEKJYBCQHSXURYUDTKFHUCYUHSEKF" print m
SXYVVHUTUSUIQHJHUILEYHUJHEFSBQIIYGKUIKHLYD WJIYNBUJJHUIJEKJYBCQHSXURYUDTKFHUCYUHSEKF

Outil de base: analyse fréquentielle

In [2]:
def freqs(s): res = {} for c in s: if not c in res: res[c] = 0 res[c] += 1 res = sorted(res.items(), key=operator.itemgetter(1), reverse=True) img = Graphics() r = .25 for i in range(len(res)): c,f = res[i] img += polygon( [(i+r, 0), (i+r, f), (i+1-r, f), (i+1-r, 0)] ) img += text(c, (i+.5,f/2), color="white") show(img, aspect_ratio="auto")
In [3]:
freqs(m)

C'est le premier exemple: il s'agit certainement d'un chiffre de César avec E \mapsto U donc, avec clé +1610+16 \equiv -10. Pour le déchiffrer, il suffit d'appliquer la rotation inverse à l'alphabet.

In [4]:
def rot(s,i,alpha): res = "" for c in s: if c in alpha: res += alpha[ (alpha.index(c) + i) % len(alpha) ] else: #print u"Caractère %s ignoré" % c res += c return res
In [5]:
alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" k = alpha.index("U") - alpha.index("E") # 16 print rot(m,-k,alpha)
CHIFFREDECESARTRESVOIRETROPCLASSIQUESURVIN GTSIXLETTRESTOUTILMARCHEBIENDUPREMIERCOUP

Yé !

Notez que l'espace des clés est ici suffisamment petit pour qu'on puisse toutes les essayer par force brute; le seul message qui semble avoir du sens est le bon.

In [6]:
for k in range(26): print k, rot(m,-k,alpha)
0 SXYVVHUTUSUIQHJHUILEYHUJHEFSBQIIYGKUIKHLYD WJIYNBUJJHUIJEKJYBCQHSXURYUDTKFHUCYUHSEKF 1 RWXUUGTSTRTHPGIGTHKDXGTIGDERAPHHXFJTHJGKXC VIHXMATIIGTHIDJIXABPGRWTQXTCSJEGTBXTGRDJE 2 QVWTTFSRSQSGOFHFSGJCWFSHFCDQZOGGWEISGIFJWB UHGWLZSHHFSGHCIHWZAOFQVSPWSBRIDFSAWSFQCID 3 PUVSSERQRPRFNEGERFIBVERGEBCPYNFFVDHRFHEIVA TGFVKYRGGERFGBHGVYZNEPUROVRAQHCERZVREPBHC 4 OTURRDQPQOQEMDFDQEHAUDQFDABOXMEEUCGQEGDHUZ SFEUJXQFFDQEFAGFUXYMDOTQNUQZPGBDQYUQDOAGB 5 NSTQQCPOPNPDLCECPDGZTCPECZANWLDDTBFPDFCGTY REDTIWPEECPDEZFETWXLCNSPMTPYOFACPXTPCNZFA 6 MRSPPBONOMOCKBDBOCFYSBODBYZMVKCCSAEOCEBFSX QDCSHVODDBOCDYEDSVWKBMROLSOXNEZBOWSOBMYEZ 7 LQROOANMNLNBJACANBEXRANCAXYLUJBBRZDNBDAERW PCBRGUNCCANBCXDCRUVJALQNKRNWMDYANVRNALXDY 8 KPQNNZMLMKMAIZBZMADWQZMBZWXKTIAAQYCMACZDQV OBAQFTMBBZMABWCBQTUIZKPMJQMVLCXZMUQMZKWCX 9 JOPMMYLKLJLZHYAYLZCVPYLAYVWJSHZZPXBLZBYCPU NAZPESLAAYLZAVBAPSTHYJOLIPLUKBWYLTPLYJVBW 10 INOLLXKJKIKYGXZXKYBUOXKZXUVIRGYYOWAKYAXBOT MZYODRKZZXKYZUAZORSGXINKHOKTJAVXKSOKXIUAV 11 HMNKKWJIJHJXFWYWJXATNWJYWTUHQFXXNVZJXZWANS LYXNCQJYYWJXYTZYNQRFWHMJGNJSIZUWJRNJWHTZU 12 GLMJJVIHIGIWEVXVIWZSMVIXVSTGPEWWMUYIWYVZMR KXWMBPIXXVIWXSYXMPQEVGLIFMIRHYTVIQMIVGSYT 13 FKLIIUHGHFHVDUWUHVYRLUHWURSFODVVLTXHVXUYLQ JWVLAOHWWUHVWRXWLOPDUFKHELHQGXSUHPLHUFRXS 14 EJKHHTGFGEGUCTVTGUXQKTGVTQRENCUUKSWGUWTXKP IVUKZNGVVTGUVQWVKNOCTEJGDKGPFWRTGOKGTEQWR 15 DIJGGSFEFDFTBSUSFTWPJSFUSPQDMBTTJRVFTVSWJO HUTJYMFUUSFTUPVUJMNBSDIFCJFOEVQSFNJFSDPVQ 16 CHIFFREDECESARTRESVOIRETROPCLASSIQUESURVIN GTSIXLETTRESTOUTILMARCHEBIENDUPREMIERCOUP 17 BGHEEQDCDBDRZQSQDRUNHQDSQNOBKZRRHPTDRTQUHM FSRHWKDSSQDRSNTSHKLZQBGDAHDMCTOQDLHDQBNTO 18 AFGDDPCBCACQYPRPCQTMGPCRPMNAJYQQGOSCQSPTGL ERQGVJCRRPCQRMSRGJKYPAFCZGCLBSNPCKGCPAMSN 19 ZEFCCOBABZBPXOQOBPSLFOBQOLMZIXPPFNRBPROSFK DQPFUIBQQOBPQLRQFIJXOZEBYFBKARMOBJFBOZLRM 20 YDEBBNAZAYAOWNPNAORKENAPNKLYHWOOEMQAOQNREJ CPOETHAPPNAOPKQPEHIWNYDAXEAJZQLNAIEANYKQL 21 XCDAAMZYZXZNVMOMZNQJDMZOMJKXGVNNDLPZNPMQDI BONDSGZOOMZNOJPODGHVMXCZWDZIYPKMZHDZMXJPK 22 WBCZZLYXYWYMULNLYMPICLYNLIJWFUMMCKOYMOLPCH ANMCRFYNNLYMNIONCFGULWBYVCYHXOJLYGCYLWIOJ 23 VABYYKXWXVXLTKMKXLOHBKXMKHIVETLLBJNXLNKOBG ZMLBQEXMMKXLMHNMBEFTKVAXUBXGWNIKXFBXKVHNI 24 UZAXXJWVWUWKSJLJWKNGAJWLJGHUDSKKAIMWKMJNAF YLKAPDWLLJWKLGMLADESJUZWTAWFVMHJWEAWJUGMH 25 TYZWWIVUVTVJRIKIVJMFZIVKIFGTCRJJZHLVJLIMZE XKJZOCVKKIVJKFLKZCDRITYVSZVEULGIVDZVITFLG

II) César un peu plus subtil

In [7]:
m = "PAPX WPD?YD P?D W?;D,PLWT;!PEEEDPYDRPYP,LWDTWD\nQL?!DQLT,PD!,P;DL!!PY!TZYDLDWJLW SLMP!D?!TWT;P\nDP!DLDWJZ,O,PDOLY;DWP.?PWDNPW?TKNTDP;!DPN,T!DH" print m
PAPX WPD?YD P?D W?;D,PLWT;!PEEEDPYDRPYP,LWDTWD QL?!DQLT,PD!,P;DL!!PY!TZYDLDWJLW SLMP!D?!TWT;P DP!DLDWJZ,O,PDOLY;DWP.?PWDNPW?TKNTDP;!DPN,T!DH

Appliquons le même outil:

In [8]:
freqs(m)

Vue la numérotation romaine, on peut croire qu'il s'agit encore d'un chiffre de César... La question est alors sur quel alphabet: il semble y avoir de la ponctuation. Si on imagine que c'est l'alphabet A-Z en rajoutant de la ponctuation au bout, la question est: combien de signes, et dans quel ordre ? (au moins 5). Si on imagine que D vient de espace et P de E, faudrait appliquer un décalage de P-E = -11. Pour que D recule jusqu'à espace, ça nous prend donc un alphabet à (au moins) 34 caractères.

In [9]:
alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567" d = alpha.index('P') - alpha.index('E') # 11 print rot(m,-d,alpha)
EXEMPLE ?N PE? PL?; ,EALI;!E111 EN GENE,AL IL FA?! FAI,E !,E; A!!EN!ION A L6ALPHABE! ?!ILI;E E! A L6O,D,E DAN; LE.?EL CEL?I7CI E;! EC,I! 4

On semble tenir quelque chose ! Il ne reste plus qu'à déterminer dans quel ordre sont écrits les signes de ponctuation à la fin de l'alphabet. Avec quelques tâtonnements on trouve aisément la position de chaque signe:

In [10]:
alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234?67" print rot(m,-d,alpha)
EXEMPLE UN PEU PLU; ,EALI;!E111 EN GENE,AL IL FAU! FAI,E !,E; A!!EN!ION A L6ALPHABE! U!ILI;E E! A L6O,D,E DAN; LE.UEL CELUI7CI E;! EC,I! 4
In [11]:
alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ 12;4?67" print rot(m,-d,alpha)
EXEMPLE UN PEU PLUS ,EALIS!E111 EN GENE,AL IL FAU! FAI,E !,ES A!!EN!ION A L6ALPHABE! U!ILISE E! A L6O,D,E DANS LE.UEL CELUI7CI ES! EC,I! 4
In [12]:
alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ 1,;4?67" print rot(m,-d,alpha)
EXEMPLE UN PEU PLUS REALIS!E111 EN GENERAL IL FAU! FAIRE !RES A!!EN!ION A L6ALPHABE! U!ILISE E! A L6ORDRE DANS LE.UEL CELUI7CI ES! ECRI! 4
In [13]:
alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ 1,;!?67" print rot(m,-d,alpha)
EXEMPLE UN PEU PLUS REALISTE111 EN GENERAL IL FAUT FAIRE TRES ATTENTION A L6ALPHABET UTILISE ET A L6ORDRE DANS LE.UEL CELUI7CI EST ECRIT !
In [14]:
alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ .,;!?67" print rot(m,-d,alpha)
EXEMPLE UN PEU PLUS REALISTE... EN GENERAL IL FAUT FAIRE TRES ATTENTION A L6ALPHABET UTILISE ET A L6ORDRE DANS LEQUEL CELUI7CI EST ECRIT !
In [15]:
alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ .,;!?'-" print rot(m,-d,alpha)
EXEMPLE UN PEU PLUS REALISTE... EN GENERAL IL FAUT FAIRE TRES ATTENTION A L'ALPHABET UTILISE ET A L'ORDRE DANS LEQUEL CELUI-CI EST ECRIT !

Enseignements: si l'espace est dans notre alphabet, il est encore plus fréquent que E.

On aurait aussi pu utiliser "EEE" = "..." comme amorce...

\gimel) Atbash

Exemple d'indice donné par le contexte: le gimel (3e lettre de l'alphabet hébraïque) doit nous faire penser (via internet, ou Dan Brown) à de l'Atbash (chaque caractère remplacé par son opposé dans l'alphabet, cas particulier tout comme César de chiffre affine).

In [16]:
m = "'C!QPIR!VN!RQAVPIE"
In [17]:
def atbash(s, alpha): res = "" for c in s: res += alpha[ -alpha.index(c) ] return res
In [18]:
atbash(m, alpha) # même alphabet qu'à la question précédente
"C'EST RENVERSANT !"

σ\sigma) Chiffre de substitution

Cette fois-ci le σ\sigma peut nous faire penser à un chiffre de substitution général obtenu par une permutation quelconque de l'alphabet. L'analyse fréquentielle nous aide encore:

In [19]:
m = "CIFVPJIN'ZYICJVMI'PICIJCFCWOI CTMI CTICRCOXXXXI'NI'LICI\n,YT'VKIV IB'E'FIRCTXITYQYFIL,CBYL.',LMILNT'D'PJI TVZICI\n.'KKYPIQCLYMI.CEYIRVPIN.Y'TI 'TLNIE'BNVTOICJC'PLNIN.YIY\nE'FIJCFCBN'BIYZ,'TYXIKHT'PJIN.YIQCNNFYMITYQYFIL,'YLIZCP\nCJYKINVILNYCFILYBTYNI,FCPLINVIN.YIYZ,'TYSLIHFN'ZCNYIRYC\n,VPMIN.YIKYCN.ILNCTMICPICTZVTYKIL,CBYILNCN'VPIR'N.IYPVH\nJ.I,VRYTINVIKYLNTVOICPIYPN'TYI,FCPYNXI,HTLHYKIQOIN.YIYZ\n,'TYSLIL'P'LNYTICJYPNLMI,T'PBYLLIFY'CITCBYLI.VZYICQVCTK\nI.YTILNCTL.',MIBHLNVK'CPIV IN.YILNVFYPI,FCPLIN.CNIBCPIL\nCEYI.YTI,YV,FYICPKITYLNVTYI TYYKVZINVIN.YIJCFCWOXXXX" print m
CIFVPJIN'ZYICJVMI'PICIJCFCWOI CTMI CTICRCOXXXXI'NI'LICI ,YT'VKIV IB'E'FIRCTXITYQYFIL,CBYL.',LMILNT'D'PJI TVZICI .'KKYPIQCLYMI.CEYIRVPIN.Y'TI 'TLNIE'BNVTOICJC'PLNIN.YIY E'FIJCFCBN'BIYZ,'TYXIKHT'PJIN.YIQCNNFYMITYQYFIL,'YLIZCP CJYKINVILNYCFILYBTYNI,FCPLINVIN.YIYZ,'TYSLIHFN'ZCNYIRYC ,VPMIN.YIKYCN.ILNCTMICPICTZVTYKIL,CBYILNCN'VPIR'N.IYPVH J.I,VRYTINVIKYLNTVOICPIYPN'TYI,FCPYNXI,HTLHYKIQOIN.YIYZ ,'TYSLIL'P'LNYTICJYPNLMI,T'PBYLLIFY'CITCBYLI.VZYICQVCTK I.YTILNCTL.',MIBHLNVK'CPIV IN.YILNVFYPI,FCPLIN.CNIBCPIL CEYI.YTI,YV,FYICPKITYLNVTYI TYYKVZINVIN.YIJCFCWOXXXX

Les quadruples X sont un peu déroutants...

In [20]:
freqs(m)

Ça peut ressembler à de l'anglais (?) Essayons

In [21]:
def subs(s,alpha,plain): res = "" for c in s: if c in alpha: res += plain[ alpha.index(c) ] else: res += c return res
In [28]:
alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ ',." plain = "ABaDEFGH JKLMNOPQRSTUVWXeZ_',." print subs(m,alpha,plain)
a FVPJ N'Ze aJVM 'P a JaFaWO _aTM _aT aRaOXXXX 'N 'L a ,eT'VK V_ B'E'F RaTX TeQeF L,aBeL.',LM LNT'D'PJ _TVZ a .'KKeP QaLeM .aEe RVP N.e'T _'TLN E'BNVTO aJa'PLN N.e e E'F JaFaBN'B eZ,'TeX KHT'PJ N.e QaNNFeM TeQeF L,'eL ZaP aJeK NV LNeaF LeBTeN ,FaPL NV N.e eZ,'TeSL HFN'ZaNe Rea ,VPM N.e KeaN. LNaTM aP aTZVTeK L,aBe LNaN'VP R'N. ePVH J. ,VReT NV KeLNTVO aP ePN'Te ,FaPeNX ,HTLHeK QO N.e eZ ,'TeSL L'P'LNeT aJePNLM ,T'PBeLL Fe'a TaBeL .VZe aQVaTK .eT LNaTL.',M BHLNVK'aP V_ N.e LNVFeP ,FaPL N.aN BaP L aEe .eT ,eV,Fe aPK TeLNVTe _TeeKVZ NV N.e JaFaWOXXXX

N'a pas l'air absurde... Ensuite ça prend d'autres accroches (ou fréquences doubles), en tout cas de l'observation. "N.e" revient plusieurs fois, peut-être "the" ?

In [24]:
alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ ',." plain = "ABaDEFGH JKLMtOPQRSTUVWXeZ*',h" print subs(m,alpha,plain)
a FVPJ t'Ze aJVM 'P a JaFaWO *aTM *aT aRaOXXXX 't 'L a ,eT'VK V* B'E'F RaTX TeQeF L,aBeLh',LM LtT'D'PJ *TVZ a h'KKeP QaLeM haEe RVP the'T *'TLt E'BtVTO aJa'PLt the e E'F JaFaBt'B eZ,'TeX KHT'PJ the QattFeM TeQeF L,'eL ZaP aJeK tV LteaF LeBTet ,FaPL tV the eZ,'TeSL HFt'Zate Rea ,VPM the Keath LtaTM aP aTZVTeK L,aBe Ltat'VP R'th ePVH Jh ,VReT tV KeLtTVO aP ePt'Te ,FaPetX ,HTLHeK QO the eZ ,'TeSL L'P'LteT aJePtLM ,T'PBeLL Fe'a TaBeL hVZe aQVaTK heT LtaTLh',M BHLtVK'aP V* the LtVFeP ,FaPL that BaP L aEe heT ,eV,Fe aPK TeLtVTe *TeeKVZ tV the JaFaWOXXXX

'that' est rassurant; ailleurs on dirait 'death'...

In [25]:
alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ ',." plain = "ABaDEFGH JdLMtOPQRSTUVWXeZ.',h" print subs(m,alpha,plain)
a FVPJ t'Ze aJVM 'P a JaFaWO .aTM .aT aRaOXXXX 't 'L a ,eT'Vd V. B'E'F RaTX TeQeF L,aBeLh',LM LtT'D'PJ .TVZ a h'ddeP QaLeM haEe RVP the'T .'TLt E'BtVTO aJa'PLt the e E'F JaFaBt'B eZ,'TeX dHT'PJ the QattFeM TeQeF L,'eL ZaP aJed tV LteaF LeBTet ,FaPL tV the eZ,'TeSL HFt'Zate Rea ,VPM the death LtaTM aP aTZVTed L,aBe Ltat'VP R'th ePVH Jh ,VReT tV deLtTVO aP ePt'Te ,FaPetX ,HTLHed QO the eZ ,'TeSL L'P'LteT aJePtLM ,T'PBeLL Fe'a TaBeL hVZe aQVaTd heT LtaTLh',M BHLtVd'aP V. the LtVFeP ,FaPL that BaP L aEe heT ,eV,Fe aPd TeLtVTe .TeedVZ tV the JaFaWOXXXX

'tV', sans doute 'to'

In [26]:
alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ ',." plain = "ABaDEFGH JdLMtOPQRSTUoWXeZ*',h" print subs(m,alpha,plain)
a FoPJ t'Ze aJoM 'P a JaFaWO *aTM *aT aRaOXXXX 't 'L a ,eT'od o* B'E'F RaTX TeQeF L,aBeLh',LM LtT'D'PJ *ToZ a h'ddeP QaLeM haEe RoP the'T *'TLt E'BtoTO aJa'PLt the e E'F JaFaBt'B eZ,'TeX dHT'PJ the QattFeM TeQeF L,'eL ZaP aJed to LteaF LeBTet ,FaPL to the eZ,'TeSL HFt'Zate Rea ,oPM the death LtaTM aP aTZoTed L,aBe Ltat'oP R'th ePoH Jh ,oReT to deLtToO aP ePt'Te ,FaPetX ,HTLHed QO the eZ ,'TeSL L'P'LteT aJePtLM ,T'PBeLL Fe'a TaBeL hoZe aQoaTd heT LtaTLh',M BHLtod'aP o* the LtoFeP ,FaPL that BaP L aEe heT ,eo,Fe aPd TeLtoTe *TeedoZ to the JaFaWOXXXX

"freedom" !

In [27]:
alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ ',." plain = "ABaDEFGH JdLMtOPQRSrUoWXemf',h" print subs(m,alpha,plain)
a FoPJ t'me aJoM 'P a JaFaWO farM far aRaOXXXX 't 'L a ,er'od of B'E'F RarX reQeF L,aBeLh',LM Ltr'D'PJ from a h'ddeP QaLeM haEe RoP the'r f'rLt E'BtorO aJa'PLt the e E'F JaFaBt'B em,'reX dHr'PJ the QattFeM reQeF L,'eL maP aJed to LteaF LeBret ,FaPL to the em,'reSL HFt'mate Rea ,oPM the death LtarM aP armored L,aBe Ltat'oP R'th ePoH Jh ,oRer to deLtroO aP ePt're ,FaPetX ,HrLHed QO the em ,'reSL L'P'Lter aJePtLM ,r'PBeLL Fe'a raBeL home aQoard her LtarLh',M BHLtod'aP of the LtoFeP ,FaPL that BaP L aEe her ,eo,Fe aPd reLtore freedom to the JaFaWOXXXX

"armored"... ok ça vient, en complétant on obtient:

In [28]:
alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ ',." plain = "*cakvl*u gds,tynbw'r*ox.emfiph" print subs(m,alpha,plain)
a long time ago, in a galaxy far, far away.... it is a period of civil war. rebel spaceships, striking from a hidden base, have won their first victory against the e vil galactic empire. during the battle, rebel spies man aged to steal secret plans to the empire's ultimate wea pon, the death star, an armored space station with enou gh power to destroy an entire planet. pursued by the em pire's sinister agents, princess leia races home aboard her starship, custodian of the stolen plans that can s ave her people and restore freedom to the galaxy....

Enseignement: effectivement, le crawl de la Guerre des Étoiles utilise des quadruples points de suspension !

V) pour Vigenère

Cette fois on dirait que les espaces et ponctuation sont normaux, ça ressemble à un poème ou quoi. Les deux dernières lignes sont curieuses...

In [29]:
m = "elhQt'A n wegX LpB'D wxQt iyw xkzI oytxwDGA vD krKs\nIAo wkD'H jHJmqF p AGlmuVpG Gz lhzKmA.\nhlhM Hpr riwR IprCi vGt sAzAv, Hu Bup wwNGmF lvh zAt pwsvDs\nevEl d VDzq Dlh Bpv tpx zGpB Fsi fzBm szv.\nRNw, wBs, eqC Hpr'D fxXxvt l wwzxzJlC wN wmnGiq.\n\nswmEp'w d RxoA zr wGt Enwp eTI Aup AdMIA Gz fh RJzr\n'NexRt GBF oqNL ABxiwHBmF HsuCH pnGi wVD urlrlMvA.\nVy e wQtm oJ xkD qzBzo, wGtzr'D e vNCootvg Vww FtrjR,\nhwzpxlLtA nwp rE DCE ElrTvpGD euD BqFrmyDC.\n\nWBs, mw LpsrD qh VDvqpv,\nRNw, qG xenDH ur HsqCtz." print m
elhQt'A n wegX LpB'D wxQt iyw xkzI oytxwDGA vD krKs IAo wkD'H jHJmqF p AGlmuVpG Gz lhzKmA. hlhM Hpr riwR IprCi vGt sAzAv, Hu Bup wwNGmF lvh zAt pwsvDs evEl d VDzq Dlh Bpv tpx zGpB Fsi fzBm szv. RNw, wBs, eqC Hpr'D fxXxvt l wwzxzJlC wN wmnGiq. swmEp'w d RxoA zr wGt Enwp eTI Aup AdMIA Gz fh RJzr 'NexRt GBF oqNL ABxiwHBmF HsuCH pnGi wVD urlrlMvA. Vy e wQtm oJ xkD qzBzo, wGtzr'D e vNCootvg Vww FtrjR, hwzpxlLtA nwp rE DCE ElrTvpGD euD BqFrmyDC. WBs, mw LpsrD qh VDvqpv, RNw, qG xenDH ur HsqCtz.
In [30]:
freqs(m)

Les fréquences ne ressemblent pas à ce qu'on voyait précédemment (le "E" devrait être aperçu à une fréquence proche de celle de l'espace), ça ressemble à du polyaphabétique, peut-être plusieurs Césars entrelacés: c'est exactement le principe du chiffre de Vigenère. Pour le déchiffrer, on procède habituellement en deux temps.

1) Trouver la taille de la clé

On pourrait tout faire par analyse fréquentielle (tester différentes tailles jusqu'à retrouver le spectre fréquentiel d'une langue connue...) mais ici on peut être plus malin: quand on regarde bien on voit des mots qui se répètent.

In [31]:
mm = m.translate(None, " \n'.,") # ignorons toute ponctuation mm
'elhQtAnwegXLpBDwxQtiywxkzIoytxwDGAvDkrKsIAowkDHjHJmqFpAGlmuVpGGzlhzKmAhlhMHprriwRIprCivGtsAzAvHuBupwwNGmFlvhzAtpwsvDsevEldVDzqDlhBpvtpxzGpBFsifzBmszvRNwwBseqCHprDfxXxvtlwwzxzJlCwNwmnGiqswmEpwdRxoAzrwGtEnwpeTIAupAdMIAGzfhRJzrNexRtGBFoqNLABxiwHBmFHsuCHpnGiwVDurlrlMvAVyewQtmoJxkDqzBzowGtzrDevNCootvgVwwFtrjRhwzpxlLtAnwprEDCEElrTvpGDeuDBqFrmyDCWBsmwLpsrDqhVDvqpvRNwqGxenDHurHsqCtz'
In [32]:
mm.index("Gz", 65) - mm.index("Gz")
154
In [33]:
mm.index("RNw", 150) - mm.index("RNw")
210

Deux occurences d'un même mot courant, chiffrées de la même façon, sont vraisemblablement distants d'un multiple de la longueur de la clé, soit au maximum:

In [34]:
gcd(154,210)
14

Un autre mot se répète presque:

In [35]:
mm.index("WBs") - mm.index("wBs")
189
In [36]:
gcd(189,14) ## hm hm
7

Vue les positions de "WBs" (en début de vers) et "wBs", la notion de lettre (indépendemment de la casse) semble respectée, ce qui serait cohérent avec un chiffrement de Vigenère sur l'alphabet "A...Za...z" -- et donc une clé de longueur 7.

2) Récupérer la clé

Ne reste plus qu'à récupérer la clé un caractère à la fois... On pourrait utiliser l'analyse fréquentielle sur chaque tranche (en prenant un caractère tous les 7) pour repérer le décalage utilisé (chose qui d'ailleurs pourrait être passablement automatisée), mais il est ici tout aussi rapide (et plus amusant) d'essayer de reconnaître des mots.

In [37]:
def vigenere(m, alpha, key): res = "" i = 0 for c in m: if c in alpha: res += rot(c,-alpha.index(key[i]),alpha) i = (i+1)%len(key) else: res += c return res

Par exemple, on voit beaucoup: 'A, 'D (deux fois), 'H, 'w, si c'est en anglais il s'agit sans doute de 's.

In [38]:
alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" print vigenere(m, alpha, "LEAAPIA") # je mets des A quand je ne sais pas
ThhQe's n lagX whB's sxQe ayl tkzt gyitwDrs vs grKd AAd skD's bHyiqF a sGaiuVay Go hhzveA. WhhM shr gewR thrre vGe kAowv, Hf tue swNreF arh zll plovDd Wvth d Vorq shh Ban tet zGat Fhe fzme sor. RNh, oBh, aqC shr's bxXint a swzirJay wN henveq. sheEe's d RigA on wGe wnll eTt sue wdMts Go bh Rurr 'CaxRe yBu kqNw sBmewHmeF wouCs hnve wVo mranlMgs. Vn a wQee oy tkD brBok, wGerr's a vNngoirg Vho FinjR, SozetlLes nll rE ouE thrTghGs auD miFgiyDn. OBh, iw Lakrs mh Vonqer, RNh, iG manDs mr woqCer.

Le reste tombe rapidement:

In [39]:
alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" print vigenere(m, alpha, "LEDZPIN")
There's a lady who's sure all that glitters is gold And she's buying a stairway to heaven. When she gets there she knows, if the stores are all closed With a word she can get what she came for. Ooh, ooh, and she's buying a stairway to heaven. There's a sign on the wall but she wants to be sure 'Cause you know sometimes words have two meanings. In a tree by the brook, there's a songbird who sings, Sometimes all of our thoughts are misgiven. Ooh, it makes me wonder, Ooh, it makes me wonder.

Enseignement: le chiffre de Vigenère, longtemps considéré suffisamment sophistiqué pour déjouer qui que ce soit, ne résiste pas longtemps aux techniques d'analyse « modernes » (disons, post-Renaissance). Comme clé, on utilise souvent une phrase à laquelle on retire les caractères en double (pour éviter de créer des coïncidences de périodicité plus courte que la longueur de la clé).

In [ ]: