In de tumultueus verlopen Amerikaanse presidentsverkiezingen van 1876 stuurde het campagneteam van de democraat Samuel J. Tilden heel wat gecodeerde berichten naar haar tussenpersonen in de verschillende strijdstaten.

Tilden vs Hayes

Twee jaar na de verkiezingen publiceerde de New York Daily Tribune ontcijferde versies van enkele van deze telegrammen. Hieruit kon opgemaakt worden dat Tilden's campagneteam geprobeerd had om de verkiezingen te winnen door sommige verkiezingsbeambten om te kopen. Hier is één van die telegrammen:

gecodeerd telegram

Omdat er in het gecodeerde bericht maar 10 verschillende letters gebruikt worden, is het waarschijnlijk dat de code gebruik maakt van letterparen (bigrammen). Als we nu elk van de opeenvolgende letterparen uit het bericht afbeelden op een verschillende letter van het alfabet

afbeelding van bigrammen

dan wordt het het gecodeerde bericht een cryptogram dat eenvoudig kan ontcijferd worden.

ontcijferd telegram

Het campagneteam van Tilden deed hetzelfde met cijferparen. Zo bleek het telegram

gecodeerd telegram

bijvoorbeeld een gecodeerde versie te zijn van het bericht

ontcijferd telegram

In 1879 achterhaalden experten van de Tribune met welke letter- en cijferparen elk van de letters van het alfabet correspondeerden:

volledige afbeelding van bigrammen

Maar het was pas in 1952 dat cryptograaf William F. Friedman de oorspronkelijke tabel reconstrueerde die de tussenpersonen gebruikt hadden om de codeersleutel te kunnen onthouden:

encryption key

In zijn boek Secret Ciphers of the 1876 Presidential Election schreef Beaird Glover hierover:

"It is amusing to note that the conspirators selected as their key a phrase quite in keeping with their attempted illegalities — HIS PAYMENT — for bribery seems to have played a considerable part in that campaign."

Opgave

Je moet berichten coderen en decoderen door gebruik te maken van codeersleutels zoals deze die gebruikt werden door het campagneteam van Tilden. Hierbij worden alle letters van een bericht gecodeerd naar bigrammen die bestaan uit twee hoofdletters. Bij het coderen van een bericht wordt geen onderscheid gemaakt tussen hoofdletters en kleine letters, en worden alle karakters die geen letter zijn genegeerd.

Een codeersleutel bestaat uit twee onderdelen. Het eerste onderdeel is een sleutelwoord dat bestaat uit verschillende hoofdletters die gebruikt worden om de rijen en kolommen van een vierkant rooster te markeren. In onderstaand voorbeeld gebruiken we hiervoor het sleutelwoord ABCD.

sample key table

Het tweede onderdeel is een omschrijving die aangeeft hoe een aantal verschillende letters van het alfabet in het rooster moeten ingevuld worden. Zo een omschrijving bestaat alternerend uit reeksen opeenvolgende hoofdletters en getallen (die uit meerdere cijfers kunnen bestaan), en kan zowel met een hoofdletter als met een getal beginnen. Deze omschrijving wordt gebruikt om het rooster in te vullen met de hoofdletters uit de omschrijving. We beginnen hierbij in de cel linksboven. Een hoofdletter geeft aan dat die letter in de huidige cel moet ingevuld worden. Een getal geeft aan dat het overeenkomstig aantal cellen moet overgeslaan worden als we het rooster van links naar rechts en van boven naar onder doorlopen. Zo komt de plaatsing van de letters in bovenstaand voorbeeldrooster overeen met de omschrijving 1AX3S1M2PYZ. Merk op dat we na de laatste Z in de omschrijving ook nog het getal 2 mogen zetten om aan te geven dat de laatste twee cellen van het rooster leeg zijn, maar dat is optioneel.

Gevraagd wordt om een klasse Codeersleutel te definiëren. Bij het instantiëren van objecten van deze klasse moeten een sleutelwoord (String) en een omschrijving (String) opgegeven worden die de codeersleutel vastleggen. Hierbij mag je ervan uitgaan dat zowel het sleutelwoord als de omschrijving geldig zijn. De objecten van deze klasse zijn onveranderlijk (immutable) en moeten minstens de volgende eigenschappen hebben:

Voorts moet de klasse Codeersleutel minstens de volgende methoden ondersteunen:

Voorbeeld

> const sleutel = new Codeersleutel("ABCD", "1AX3S1M2PYZ");
> sleutel.rooster
[["-", "A", "X", "-"], ["-", "-", "S", "-"], ["M", "-", "-", "P"], ["Y", "Z", "-", "-"]]
> sleutel.afbeelding
{"A": "AB", "X": "AC", "S": "BC", "M": "CA", "P": "CD", "Y": "DA", "Z": "DB"}
> sleutel.codeer("spam")
"BCCDABCA"
> sleutel.decodeer("BCCDABCA")
"SPAM"
> sleutel.codeer("eggs")
Error: ongeldig bericht
> sleutel.decodeer("BCCDBACA")
Error: ongeldig bericht

> const sleutel02 = new Codeersleutel("HISPAYMENT", "14K1S2DL1NW4P2R1H3T3U2O6X3A1F6B1G4I1C2V1Y3E2M2J");
> sleutel02.rooster
[["-", "-", "-", "-", "-", "-", "-", "-", "-", "-"], ["-", "-", "-", "-", "K", "-", "S", "-", "-", "D"], ["L", "-", "N", "W", "-", "-", "-", "-", "P", "-"], ["-", "R", "-", "H", "-", "-", "-", "T", "-", "-"], ["-", "U", "-", "-", "O", "-", "-", "-", "-", "-"], ["-", "X", "-", "-", "-", "A", "-", "F", "-", "-"], ["-", "-", "-", "-", "B", "-", "G", "-", "-", "-"], ["-", "I", "-", "C", "-", "-", "V", "-", "Y", "-"], ["-", "-", "E", "-", "-", "M", "-", "-", "J", "-"], ["-", "-", "-", "-", "-", "-", "-", "-", "-", "-"]]
> sleutel02.afbeelding
{"T": "PE", "Y": "EN", "M": "NY", "J": "NN", "A": "YY", "F": "YE", "G": "MM", "O": "AA", "V": "EM", "I": "EI", "R": "PI", "S": "IM", "X": "YI", "H": "PP", "D": "IT", "U": "AI", "N": "SS", "C": "EP", "P": "SN", "K": "IA", "B": "MA", "L": "SH", "W": "SP", "E": "NS"}
> sleutel02.codeer("Have Marble and Coyle telegraph for influential men from Delaware and Virginia.")
"PPYYEMNSNYYYPIMASHNSYYSSITEPAAENSHNSPENSSHNSMMPIYYSNPPYEAAPIEISSYESHAINSSSPEEIYYSHNYNSSSYEPIAANYITNSSHYYSPYYPINSYYSSITEMEIPIMMEISSEIYY"
> sleutel02.decodeer("PPYYEMNSNYYYPIMASHNSYYSSITEPAAENSHNSPENSSHNSMMPIYYSNPPYEAAPIEISSYESHAINSSSPEEIYYSHNYNSSSYEPIAANYITNSSHYYSPYYPINSYYSSITEMEIPIMMEISSEIYY")
"HAVEMARBLEANDCOYLETELEGRAPHFORINFLUENTIALMENFROMDELAWAREANDVIRGINIA"
> sleutel02.codeer("Indications of weakening here.")
"EISSITEIEPYYPEEIAASSIMAAYESPNSYYIANSSSEISSMMPPNSPINS"
> sleutel02.decodeer("EISSITEIEPYYPEEIAASSIMAAYESPNSYYIANSSSEISSMMPPNSPINS")
"INDICATIONSOFWEAKENINGHERE"
> sleutel02.codeer("Press advantage and watch Board.")
"SNPINSIMIMYYITEMYYSSPEYYMMNSYYSSITSPYYPEEPPPMAAAYYPIIT"
> sleutel02.decodeer("SNPINSIMIMYYITEMYYSSPEYYMMNSYYSSITSPYYPEEPPPMAAAYYPIIT")
"PRESSADVANTAGEANDWATCHBOARD"