Apps für Android programmieren leicht gemacht!
Text verschlüsseln - AES-Verschlüsselung

Text verschlüsseln – AES-Verschlüsselung

Die Verschlüsselung von Texten ist ein ganz großes Thema in der Programmierung, vor allem, wenn man sensible Daten speichern möchte. In diesem Artikel wollen wir uns mit der Verschlüsselung von Texten unter Androids Java beschäftigen.

Nebst sehr vielen verschiedenen Verschlüsselungsalgorithmen werden wir unseren Text mit einer AES-Verschlüsselung versehen.
Durch dieses Verfahren ist uns beispielsweise möglich sensible Daten, wie Passwörter, Zahlungsinformationen oder Nutzer-ID’s zu verschlüsseln und sicherer zu speichern.

Das schöne an diesem AES-Algorithmus ist, dass es sich hierbei um ein symmetrisches Verschlüsselungsverfahren handelt.
Das heißt, dass sowohl der Schlüssel/das Passwort zum Ver-, als auch zum Entschlüsseln gleich ist.
Und obwohl es sich um symmetrisches Verschlüsselungsverfahren handelt, bietet es jedoch ein sehr hohes Maß an Sicherheit.

Mehr zu diesem Thema gibt es wie immer auch bei Wikipedia, wir werden uns jetzt mit der Programmierung und weniger mit der Theorie beschäftigen.

 

AES.class:

Wir werden versuchen den größten Teil des Algorithmus in eine externe Klasse auszulagern.
Diese Vorgehensweise hat den Vorteil, dass wir unseren eigentlichen Code sauber und übersichtlich halten können. Euch steht selbstverständlich frei die Funktionen direkt in eine bestehende Klasse zu integrieren.

Wir müssen in dieser Klasse ein paar wenige Dinge importieren, damit unsere Verschlüsselung/Entschlüsselung arbeiten kann.

import android.util.Base64;

import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

 

Nachdem wir nun die nötigen Abhängigkeiten importiert haben, können wir beginnen die Ver-/Entschlüsselung von Texten zu programmieren.
Der Einfachheit halber sollten wir vielleicht mit der Verschlüsselung beginnen.

Ablauf:

Der Ablauf unserer Verschlüsselung ist recht einfach zu erklären und in wenige Teilschritte zu verpacken.
Wir werden nun versuchen unseren bereits angesprochenen synchronen Schlüssel (unser Passwort) so umzuwandeln, dass wir einen Seed daraus bekommen.

Dieser Seed ist eigentlich nichts anderes als unser Passwort in Byte Form so umgeformt, dass unsere genutzte Kryptographie Engine diesen nutzen kann, um aus unserem Klartext einen verschlüsselten Text zu generieren. Wer sich den Wikipedia Eintrag durchgelesen hat, wird feststellen, dass die AES-Verschlüsselung unter anderem auf der Verschiebung unserer Klartextbuchstaben in mehreren Durchläufen basiert. Dieser Seed dient ergo dazu da, um die Verschiebung zu beschreiben. Das ist ganz grob erzählt, aber ich hoffe verständlich genug, für einen ersten Eindruck.

Anschließend laden wir die Kryptograhie Engine, sagen ihr sie solle Verschlüsseln und übergeben den Seed.
Nun können wir den Klartext, ebenfalls in Byte Form umgewandelt, an die Engine übergeben und diese tut ihr übriges.
Zum Schluss erstellen wir manuell aus dem verschlüsselten Text einen HEX-Code und können diesen ohne Informationsverlust speichern.

Der Code:

// Verschlüsselung (Der Seed ist der gewählte Schlüssel/unser gewähltes Passwort.)
public static String encrypt(String passwort, String klartext) throws Exception {

    // Erstelle einen verwendbaren Byte Schlüssel aus unserem Klartextschlüssel (seed).
    byte[] seed = getSchluessel(passwort.getBytes());

    // Übergebe den Byte Schlüssel an das Objekt SecretKeySpec, um ihn gleich an die Kryptograthie Engine zu übergeben.
    SecretKeySpec skeySpec = new SecretKeySpec(seed, "AES");

    // Erstelle das Objekt cipher, um die Kryptograthie Engine zu laden.
    Cipher cipher = Cipher.getInstance("AES");

    // Übergebe den Byte Schlüssel an die Kryptograthie Engine.
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);

    // Übergebe den zu verschlüsselnden Klartext an die Kryptograthie Engine und lasse die Magie beginnen.
    byte[] encryptedText = cipher.doFinal(klartext.getBytes("UTF-8"));

    // Erstelle aus dem nun verschlüsselten Text in Byte Form ein String und erstelle daraus gleich einen HEX-Code.
    // Wir benötigen diesen HEX-Code, damit keine Daten verloren gehen und im späteren Verlauf wieder einen entschlüsselten Klartext daraus machen können.
    return toHex(Base64.encodeToString(encryptedText, Base64.DEFAULT));
}

// Erstelle aus einem String einen zugehörigen HEX-Code.
public static String toHex(String text) {

    byte[] buf = text.getBytes();
    String HEX = "0123456789ABCDEF";

    if (buf == null)
        return "";
    StringBuffer result = new StringBuffer(2*buf.length);
    for (int i = 0; i < buf.length; i++) {
        result.append(HEX.charAt((buf[i]>>4)&0x0f)).append(HEX.charAt(buf[i]&0x0f));
    }
    return result.toString();
}

 

Entschlüsselung:

Was nützt uns ein verschlüsselter Text, wenn wir ihn nicht wieder zu einem Klartext umwandeln können?

In der zweiten Instanz müssen wir versuchen den verschlüsselten Text wieder in einen Klartext umzuwandeln.
Dies erreichen wir, indem wir den HEX-Code wieder in Bytes umwandeln, an die Funktion übergeben und vom Prinzip her das selbe tun, wie auch bei der Verschlüsselung schon. Wir sagen der Kryptograhpie Engine nun, dass sie entschlüsseln soll, und sparen uns den Schritt am Ende einen HEX-Code zu generieren.

//Entschlüsselung
public static String decrypt(String passwort, String verschluesselt) throws Exception {

    // Erstelle einen verwendbaren Byte Schlüssel aus unserem Klartextschlüssel (seed).
    byte[] seed = getSchluessel(passwort.getBytes());

    // Übergebe den Byte Schlüssel an das Objekt SecretKeySpec, um ihn gleich an die Kryptograthie Engine zu übergeben.
    SecretKeySpec skeySpec = new SecretKeySpec(seed, "AES");

    // Erstelle das Objekt cipher, um die Kryptograthie Engine zu laden.
    Cipher cipher = Cipher.getInstance("AES");

    // Übergebe den Byte Schlüssel an die Kryptograthie Engine.
    cipher.init(Cipher.DECRYPT_MODE, skeySpec);

    // Übergebe den zu entschlüsselnden Text an die Kryptograthie Engine und lasse die Magie beginnen.
    byte[] klartext = cipher.doFinal(Base64.decode(toByte(verschluesselt), Base64.DEFAULT));

    // Nun können wir aus dem zurück gegebenen Klartext in Byte Form einen String erstellen.
    return new String(klartext, "UTF-8");
}

// In dieser Funktion machen wir eigentlich nichts anderes, als den HEX-Code wieder in Bytes eines Strings zurück zu wandeln.
public static byte[] toByte(String hexString) {
    int len = hexString.length()/2;
    byte[] result = new byte[len];
    for (int i = 0; i < len; i++)
        result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();
    return result;
}

 

Seed:

Als Kleinigkeit fehlt nun noch die Funktion, die uns einen Seed, aus einem Klartextpasswort erstellt.

// Diese Funktion dient dazu einen bereits in Bytes umgewandelten Seed (unser Schlüssel/Passwort) in einen von der Kryptograthie Engine verwendbaren Schlüssel umzuwandeln.
private static byte[] getSchluessel(byte[] seed) throws Exception {
    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    SecureRandom sr = SecureRandom.getInstance("SHA1PRNG","Crypto");
    sr.setSeed(seed);
    kgen.init(128, sr); // 192 and 256 bits sind möglicherweise nicht verfügbar. Probiert es aus.
    SecretKey skey = kgen.generateKey();
    byte[] raw = skey.getEncoded();
    return raw;
}

Zur Generierung des Seeds wird ein 128 Bit langer Seed benutzt.
Es handelt sich also um eine 128 Bit Verschlüsselung.
Natürlich würden 192, 256, 512, … Bit Verschlüsselungen mehr an Sicherheit bieten, aber aufgrund der begrenzten Ressourcen eines Smartphones sind diese vielleicht nicht verfügbar. Vielleicht solltet ihr euren späteren Nutzern die Möglichkeit bieten die Bit Länge selber einzustellen und selber zu testen, ob ihr Smartphone diese unterstützt.

 

Verwendung:

Um die neu erstellte Klasse nutzen zu können, habe ich mich für dieses Beispiel entschieden:

/*
 * Copyright 2016 www.droid-lernen.de
 *
 * Licensed under the Apache License, Version 2.0 (the „License“);
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an „AS IS“ BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package de.droid_lernen.aesverschlsselung;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        String klarText = "www.droid-lernen.de";
        String passwort = "Unser gewähltes Passwort";
        
        // Der Vorgang muss in einem try-catch stehen, da Fehler auftreten können, die die App nicht abstürzen lassen sollen. 
        try {
            // Verschlüssele den Klartext.
            String verschluesselt = AES.encrypt(passwort, klarText);
            
            // Entschlüssele den Text wieder.
            String entschluesselt = AES.decrypt(passwort, verschluesselt);
            
            // Erstelle ein neues TextView, indem die Texte (Klartext, Verschlüsselt, Entschlüsselt) nachvollziehbar angezeigt werden können.
            TextView text = new TextView(this);

            text.setText("Klartext: " + klarText + 
                         " \n Verschlüsselt: " + verschluesselt +
                         " \n Entschlüsselt: " + entschluesselt);
            setContentView(text);
            
        } catch (Exception e) {
            
            // Fehlerausgabe auf der Konsole.
            e.printStackTrace();
        }
    }
}

AES Verschlüsselung - Source Code


Der komplette Source Code zu diesem Artikel im Download.

DownloadLizenzbedingungen

Marvin

Ich bin 23 Jahre jung und studiere zurzeit Wirtschaftsinformatik an der Georg-August-Universität in Göttingen. Ich bin ein Mensch, der sich neben der Programmierung noch für tausend andere Dinge interessiert, die mal mehr und mal weniger verrückt sind. Vor allem aber bin ich Feuer und Flamme mit der Programmierung von eigenen kleinen Apps und Programmen, die mein Leben bereichern.

Kommentar hinzufügen

*Pflichtfeld