Fidelio demo notebook


In [1]:
from fidelio_functions import *

Choose an alphabet

Before sending any messages, we must agree on a way to represent characters as numbers.
Fidelio comes with 3 pre-defined character encodings: ALL_CAPS, CAPS_PLUS, and DEFAULT_100.
Each of these is a tuple for converting int -> char.
char_to_num() creates a dictionary for converting char -> int.


In [2]:
print(ALL_CAPS)


('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z')

In [3]:
for key, val in sorted(char_to_num(ALL_CAPS).items()):
    print(key,val)


A 0
B 1
C 2
D 3
E 4
F 5
G 6
H 7
I 8
J 9
K 10
L 11
M 12
N 13
O 14
P 15
Q 16
R 17
S 18
T 19
U 20
V 21
W 22
X 23
Y 24
Z 25

Convert a string to a list of integers and back

Characters not in the selected alphabet will be discarded.


In [4]:
message = "WHERE IS RPT WHERE IS TASK FORCE THIRTY FOUR RR THE WORLD WONDERS?"
print(message)


WHERE IS RPT WHERE IS TASK FORCE THIRTY FOUR RR THE WORLD WONDERS?

In [5]:
# Default alphabet
ints = text_to_ints(message)
print(ints,'\n')

test_text = ints_to_text(ints)
print(test_text)


[55, 40, 37, 50, 37, 0, 41, 51, 0, 50, 48, 52, 0, 55, 40, 37, 50, 37, 0, 41, 51, 0, 52, 33, 51, 43, 0, 38, 47, 50, 35, 37, 0, 52, 40, 41, 50, 52, 57, 0, 38, 47, 53, 50, 0, 50, 50, 0, 52, 40, 37, 0, 55, 47, 50, 44, 36, 0, 55, 47, 46, 36, 37, 50, 51, 31] 

WHERE IS RPT WHERE IS TASK FORCE THIRTY FOUR RR THE WORLD WONDERS?

In [6]:
# ALL_CAPS alphabet has capital letters only, no punctuation or spaces
ints = text_to_ints(message,ALL_CAPS)
print(ints,'\n')

test_text = ints_to_text(ints,ALL_CAPS)
print(test_text)


[22, 7, 4, 17, 4, 8, 18, 17, 15, 19, 22, 7, 4, 17, 4, 8, 18, 19, 0, 18, 10, 5, 14, 17, 2, 4, 19, 7, 8, 17, 19, 24, 5, 14, 20, 17, 17, 17, 19, 7, 4, 22, 14, 17, 11, 3, 22, 14, 13, 3, 4, 17, 18] 

WHEREISRPTWHEREISTASKFORCETHIRTYFOURRRTHEWORLDWONDERS

Classic Caesar cipher: subtract 3 (mod 26)

The Caesar cipher shifts each letter in the alphabet back 3 places.
The alphabet "wraps around," meaning the letters ABC are mapped to XYZ.

To reproduce the Caesar cipher with Fidelio, first use ALL_CAPS to convert text to integers.
Then subtract 3 using base 26 modular arithmetic and convert back to text.

To decrypt, do the same, but with a shift of +3 instead of -3.


In [7]:
ciphertext = caesar(message,-3,ALL_CAPS)
print(ciphertext)

plaintext = caesar(ciphertext,3,ALL_CAPS)
print(plaintext)


TEBOBFPOMQTEBOBFPQXPHCLOZBQEFOQVCLROOOQEBTLOIATLKABOP
WHEREISRPTWHEREISTASKFORCETHIRTYFOURRRTHEWORLDWONDERS

ROT13 cipher: add 13 (mod 26)

ROT13 is like the classic Caesar cipher, but it shifts each letter 13 characters forward: $m \rightarrow (m + 13) \% 26$.
Shifting each letter 13 characters backward gives the same effect: $m \rightarrow (m-13)\%26 = (m+13)\%26$.
The ROT13 transformation is its own inverse.


In [8]:
ciphertext = caesar(message,13,ALL_CAPS)
print(ciphertext)

plaintext = caesar(ciphertext,-13,ALL_CAPS)
print(plaintext)

# With a 26-character alphabet, +13 and -13 are the same shift
plaintext = caesar(ciphertext,13,ALL_CAPS)
print(plaintext)


JURERVFECGJURERVFGNFXSBEPRGUVEGLSBHEEEGURJBEYQJBAQREF
WHEREISRPTWHEREISTASKFORCETHIRTYFOURRRTHEWORLDWONDERS
WHEREISRPTWHEREISTASKFORCETHIRTYFOURRRTHEWORLDWONDERS

In [9]:
# With the default 100-character alphabet, ROT50 is its own inverse
caesar(caesar(message,50),50)


Out[9]:
'WHERE IS RPT WHERE IS TASK FORCE THIRTY FOUR RR THE WORLD WONDERS?'

Fancy Caesar: add $x$ (mod $n$)

Fidelio can create Caesar-type ciphers with any shift value and any of its alphabets.


In [10]:
ciphertext = caesar(message,13,CAPS_PLUS)
print(ciphertext)

plaintext = caesar(ciphertext,-13,CAPS_PLUS)
print(plaintext)


4UR/RMV0M/?1M4UR/RMV0M1N0XMS./PRM1UV/16MS.2/M//M1URM4./YQM4.,QR/0 
WHERE IS RPT WHERE IS TASK FORCE THIRTY FOUR RR THE WORLD WONDERS?

Cracking Caesar ciphers

The shift amount is effectively the password for a Caesar cipher.
There aren't many possible passwords, so Caesar ciphers are vulnerable to brute-force attacks.


In [11]:
for x in range(42):
    print( caesar(ciphertext,x,CAPS_PLUS) )


4UR/RMV0M/?1M4UR/RMV0M1N0XMS./PRM1UV/16MS.2/M//M1URM4./YQM4.,QR/0 
5VS0SNW1N0!2N5VS0SNW1N2O1YNT?0QSN2VW027NT?30N00N2VSN5?0ZRN5?.RS01A
6WT1TOX2O1/3O6WT1TOX2O3P2ZOU!1RTO3WX138OU!41O11O3WTO6!1,SO6!?ST12B
7XU2UPY3P204P7XU2UPY3P4Q3,PV/2SUP4XY249PV/52P22P4XUP7/2.TP7/!TU23C
8YV3VQZ4Q315Q8YV3VQZ4Q5R4.QW03TVQ5YZ35 QW063Q33Q5YVQ803?UQ80/UV34D
9ZW4WR,5R426R9ZW4WR,5R6S5?RX14UWR6Z,46ARX174R44R6ZWR914!VR910VW45E
 ,X5XS.6S537S ,X5XS.6S7T6!SY25VXS7,.57BSY285S55S7,XS 25/WS 21WX56F
A.Y6YT?7T648TA.Y6YT?7T8U7/TZ36WYT8.?68CTZ396T66T8.YTA360XTA32XY67G
B?Z7ZU!8U759UB?Z7ZU!8U9V80U,47XZU9?!79DU,4 7U77U9?ZUB471YUB43YZ78H
C!,8,V/9V86 VC!,8,V/9V W91V.58Y,V !/8 EV.5A8V88V !,VC582ZVC54Z,89I
D/.9.W0 W97AWD/.9.W0 WAX 2W?69Z.WA/09AFW?6B9W99WA/.WD693,WD65,.9 J
E0? ?X1AX 8BXE0? ?X1AXBYA3X!7 ,?XB01 BGX!7C X  XB0?XE7 4.XE76.? AK
F1!A!Y2BYA9CYF1!A!Y2BYCZB4Y/8A.!YC12ACHY/8DAYAAYC1!YF8A5?YF87?!ABL
G2/B/Z3CZB DZG2/B/Z3CZD,C5Z09B?/ZD23BDIZ09EBZBBZD2/ZG9B6!ZG98!/BCM
H30C0,4D,CAE,H30C0,4D,E.D6,1 C!0,E34CEJ,1 FC,CC,E30,H C7/,H 9/0CDN
I41D1.5E.DBF.I41D1.5E.F?E7.2AD/1.F45DFK.2AGD.DD.F41.IAD80.IA 01DEO
J52E2?6F?ECG?J52E2?6F?G!F8?3BE02?G56EGL?3BHE?EE?G52?JBE91?JBA12EFP
K63F3!7G!FDH!K63F3!7G!H/G9!4CF13!H67FHM!4CIF!FF!H63!KCF 2!KCB23FGQ
L74G4/8H/GEI/L74G4/8H/I0H /5DG24/I78GIN/5DJG/GG/I74/LDGA3/LDC34GHR
M85H509I0HFJ0M85H509I0J1IA06EH350J89HJO06EKH0HH0J850MEHB40MED45HIS
N96I61 J1IGK1N96I61 J1K2JB17FI461K9 IKP17FLI1II1K961NFIC51NFE56IJT
O 7J72AK2JHL2O 7J72AK2L3KC28GJ572L AJLQ28GMJ2JJ2L 72OGJD62OGF67JKU
PA8K83BL3KIM3PA8K83BL3M4LD39HK683MABKMR39HNK3KK3MA83PHKE73PHG78KLV
QB9L94CM4LJN4QB9L94CM4N5ME4 IL794NBCLNS4 IOL4LL4NB94QILF84QIH89LMW
RC M 5DN5MKO5RC M 5DN5O6NF5AJM8 5OCDMOT5AJPM5MM5OC 5RJMG95RJI9 MNX
SDANA6EO6NLP6SDANA6EO6P7OG6BKN9A6PDENPU6BKQN6NN6PDA6SKNH 6SKJ ANOY
TEBOB7FP7OMQ7TEBOB7FP7Q8PH7CLO B7QEFOQV7CLRO7OO7QEB7TLOIA7TLKABOPZ
UFCPC8GQ8PNR8UFCPC8GQ8R9QI8DMPAC8RFGPRW8DMSP8PP8RFC8UMPJB8UMLBCPQ,
VGDQD9HR9QOS9VGDQD9HR9S RJ9ENQBD9SGHQSX9ENTQ9QQ9SGD9VNQKC9VNMCDQR.
WHERE IS RPT WHERE IS TASK FORCE THIRTY FOUR RR THE WORLD WONDERS?
XIFSFAJTASQUAXIFSFAJTAUBTLAGPSDFAUIJSUZAGPVSASSAUIFAXPSMEAXPOEFST!
YJGTGBKUBTRVBYJGTGBKUBVCUMBHQTEGBVJKTV,BHQWTBTTBVJGBYQTNFBYQPFGTU/
ZKHUHCLVCUSWCZKHUHCLVCWDVNCIRUFHCWKLUW.CIRXUCUUCWKHCZRUOGCZRQGHUV0
,LIVIDMWDVTXD,LIVIDMWDXEWODJSVGIDXLMVX?DJSYVDVVDXLID,SVPHD,SRHIVW1
.MJWJENXEWUYE.MJWJENXEYFXPEKTWHJEYMNWY!EKTZWEWWEYMJE.TWQIE.TSIJWX2
?NKXKFOYFXVZF?NKXKFOYFZGYQFLUXIKFZNOXZ/FLU,XFXXFZNKF?UXRJF?UTJKXY3
!OLYLGPZGYW,G!OLYLGPZG,HZRGMVYJLG,OPY,0GMV.YGYYG,OLG!VYSKG!VUKLYZ4
/PMZMHQ,HZX.H/PMZMHQ,H.I,SHNWZKMH.PQZ.1HNW?ZHZZH.PMH/WZTLH/WVLMZ,5
0QN,NIR.I,Y?I0QN,NIR.I?J.TIOX,LNI?QR,?2IOX!,I,,I?QNI0X,UMI0XWMN,.6
1RO.OJS?J.Z!J1RO.OJS?J!K?UJPY.MOJ!RS.!3JPY/.J..J!ROJ1Y.VNJ1YXNO.?7
2SP?PKT!K?,/K2SP?PKT!K/L!VKQZ?NPK/ST?/4KQZ0?K??K/SPK2Z?WOK2ZYOP?!8
3TQ!QLU/L!.0L3TQ!QLU/L0M/WLR,!OQL0TU!05LR,1!L!!L0TQL3,!XPL3,ZPQ!/9

Dodgson cipher (aka Vigenère cipher, Bellaso cipher)

This polyalphabetic cipher shifts characters using modular arithmetic, but characters are not all shifted by the same amount. There are many possible passwords, so brute-force attacks are much harder.

Choose a password, and be sure to use characters which are in the selected alphabet. The password is then repeated until it is the same length as the plaintext. Each integer $m_k$ in the plaintext is shifted $$ m_k \rightarrow (m_k+x_k) \% 26 $$ where $x_k$ is the corresponding integer in the extended password.


In [12]:
ints = text_to_ints('MEETMEATDAWN',ALL_CAPS)
print(ints,'\n')

extended_password = text_to_ints('FIDELIOFIDEL',ALL_CAPS)
print(extended_password,'\n')

cipher = [ (ints[k] + extended_password[k]) % 26 for k in range(len(ints)) ]
print(cipher,'\n')

ciphertext = ints_to_text(cipher,ALL_CAPS)
print(ciphertext,'\n')

decipher = [ (cipher[k] - extended_password[k]) % 26 for k in range(len(cipher)) ]
print(decipher,'\n')

plaintext = ints_to_text(decipher,ALL_CAPS)
print(plaintext)


[12, 4, 4, 19, 12, 4, 0, 19, 3, 0, 22, 13] 

[5, 8, 3, 4, 11, 8, 14, 5, 8, 3, 4, 11] 

[17, 12, 7, 23, 23, 12, 14, 24, 11, 3, 0, 24] 

RMHXXMOYLDAY 

[12, 4, 4, 19, 12, 4, 0, 19, 3, 0, 22, 13] 

MEETMEATDAWN

In [13]:
# Try the original message and default alphabet
ciphertext = dodgson(message,'FIDELIO')
print(ciphertext)
plaintext = dodgson(ciphertext,'FIDELIO',decrypt=True)
print(plaintext)


}qiwqIxyIvu∀I"nnvjLr¬F}exwIuu{gjL}wo{x~Lo~{{Dw~I∞nnD|{{{jI{tzmtx|c
WHERE IS RPT WHERE IS TASK FORCE THIRTY FOUR RR THE WORLD WONDERS?

In [14]:
# Let's try guessing the password
dodgson(ciphertext,'12345',decrypt=True)


Out[14]:
'l_Vc\\8ff5adn6rY]dW8]q4jQcf7bafVX9ib^iej7^lhg/fl6oY]2igfjX6g_i[adgR'

In [15]:
# Caution: a partially-correct password can recover parts of the message
ciphertext = dodgson(message,'Passw0rd123')
print(ciphertext)
plaintext = dodgson(ciphertext,'password123',decrypt=True)
print(plaintext)


#%4A80731dc aF78b3dZe3 ¬B:wV=2TW3 %8AGir&`geP/AsGX3dhae|!sFB^2%ceR
7HEREEIS RP4 WHEwE IS 4ASK kORCE 4HIRT~ FOURdRR TmE WOR,D WOsDERS?