Tijdens de Vietnamoorlog maakte het Amerikaanse leger gebruik van het Diana Cryptosystem. Deze methode om berichten te coderen en decoderen kan in theorie niet gekraakt worden indien ze volgens de regels van de kunst gebruikt wordt. De versleuteling is gebaseerd op twee technieken.
Eerst en vooral wordt er gebruikgemaakt van een trigraph om twee letters om te zetten naar een derde letter. Deze omzetting gebeurt aan de hand van een vaste tabel — waarvan hieronder een voorbeeld gegeven wordt — waarbij twee zwarte letters telkens een rode letter opleveren. Typisch aan deze omzetting is dat voor elk drietal letters geldt dat twee van de drie letters door de trigraph steeds worden omgezet in de derde letter. Als we bijvoorbeeld weten dat de letters B en K de letter O opleveren, dan leveren ook K en B de letter O op, maar leveren ook K en O de letter B op, en leveren ook O en B de letter K op. Eigenlijk kan de omzetting ook makkelijk berekend worden. Als we de twee gegeven letters in het alfabet terugvinden op posities $$p_1$$ en $$p_2$$ (waarbij A op positie 0 staat, B op positie 1, enzoverder), dan vinden we de derde letter in het alfabet terug op positie $$(25 - p_1 - p_2)\ \textrm{mod}\ 26$$. Hierbij staat de operator $$\textrm{mod}$$ voor de rest na gehele deling.
Daarnaast wordt gebruikgemaakt van een one-time pad. Dit is eigenlijk niets anders dan een willekeurige opeenvolging van letters. Voor de leesbaarheid worden deze vaak weergegeven in groepen van vijf letters, maar elk karakter dat geen letter is moet genegeerd worden in het one-time pad (dus ook de spaties). Als voorbeeld beschouwen we het volgende one-time pad.
WHTVI AUCFU RETFK OMSAL MYMNE ZIEGP UKVTF WZHOK GORWY WETFR COYET OOWHY ZPDDA CMMXT VYTJI RRQGU VAXPM IPIXU QUXIP MAXIU
Om dan bijvoorbeeld het bericht ATTACK AT DAWN te coderen, gaan we als volgt te werk. Eerst wordt er een willekeurig fragment van een vooraf afgesproken lengte gekozen uit het one-time pad. Stel bijvoorbeeld dat we kiezen voor de tien letters UKVTF WZHOK. De letters van het bericht (alle karakters die geen letter zijn worden genegeerd) worden dan onder de letters van het one-time pad geschreven die volgen op het willekeurig gekozen fragment. Daarna wordt elk paar letters (een letter uit het one-time pad en een letter uit het origineel bericht op dezelfde positie) omgezet naar een derde letter door gebruik te maken van een trigraph. Deze laatste letters leveren uiteindelijk het gecodeerde bericht op.
one-time pad: UKVTF WZHOK GORWY WETFR COYET OOWHY origineel bericht: ATTAC KATDA WN ----------------------------------- gecodeerd bericht: TSPDZ TVNRI BY
Het bericht UKVTF WZHOK TSPDZ TVNRI BY wordt dan verstuurd in morsecode. Hierbij wordt dus eerst het willekeurige fragment van tien letters in niet-gecodeerde vorm verstuurd, gevolgd door het gecodeerde bericht zelf. Omwille van de symmetrie van de trigraph werkt het decoderen van een bericht volgens exact dezelfde procedure als het coderen. Eerst zoekt de ontvanger de eerste tien letters van het bericht op in het one-time pad (de ontvanger moet hiervoor hetzelfde one-time pad gebruiken als de verzender), en decodeert het dan opnieuw door gebruik te maken van een trigraph.
one-time pad: UKVTF WZHOK GORWY WETFR COYET OOWHY gecodeerd bericht: TSPDZ TVNRI BY ----------------------------------- origineel bericht: ATTAC KATDA WN
Een soldaat die meestreed tijdens de Vietnamoorlog verwoordde het gebruik van het Diana Cryptosystem op de volgende manier:
Special Forces were one of (if not the only) units in Vietnam to utilize Morse code on a regular basis. We used a method of encryption called the Diana Cryptosystem.
The basis of these one-time pads, is that there were only two matching pads in existence, and they would only be used one time. They were booklets that contained randomly generated groups of 5-letter words, 30 words to a page. The person sending a message would first write the letters to the message, over these random groups of words. Included in the front of each one-time pad was a one-page encryption table. If I wanted to send the letter P, and the letter under the P was an A, then I would send a K. The person listening on the frequency at the other end, would have the other matching pad. They would write the letter they received (a K) over the letter in their one-time pad (an A), and decipher it based on the table, yielding the original letter P.
Each communication site in Vietnam (we had over 100 A-Camps along the Cambodian / Laotian border, and some 20 B-detachment sites spread over the country) had a different pad, depending on the location they were having the commo-check with. It obviously was very important that both people were using the appropriate matching pads, or the deciphered messages would not make any sense.
After a while, most of us became so proficient with the system, that we actually learned the deciphering matrix by heart. No matter what pads anyone had, the combinations always were the same. i.e. Any 3 letters always went together, regardless of the order; BKO/KOB/OBK/BOK. After listening to thousands and thousands of transmissions, it really got quite simple. If I was listening to code, and a letter B was sent (now remember, we usually sent around 20-25 words (5 letters per word) a minute, hence the importance of the speed keys!), and the letter it was associated with was an O, most of us would decipher as we heard it, and just write the K. That may sound like quite a yarn, but it is absolutely true.
De combinatie trigraph en one-time pad levert een zeer sterke vorm van encryptie op. In de veronderstelling dat de letters van het pad echt willekeurig gegenereerd worden, nooit hergebruikt worden en niet gecompromiteerd zijn, kan aangetoond worden dat de code onbreekbaar is. Het is daarom niet verwonderlijk dat heel wat inlichtingendiensten gebruik maakten en maken van deze vorm van encryptie. De KGB gaf aan haar agenten bijvoorbeeld vaak one-time pads mee die gedrukt waren op flash paper — papier dat chemisch omgezet werd naar nitrocellulose, waardoor het bijna onmiddellijk verbrandt zonder as na te laten.
Definieer een klasse Diana waarmee berichten kunnen gecodeerd en gedecodeerd worden volgens het Diana Cryptosystem met een vooraf vastgelegd one-time pad. Deze klasse moet minstens de volgende methoden ondersteunen:
Een initialisatiemethode __init__ waaraan de locatie van een tekstbestand moet doorgegeven worden. Dit tekstbestand moet de letters van een one-time pad bevatten. Hierbij mag het tekstbestand bestaan uit meerdere regels, en naast letters ook andere karakters bevatten. Het one-time pad zelf wordt opgebouwd uit de opeenvolgende letters in het bestand, waarbij de andere karakters genegeerd worden.
Een methode index waaraan een string moet doorgegeven worden. De methode moet de gegeven string herleiden tot een reeks opeenvolgende letters (alle karakters die geen letter zijn moeten hierbij dus genegeerd worden), en moet het eerste voorkomen van deze reeks letters opzoeken in het one-time pad. Bij het opzoeken mag geen onderscheid gemaakt worden tussen hoofdletters en kleine letters. Indien de reeks letters voorkomt in het one-time pad, dan moet de methode de positie teruggeven van de eerste letter die volgt op de reeks letters in het one-time pad. Hierbij staat de eerste letter van het one-time pad op positie 0, de tweede letter op positie 1, enzoverder. Indien de reeks letters niet voorkomt in het one-time pad, dan moet de methode een AssertionError opwerpen met de boodschap ongeldige prefix.
Een methode trigraph waaraan twee strings moeten doorgegeven worden die elk bestaan uit één enkele letter. De methode moet de hoofdletter teruggeven waarop de twee gegeven letters worden afgebeeld volgens een trigraph.
Een methode codeer waaraan een string moet doorgegeven worden. De gegeven string moet bestaan uit een reeks letters die voorkomen in het one-time pad, gevolgd door de letters van een bericht dat moet gecodeerd worden volgens het Diana Cryptosystem. Het bericht mag zowel hoofdletters als kleine letters bevatten. Naast letters mag de gegeven string ook andere karakters bevatten, die echter moeten genegeerd worden bij het coderen. De methode heeft ook nog een tweede optionele parameter waaraan een integer $$n$$ kan doorgegeven worden die aangeeft hoeveel letters van de string moeten gebruikt worden voor het opzoeken in het one-time pad (standaardwaarde: $$n=10$$). De methode moet het gecodeerde bericht teruggeven, dat enkel mag bestaan uit hoofdletters. Indien de eerste $$n$$ letters van de gegeven string niet teruggevonden worden in het one-time pad, dan moet de methode een AssertionError opwerpen met de boodschap ongeldige prefix. Indien er na het voorkomen van de eerste $$n$$ letters van de gegeven string in het one-time pad minder letters volgen dan er letters zijn in het gegeven bericht, dan moet de methode een AssertionError opwerpen met de boodschap one-time pad is te kort.
Een methode decodeer die op exact dezelfde manier werkt als de methode codeer, en dus kan gebruikt worden om gecodeerde berichten te decoderen. We herhalen hier nogmaals dat bij het Diana Cryptosystem het coderen en decoderen werkt volgens exact dezelfde procedure.
Bij onderstaande voorbeeldsessie gaan we ervan uit dat het tekstbestand otp.txt1 zich in de huidige directory bevindt.
>>> diana = Diana('otp.txt')
>>> diana.index('UKVTF WZHOK')
40
>>> diana.index('CMMXT VYTJI RRQGU')
80
>>> diana.index('ABCDE FGHIJ')
Traceback (most recent call last):
AssertionError: ongeldige prefix
>>> diana.trigraph('Q', 'K')
'Z'
>>> diana.trigraph('t', 'f')
'B'
>>> diana.codeer('UKVTF WZHOK attack at dawn')
'TSPDZTVNRIBY'
>>> diana.codeer('CMMXT VYTJI RRQGU meet at ten tonight', 15)
'SVYRNYRNPMVSULDU'
>>> diana.codeer('ABCDE FGHIJ zero dark thirty')
Traceback (most recent call last):
AssertionError: ongeldige prefix
>>> diana.codeer('VAXPM IPIXU zero dark thirty')
Traceback (most recent call last):
AssertionError: one-time pad is te kort
>>> diana.decodeer('UKVTF WZHOK TSPDZ TVNRI BY')
'ATTACKATDAWN'
>>> diana.decodeer('CMMXT VYTJI RRQGU SVYRN YRNPM VSULD U', 15)
'MEETATTENTONIGHT'
>>> diana.decodeer('ABCDE FGHIJ zero dark thirty')
Traceback (most recent call last):
AssertionError: ongeldige prefix
>>> diana.decodeer('VAXPM IPIXU zero dark thirty')
Traceback (most recent call last):
AssertionError: one-time pad is te kort