Kapitel 4 · Lszqupmphjf?!

Die Skytale von Sparta in Python

Eines der ältesten überlieferten Verschlüsselungsverfahren braucht nur einen Holzstab und einen schmalen Streifen Pergament. Die Buchstaben bleiben, wie sie sind – nur ihre Reihenfolge ändert sich. Das Programm schreibt den Text auf den Stab, wickelt den Streifen ab und liest ihn mit vertauschten Zeilen und Spalten wieder zurück.

Aus dem Buch · Kapitel 4 Einsteiger VerschlüsselungText & SprachePython 3 · läuft im Browser
Bereit · Python startet beim ersten Klick
# Die Skytale von Sparta – Kapitel 4 »Lszqupmphjf?!«
# aus »Coding for Fun mit Python«, portiert auf Python 3 und c4f
import math
from c4f import Screen, sleep


# stellt sicher, dass die Länge des Textes
# ohne Rest durch den Umfang teilbar ist
def ensureSideCondition(text, umfang):
    length      = len(text)
    remainder   = length % umfang
    while remainder != 0:
        text       += " "
        length      = len(text)
        remainder   = length % umfang

    return text


def skytale_encrypt(text, umfang):
    text    = ensureSideCondition(text, umfang)
    length  = len(text)
    cipher  = ""
    for x in range(0, umfang):
        for y in range(x, length, umfang):
            cipher += text[y]

    return cipher.upper()


def skytale_decrypt(text, umfang):
    length      = len(text)
    umfang      = length // umfang
    plaintext   = skytale_encrypt(text, umfang)

    return plaintext.lower()


key         = 8
plaintext   = "heute ist sehr schönes wetter"
cipher      = skytale_encrypt(plaintext, key)

print(plaintext)
print(cipher)
print(skytale_decrypt(cipher, key))

receiverKey = key  # der Empfänger hat einen Stab mit demselben Umfang

# --- Die Skytale im Bild (neu im Browser) ----------------------------------
lettersPerSecond = 12
W, H      = 720, 420
INK       = (27, 28, 32)
MUTED     = (118, 122, 132)
PARCHMENT = (240, 228, 198)
EDGE      = (186, 164, 122)
WOOD      = (156, 110, 66)
DARK      = (112, 76, 44)
MARK      = (252, 226, 130)
READ      = (226, 234, 252)
BLUE      = (47, 85, 212)

screen = Screen(W, H, background=(252, 251, 247), title="Skytale")


def show(letter):
    return "␣" if letter == " " else letter


def arrow(start, end, color):
    screen.line(start, end, color, 2)
    (x1, y1), (x2, y2) = start, end
    angle = math.atan2(y2 - y1, x2 - x1)
    screen.polygon([(x2, y2),
                    (x2 - 10 * math.cos(angle - 0.4), y2 - 10 * math.sin(angle - 0.4)),
                    (x2 - 10 * math.cos(angle + 0.4), y2 - 10 * math.sin(angle + 0.4))], color)


def drawRod(letters, highlight=None):
    # Der Stab mit dem aufgewickelten Streifen wie in Abbildung 4.3:
    # Jede Windung trägt ein Zeichen der vordersten Zeile.
    x0, x1, y, h = 110, 610, 64, 46
    screen.rect(x0 - 70, y + 7, x1 - x0 + 140, h - 14, WOOD)
    screen.ellipse(x0 - 82, y + 7, 24, h - 14, DARK)
    screen.ellipse(x1 + 58, y + 7, 24, h - 14, WOOD)
    band = (x1 - x0) / len(letters)
    for i, letter in enumerate(letters):
        x = x0 + i * band
        color = MARK if i == highlight else PARCHMENT
        screen.polygon([(x + 6, y), (x + band + 4, y), (x + band - 6, y + h), (x - 4, y + h)], color)
        screen.line((x + 6, y), (x - 4, y + h), EDGE, 1.5)
        if letter is not None:
            screen.text(letter, (x + band / 2, y + h / 2), INK, size=22, align="center",
                        baseline="middle", font="serif", bold=True)


def drawGrid(cells, columns, top, bottom, labels, lit=None, done=()):
    # Die »Skytale für unterwegs« aus Abbildung 4.4: eine Tabelle
    rows = len(cells) // columns
    size = min(36, 520 / columns, (bottom - top) / rows)
    left = (W - size * columns) / 2
    for i, letter in enumerate(cells):
        row, column = divmod(i, columns)
        x, y = left + column * size, top + row * size
        fill = MARK if i == lit else (READ if i in done else (255, 255, 255))
        screen.rect(x, y, size, size, fill)
        screen.rect(x, y, size, size, (200, 204, 212), width=1)
        if letter is not None:
            screen.text(show(letter), (x + size / 2, y + size / 2), INK, size=size * 0.55,
                        align="center", baseline="middle", font="mono")
    width, height = size * columns, size * rows
    arrow((left, top - 12), (left + width, top - 12), MUTED)
    screen.text(labels[0], (left + width / 2, top - 30), MUTED, size=14, align="center")
    arrow((left - 14, top), (left - 14, top + height), MUTED)
    screen.push()
    screen.translate(left - 30, top + height / 2)
    screen.rotate(-90)
    screen.text(labels[1], (0, 0), MUTED, size=14, align="center", baseline="middle")
    screen.pop()


def drawStrip(letters, total, y=326):
    # Der abgewickelte Streifen – so wird die Nachricht verschickt
    perLine = 32
    w = min(20, 640 / min(total, perLine))
    for line in range(math.ceil(total / perLine)):
        n = min(perLine, total - line * perLine)
        x0 = (W - n * w) / 2
        screen.rect(x0 - 6, y + line * 34, n * w + 12, 28, PARCHMENT)
        screen.rect(x0 - 6, y + line * 34, n * w + 12, 28, EDGE, width=1)
    for i, letter in enumerate(letters):
        line, pos = divmod(i, perLine)
        n = min(perLine, total - line * perLine)
        x0 = (W - n * w) / 2
        screen.text(show(letter), (x0 + pos * w + w / 2, y + line * 34 + 14), INK, size=16,
                    align="center", baseline="middle", font="mono")


async def wrapAndRead(text, columns, title, labels, withRod, convert, result):
    """Schreibt text Zeile für Zeile in die Tabelle und liest ihn Spalte für Spalte aus."""
    text  = ensureSideCondition(text, columns)
    rows  = len(text) // columns
    cells = [None] * len(text)
    top   = 158 if withRod else 86
    # dieselbe Reihenfolge wie die beiden Schleifen in skytale_encrypt()
    order = [y for x in range(0, columns) for y in range(x, len(text), columns)]
    strip = []

    def draw(step, lit=None, done=()):
        screen.clear()
        screen.text(title, (30, 12), INK, size=19, bold=True)
        screen.text(step, (30, 38), MUTED, size=14)
        if withRod:
            column = lit % columns if lit is not None and done else None
            drawRod(cells[:columns], highlight=column)
        drawGrid(cells, columns, top, 304, labels, lit, done)
        drawStrip(strip, len(text))
        screen.text(f"{columns} Zeichen pro Zeile · {rows} Zeilen", (W - 30, H - 22), BLUE,
                    size=14, align="right")

    for i, letter in enumerate(text):
        cells[i] = letter
        draw("1. Den Text Zeile für Zeile eintragen", lit=i)
        await screen.frame(lettersPerSecond)

    done = set()
    for i in order:
        strip.append(convert(text[i]))
        done.add(i)
        draw("2. Spalte für Spalte ablesen – so entsteht der Streifen", lit=i, done=done)
        await screen.frame(lettersPerSecond)

    draw(result, done=done)
    await screen.frame()
    return "".join(strip)


await wrapAndRead(plaintext, key, "Verschlüsseln mit der Skytale", ("Klartext", "Geheimtext"),
                  True, str.upper, "Fertig: Der Streifen trägt dieselben Buchstaben in neuer Reihenfolge")
await sleep(2.5)
await wrapAndRead(cipher, len(cipher) // receiverKey, "Entschlüsseln: Zeilen und Spalten tauschen",
                  ("Geheimtext", "Klartext"), False, str.lower, "Fertig: Spaltenweise gelesen steht da wieder der Klartext")
Holzstab mit schräg gewickeltem Pergamentstreifen, darunter eine Tabelle mit dem Klartext und der abgewickelte Streifen mit dem Geheimtext

Erst wird verschlüsselt, dann mit vertauschten Zeilen und Spalten wieder entschlüsselt. Die Konsole zeigt die drei Zeilen aus dem Buch.

Konsole

    

Was du hier lernst

  • Transposition
  • Verschachtelte Schleifen
  • range() mit Schrittweite
  • Modulo-Rechnung
  • Ganzzahldivision //
  • Strings zusammensetzen

Die Erklärung stammt – leicht überarbeitet für Python 3 – aus dem Buch „Coding for Fun mit Python“ von Lars Heppert, Kapitel 4, Abschnitte 4.3 und 4.4.

Seit wann wird chiffriert?

Kürzestmögliche Antwort: seit einer Ewigkeit, mindestens seit der Zeit der Pharaonen. Allerdings waren die Mittel, um Nachrichten zu verschlüsseln, denkbar einfach im Vergleich zu den heutigen ausgeklügelten Systemen. Selbst die Verfahren der Römer sind für heutige Verhältnisse sehr leicht zu knacken – auch für dich.

Eines der ältesten überlieferten Verfahren ist unter dem Namen Skytale von Sparta bekannt. Die Griechen verwendeten es, um geheime Botschaften durch Transposition zu verschlüsseln. Bei einem Transpositionsverfahren werden die Buchstaben des Klartextes nicht verändert, sondern nur ihre Positionen innerhalb der Nachricht vertauscht.

Die Skytale beruhte darauf, dass Absender und Empfänger je einen Stab mit gleichem Durchmesser besaßen. Um den Stab wickelte man spiralförmig einen schmalen Streifen Pergament und beschriftete ihn längs zum Stab. Abgewickelt zeigt der Streifen nur noch Buchstabensalat. Zum Ablesen musste man das Pergament wieder um einen Stab mit demselben Durchmesser wickeln. Der Durchmesser des Stabes war also der Schlüssel und entsprechend geheim zu halten.

Ein Holzstab, um den ein Pergamentstreifen spiralförmig gewickelt ist; entlang des Stabes steht »DieSkytale«
Abbildung 4.3 aus dem Buch: die Skytale von Sparta

Ob die Spartaner ihre Stäbe wirklich zum Verschlüsseln benutzten, ist unter Historikern übrigens umstritten. Die antiken Quellen sind dünn, und manche Forscher halten die Skytale eher für ein Erkennungszeichen. Als Gedankenexperiment taugt sie trotzdem hervorragend.

Untereinander geschrieben

Wie sich die Zeichen verschieben, siehst du auch, wenn du den Text in Zeilen untereinanderschreibst:

heute ist sehr
schönes wetter

Zum Geheimtext gelangst du, indem du die beiden Zeilen spaltenweise liest: HSECUHTÖEN EISS TW ESTETHERR. Zum Entziffern musst du in diesem Fall nicht den Durchmesser des Stabes kennen, sondern die Anzahl der Zeichen pro Zeile. Mit diesem Wissen ist der Text leicht zu entziffern, aber auch ohne ist das Verfahren aus heutiger Sicht alles andere als sicher.

Trotzdem sind Transpositionen bis heute ein wichtiger Bestandteil vieler moderner Verfahren. Der Standard AES, der heute fast jede Internetverbindung schützt, vertauscht zum Beispiel in jeder Runde mit dem Schritt »ShiftRows« die Bytes seines Datenblocks – natürlich kombiniert mit weiteren, viel stärkeren Schritten.

Die Skytale von Sparta in Python

Die Skytale lässt sich mit Python sehr einfach nachprogrammieren und auch mit Papier und Bleistift simulieren. Beides schauen wir uns an. Beginnen wir mit der Funktion skytale_encrypt(), die sich um die Verschlüsselung kümmert:

def skytale_encrypt(text, umfang):
    text    = ensureSideCondition(text, umfang)
    length  = len(text)
    cipher  = ""
    for x in range(0, umfang):
        for y in range(x, length, umfang):
            cipher += text[y]

    return cipher.upper()

Der Parameter umfang gibt die Zeichen pro Zeile vor. Die Zeichen werden genau in diesem Abstand aneinandergehängt: Die äußere Schleife wählt mit x eine Spalte, die innere springt mit der Schrittweite umfang durch den Text – range(x, length, umfang) liefert die Positionen x, x + umfang, x + 2 · umfang und so weiter. Bei acht Zeichen pro Zeile sind das für die erste Spalte die Positionen 0, 8, 16 und 24, also genau die Zeichen, die in der Tabelle untereinanderstehen.

Die Nebenbedingung

Eine Nebenbedingung ist dabei zu beachten: Die Textlänge muss glatt, also ohne Rest, durch den Umfang teilbar sein. Sonst wäre die letzte Zeile der Tabelle kürzer, und beim Entschlüsseln würden die Spalten nicht mehr passen. Die Prüfung ist in die Funktion ensureSideCondition() ausgelagert, die den Text bei Bedarf um Leerzeichen erweitert:

def ensureSideCondition(text, umfang):
    length      = len(text)
    remainder   = length % umfang
    while remainder != 0:
        text       += " "
        length      = len(text)
        remainder   = length % umfang

    return text

Solange die Division durch den Umfang einen Rest lässt, hängt die Schleife ein Leerzeichen an. Unser Beispieltext hat 29 Zeichen, bei acht Zeichen pro Zeile kommen also drei Leerzeichen dazu.

Entschlüsseln mit vertauschtem Schlüssel

Die Entschlüsselung muss die Umwandlung vom zeilenweisen ins spaltenweise Lesen wieder rückgängig machen. Dafür brauchst du keine neue Funktion: Die Entschlüsselung nutzt dasselbe Verfahren wie die Verschlüsselung, nur mit einem anderen Schlüssel. Die beiden Schlüssel, die sich hier gegenüberstehen, entsprechen der Breite und der Höhe der Tabelle in Zeichen. Zum Verschlüsseln verwenden wir die Anzahl der Zeichen pro Zeile als Umfang, zum Entschlüsseln die Anzahl der Zeilen. Die beiden Werte lassen sich leicht ineinander umrechnen, denn du musst nur die Gesamtzahl der Zeichen durch den jeweils anderen teilen:

def skytale_decrypt(text, umfang):
    length      = len(text)
    umfang      = length // umfang
    plaintext   = skytale_encrypt(text, umfang)

    return plaintext.lower()

Zwei Schrägstriche

Im Buch stand hier noch length / umfang. In Python 2 teilte / zwei ganze Zahlen ganzzahlig. In Python 3 liefert / immer eine Kommazahl: 32 / 8 ergibt 4.0, und range() weigert sich, mit 4.0 zu arbeiten. Die Ganzzahldivision // liefert die ganze Zahl 4.

Die Aufrufe von lower() und upper() sorgen nur für die Konvention des Kapitels: Klartext steht in Kleinbuchstaben, Geheimtext in Großbuchstaben. Mehr dazu findest du auf der Seite zur Caesar-Verschlüsselung.

Die Skytale in Aktion

Die Funktionen verwendest du wie folgt:

key         = 8
plaintext   = "heute ist sehr schönes wetter"
cipher      = skytale_encrypt(plaintext, key)

print(plaintext)
print(cipher)
print(skytale_decrypt(cipher, key))

In der Konsole erscheinen drei Zeilen:

heute ist sehr schönes wetter
HTCEE HTUSÖTTENEEHER RS I   SSW
heute ist sehr schönes wetter

Die mittlere Zeile ist die Tabelle mit vier Zeilen zu je acht Zeichen, Spalte für Spalte gelesen: »htce« aus der ersten Spalte, »e ht« aus der zweiten und so weiter. Die drei angehängten Leerzeichen stecken im Geheimtext und am Ende des entschlüsselten Textes, du siehst sie nur nicht. Im gedruckten Buch blieb das »ö« im Geheimtext übrigens klein, weil upper() in Python 2 auf Bytes arbeitete und Umlaute nicht kannte. Python 3 rechnet mit Unicode und macht daraus ein »Ö«.

Die Skytale für unterwegs

Die Skytale ist in ihrer Anwendung so einfach, dass du sie leicht auch unterwegs verwenden kannst. Statt eines Stabes mit bestimmtem Umfang brauchst du nur die Anzahl der Spalten, also der Zeichen je Zeile. Zum Verschlüsseln trägst du den Text Zeile für Zeile in eine Tabelle mit der festgelegten Anzahl an Spalten ein und liest ihn Spalte für Spalte wieder aus:

Tabelle mit vier Spalten und drei Zeilen: »gut-«, »und-«, »böse«; ein Pfeil nach rechts heißt Klartext, ein Pfeil nach unten Geheimtext
Abbildung 4.4 aus dem Buch: Skytale für unterwegs – verschlüsseln

Zum Entschlüsseln tauschst du einfach Zeilen und Spalten. Die Anzahl der Zeilen aus der ersten Tabelle ist jetzt die Anzahl der Spalten und umgekehrt:

Die gedrehte Tabelle mit drei Spalten und vier Zeilen; jetzt heißt der Pfeil nach unten Klartext und der Pfeil nach rechts Geheimtext
Abbildung 4.5 aus dem Buch: Skytale für unterwegs – entschlüsseln

Die Pfeile zeigen, in welcher Richtung der jeweilige Text zu lesen ist. Genau diese beiden Tabellen zeichnet auch die Animation oben. Unter »Probier mal« kannst du das Beispiel »gut und böse« aus den Abbildungen direkt nachspielen.

Wie sicher ist die Skytale?

Nicht sehr. Die Länge des Geheimtexts ist immer ein Vielfaches der Zeilenlänge, und damit kommen nur wenige Schlüssel in Frage. Bei 32 Zeichen sind es 2, 4, 8 und 16 – vier Versuche genügen. Hinzu kommt eine zweite Schwäche: Eine Transposition verändert keine Buchstaben. Im Geheimtext kommen deshalb genauso viele »e« und »n« vor wie im Klartext. Wer die Buchstaben zählt, erkennt sofort, dass hier ein deutscher Text nur durcheinandergewürfelt wurde.

Stärker wird es, wenn man Vertauschen und Ersetzen kombiniert. Die Caesar-Chiffre, die im Buch als Nächstes folgt, ersetzt jeden Buchstaben durch einen anderen. Im Ersten Weltkrieg setzte das deutsche Heer mit der ADFGVX-Chiffre auf genau diese Mischung aus Ersetzung und Transposition. Und moderne Blockchiffren wie AES wechseln in jeder Runde zwischen Ersetzen und Vertauschen ab.

Das Bild zum Programm

Die Animation ist neu auf dieser Website. Die Funktion wrapAndRead() schreibt den Text Zeichen für Zeichen in die Tabelle, danach liest sie ihn Spalte für Spalte wieder aus. Die Reihenfolge des Auslesens berechnet sie mit denselben beiden Schleifen wie skytale_encrypt(), hier nur als List Comprehension in einer Zeile:

order = [y for x in range(0, columns) for y in range(x, len(text), columns)]

Oben zeichnet drawRod() den Stab aus Abbildung 4.3. Jede Windung des Streifens trägt ein Zeichen der vordersten Zeile. Beim Ablesen leuchtet die Windung auf, deren Spalte gerade dran ist: Jede Spalte der Tabelle ist eine Windung des Streifens. Unten wächst mit drawStrip() der abgewickelte Streifen, so wie er verschickt wird. Für das Entschlüsseln ruft das Programm wrapAndRead() ein zweites Mal auf, nur mit vertauschter Tabelle: len(cipher) // receiverKey Spalten statt key. Das ist derselbe Trick wie in skytale_decrypt().

Probier mal

Jede Variante ändert den Code oben. Ein Klick auf »Ausprobieren« übernimmt die Änderung in den Editor und startet das Programm. »Zurücksetzen« holt das Original zurück.

  1. 01Ein dickerer Stab

    Mit key = 5 passen nur noch fünf Zeichen in eine Zeile, dafür wird die Tabelle höher: sechs Zeilen statt vier. Der Geheimtext sieht völlig anders aus, obwohl wieder nur dieselben Buchstaben vertauscht werden. Ein Leerzeichen hängt ensureSideCondition() an, damit 30 Zeichen glatt aufgehen.

    - key         = 8
    + key         = 5
  2. 02Das Beispiel aus Abbildung 4.4

    Im Buch zeigt eine kleine Tabelle, wie die Skytale auch ohne Stab funktioniert: »gut und böse« mit vier Zeichen pro Zeile. Die Animation baut genau diese Tabelle nach, beim Entschlüsseln entsteht die gedrehte Tabelle aus Abbildung 4.5.

    - key         = 8
    + key         = 4
    - plaintext   = "heute ist sehr schönes wetter"
    + plaintext   = "gut und böse"
  3. 03Der falsche Stab

    Der Empfänger braucht einen Stab mit demselben Umfang. Mit einem zu dünnen Stab – hier receiverKey = 4 statt 8 – ergeben die Zeilen keinen Sinn. Die Konsole zeigt den Zeichensalat in einer vierten Zeile, die Animation beim Entschlüsseln ebenfalls.

    - receiverKey = key  # der Empfänger hat einen Stab mit demselben Umfang
    + receiverKey = 4  # der Empfänger hat einen zu dünnen Stab
    + print(skytale_decrypt(cipher, receiverKey))
  4. 04Alle Stäbe durchprobieren

    Wie sicher ist die Skytale? Die Länge des Geheimtexts ist immer ein Vielfaches der Zeilenlänge. Bei 32 Zeichen kommen deshalb nur 2, 4, 8 und 16 als Schlüssel in Frage – vier Versuche, und eine der Zeilen ist lesbar.

    - print(skytale_decrypt(cipher, key))
    + print(skytale_decrypt(cipher, key))
    + 
    + print()
    + print("Alle möglichen Stäbe:")
    + for guess in range(2, len(cipher)):
    +     if len(cipher) % guess == 0:
    +         print(f"{guess:2}  {skytale_decrypt(cipher, guess)}")
  5. 05Deine eigene Botschaft

    Ersetze den Text in plaintext. Die Skytale verträgt Ziffern und Satzzeichen, denn sie ersetzt nichts, sie vertauscht nur. Nur Groß- und Kleinschreibung gehen verloren: Nach der Konvention des Kapitels schreibt das Programm den Geheimtext groß und den Klartext klein. Ab etwa 64 Zeichen wird es in der Tabelle eng.

    - plaintext   = "heute ist sehr schönes wetter"
    + plaintext   = "Treffpunkt um Mitternacht am alten Leuchtturm!"

Vom Buch in den Browser

Die drei Funktionen und der Aufruf stammen aus den Listings 4.3 bis 4.6 des Buchs, auf der CD als Kapitel04/skytale.py. Neu für die Website ist nur die Animation: wrapAndRead(), drawRod(), drawGrid(), drawStrip() und die Variable receiverKey, mit der die Animation entschlüsselt.

Im Buch Hier
umfang = length/umfang umfang = length // umfang
print plaintext print(plaintext)
Datei in Latin-1 (#coding: latin1) UTF-8, wie jede Python-3-Datei ohne Angabe
Ausgabe HTUSöTT… Ausgabe HTUSÖTT…

Die wichtigste Änderung: // statt /. In Python 2 teilte / zwei ganze Zahlen ganzzahlig, 32/8 ergab 4. In Python 3 ergibt 32 / 8 die Kommazahl 4.0, und range(0, 4.0) bricht mit einem TypeError ab. Deshalb steht in skytale_decrypt() die Ganzzahldivision //.

Umlaute. Im Buch war "heute ist sehr schönes wetter" eine Folge von Latin-1-Bytes. upper() kannte für diese Bytes nur die Buchstaben A bis Z, das »ö« blieb deshalb im Geheimtext klein. In Python 3 sind Strings Unicode, und "ö".upper() ergibt "Ö". Am Verfahren ändert das nichts, denn lower() macht beim Entschlüsseln wieder ein »ö« daraus.

Eine Debug-Zeile weniger. Im gedruckten Listing 4.5 steht in skytale_decrypt() noch die Zeile print umfang, length. Die Konsolenausgabe im Buch (Listing 4.7) zeigt diese Zahlen aber nicht, und in der Datei auf der CD fehlt die Zeile ebenfalls. Es handelt sich um einen Rest aus der Entwicklung, deshalb ist sie hier weggelassen.

Warten mit await. Wie alle bewegten Beispiele dieser Website gibt die Animation dem Browser nach jedem Buchstaben mit await screen.frame(lettersPerSecond) die Gelegenheit, das Bild anzuzeigen. await sleep(2.5) hält das fertige Bild der Verschlüsselung kurz fest, bevor die Entschlüsselung beginnt.

Original aus dem Buch ansehen skytale.py · Python 2
#coding: latin1

# stellt sicher, dass die Länge des Textes ohne Rest durch den Umfang teilbar ist
def ensureSideCondition(text, umfang):
    length      = len(text)
    remainder   = length % umfang
    while remainder != 0:
        text       += " "
        length      = len(text)
        remainder   = length % umfang
       
    return text
        
def skytale_encrypt(text, umfang):
    text    = ensureSideCondition(text, umfang)
    length  = len(text)
    cipher  = ""
    for x in range(0, umfang):
        for y in range(x, length, umfang):
            cipher += text[y]
            
    return cipher.upper()

def skytale_decrypt(text, umfang):
    length      = len(text)
    umfang      = length/umfang
    plaintext   = skytale_encrypt(text, umfang)

    return plaintext.lower()

key         = 8
plaintext   = "heute ist sehr schönes wetter"
cipher      = skytale_encrypt(plaintext, key)

print plaintext
print cipher
print skytale_decrypt(cipher, key)