Selbst ist der Datenschützer Teil 2

Google-Drive-API – Kryptofunktionalitäten fürs Ver- und Entschlüsseln
Kommentare

Für den programmgestützten Datentransfer zwischen globalen Cloud-Speichern und lokalen Computern stellen die Anbieter solcher Onlinespeichersysteme Bibliotheken für das Einbinden in eigene Clientapplikationen bereit und ermöglichen damit den automatisierten bidirektionalen Datentransfer. Es ist somit möglich, das Verschlüsseln und das Hochladen einer Datei in einen einzigen Prozessschritt zu integrieren, sodass die Akzeptanz der Anwender merklich steigen dürfte. Genauer betrachtet muss eine Datei nicht mehr zuerst mit einer separaten Applikation verschlüsselt und danach via Browserinterface in den Cloud-Speicher transferiert werden. Vielmehr kann beides in einem Arbeitsgang ohne tiefgreifendes Know-how bezüglich Verschlüsselungstechniken erledigt werden.

Im zweiten Teil dieser Artikelserie (Teil 1: Cloud Computing – digitale Schlüssel und Zertifikate) werden zunächst die grundlegenden Möglichkeiten der SkyDrive- und GDrive-APIs bezüglich des Hochladens und Herunterladens von Dateien aufgezeigt. Daran anschließend wird das Einrichten einer Entwicklungsumgebung gezeigt und der Einsatz des GDrive-APIs anhand eines kompletten Beispiels erläutert. Hierbei handelt es sich um die Realisierung einer Applikation für den Transfer zuvor lokal verschlüsselter und signierter Dateien. Außerdem wird gezeigt, wie diese Applikation so registriert werden kann, dass sie komfortabel mit einem Rechtsklick auf eine zu verschlüsselnde Datei im Dateiexplorer gestartet werden kann.

SkyDrive-API

Microsoft stellt für die Onlineauthentifizierung und den Zugriff auf SkyDrive eine adäquate Applikationsschnittstelle (API) zur Verfügung, die sich für die Integration in eigene Programme eignet. Die notwendigen Komponenten sind im Microsoft-Installer LiveSDK.msi enthalten, der als Download frei verfügbar ist. Ein Doppelklick auf LiveSDK.msi öffnet einen einfachen Set-up-Dialog, der zum Akzeptieren der Lizenzbedingungen auffordert. Nachdem das entsprechende Kontrollkästchen selektiert wurde, kann die unspektakuläre Installation mit der gleichnamigen Schaltfläche gestartet werden. Nach erfolgreicher Installation ist der Ordner C:Program Files (x86)Microsoft SDKsLivev5.5 vorhanden, wobei „v.5.5“ die derzeit aktuelle Version darstellt. Der Unterordner „Documentation“ enthält den Onlinelink „Live Connect Documentation“, der auf die Live-Connect-Dokumentation zeigt. In dieser Onlinedoku sind erste Schritte, das Live-SDK-Entwicklerhandbuch, SkyDrive-, Identitäts- und Outlook.com-APIs sowie weitere nützliche Informationen zu finden. Weiterhin ist im Unterordner „Samples“ ein Onlinelink verfügbar, der auf ein englischsprachiges Portal mit Samples für verschiedene Plattformen (Windows, PHP, ASP.NET etc.) verweist. Die DLLs Microsoft.Live.dll und Microsoft.Live.Web.dll sind im Unterordner „NetBin“ gespeichert und müssen als Verweise in ein Visual-Studio-Projekt eingebunden werden, um im Code auf ein entsprechendes Using zugreifen zu können. Grundsätzlich ist auch für die Nutzung des SkyDrive-API ein Microsoft-Konto erforderlich, das durch eine kostenlose Registrierung zu bekommen ist. Wie eine derartige Registrierung vonstatten geht, ist im ersten Teil dieses Artikels ausführlich beschrieben. Bevor mit der Entwicklung einer SkyDrive-Applikation begonnen werden kann, wird eine Client-ID benötigt, die auf dem Live Connect Developer Center generiert werden kann. Dieses Portal ermöglicht nach erfolgreicher Anmeldung mit einem Microsoft-Konto die Vergabe eines Applikationsnamens und der Angabe, ob es sich um eine mobile App handelt. Mit der Schaltfläche „Speichern“ werden die Applikationsdaten gespeichert und eine Client-ID sowie ein geheimer Clientschlüssel stehen zur Verfügung.

public async Task Authenticate()
{
  LiveConnectSession liveConnectSession;
  try
  {
    LiveAuthClient authClient = new LiveAuthClient("Client ID");
    var Result = await authClient.IntializeAsync(new String[] {"wl.skydrive", "wl.skydrive_update"});
    if (Result.Status == LiveConnectSessionStatus.Connected)
    liveConnectSession = Result.Session;
  }
  catch (Exception ex)
  {
    MessageBox.Show(ex.Message);
  }
}

Diese Client-ID wird gemäß Listing 1 für den Authentifizierungsprozess benötigt und ist für jede einzelne Applikation neu zu generieren. Falls die Authentifizierung erfolgreich verlaufen ist und eine gültige Session vorliegt, kann mit dem SkyDrive-API sowohl auf die dort gespeicherten Dateien zugegriffen, als auch Dateitransfers vorgenommen werden.

GDrive-API

Ebenso wie Microsoft stellt auch Google ein API mit Bibliotheksfunktionen zur Integration in ein .NET-Projekt bereit. Die Verwendung dieses GDrive-API setzt ein Google-Konto voraus, das für GDrive freigeschaltet ist. Weitere Einzelheiten und eine Erste-Schritte-Anleitung können hier entnommen werden.
Zur Veranschaulichung eines gesamten Entwicklungszyklus sind nachfolgend sämtliche Schritte, die zur Implementierung einer Applikation mit Google Drive erforderlich sind, an einem vollständigen Beispiel beschrieben: 1. Schritt: Freischaltung des GDrive-API:

Anmeldung auf dem Internetportal mit einem geeigneten Google-Account.
• Registration einer Applikation durch Anklicken des Links „set up a project and application in the Developers Console“ (Fortsetzung erfolgt auf einer weiteren Webseite).
• Belassen der Vorauswahl „Create a new project“ und Anklicken der Schaltfläche „Continue“.
• Eingabe eines freiwählbaren Projektnamens und Anklicken der Schaltfläche „Create“ gemäß Abbildung 1.
• Nach erfolgreichem Anlegen eines neuen Projekts werden eine Project-ID und eine Project-Number generiert und angezeigt.

Abb. 1: Google Drive – New Project

• Ein weiterer Link auf der Webseite mit der Bezeichnung „Google Developer Console“ führt zu einer Webseite, auf der alle bisher angelegten Projekte aufgelistet sind. Natürlich sollte hier auch das zuvor neu angelegte Projekt aufgeführt und auswählbar sein. Ein Klick auf den Projektnahmen bewirkt das Laden einer neuen Webseite, auf der die Optionen für das angeklickte Projekt eingestellt werden können.
• Ein Klick auf die Option „APIs & auth“ in der linken Menüleiste öffnet das Untermenü „APIs“. Hier sind die Status der einzelnen Optionen ausgewiesen, wobei darauf zu achten ist, dass die Option „Drive API“ den Status ON aufweist.
• Ein Klick auf die Option „Credentials“ bewirkt das Anzeigen der Client-ID.
• Für eine Applikation wird neben einer Client-ID auch ein Client-Secret benötigt. Dieser kann durch Anklicken der roten Schaltfläche generiert werden (Abb. 2).

Abb. 2: Generieren von Client-ID und Client-Secret

2. Schritt: Installation der Google-Clientbibliothek:

• Der zweite Schritt kann durch Anklicken des Links auf „Drive API NuGet package“ gestartet werden. Dieser Link ruft eine Webseite auf dem Portal „nuget.org“ auf. Dieser Seite kann die Anweisung für Paketmanager entnommen werden: „PM> Install-Package Google.Apis.Drive.v2 –Pre“.
• Das benötigte Paket kann entweder via Powershell-Konsole oder direkt innerhalb von Visual Studio installiert werden. Nachfolgend ist die zweitgenannte Option beschrieben, demzufolge muss zunächst ein neues Projekt in Visual Studio angelegt werden.
• Für das nachstehend beschriebene Sample ist ein Projekt vom Typ „Windows Konsolen-Anwendung“ geeignet (Demo01Client.sln).
• Der Paketmanager kann über das Menü TOOLS | BIBLIOTHEKS-PAKET-MANAGER | PAKET-MANAGER-KONSOLE aktiviert werden, wobei im unteren Teil von Visual Studio ein Fenster geöffnet wird, in dem der Prompt „PM>“ zur Eingabe auffordert.
• Für die Google-Clientbibliothek lautet die einzugebende Sequenz: „Install-Package Google.Apis.Drive.v2 –Pre“.
• Als Reaktion auf das Abschicken dieser Sequenz werden alle Bestandteile dieses Pakets installiert und gleichzeitig automatisch zu den Verweisen des geöffneten Projekts hinzugefügt.

3. Schritt: Implementierung eines Samples:

• Der Quellcode für eine komplette Beispielanwendung ist in einzelne Listings aufgeteilt, wobei aus Gründen der Übersichtlichkeit auf Fehlerbehandlung etc. verzichtet wurde.
• Bevor auf Dateien und Informationen, die auf GDrive gespeichert sind, zugegriffen werden kann, muss die in Listing 2 gezeigte Autorisierung durchgeführt werden. Hierfür werden die im ersten Schritt generierten Parameter ClientID und ClientSecret benötigt, um die Klasse UserCredential mit gültigen Werten zu versorgen. Weiterhin ist eine Klasse DriveService zu instanziieren, die UserCredential und der Projektname übergeben werden. Dieser DriveService wird für alle via GDrive-API durchgeführten Onlinetransaktionen benötigt.
• Der erstmalige Aufruf der in Listing 2 gezeigten Autorisierungssequenz startet automatisch den Standardbrowser, und es erfolgt die Aufforderung zur Anmeldung mit einem gültigen Google-Konto entsprechend Abbildung 3. Nach erfolgreicher Anmeldung muss die Applikation autorisiert werden, indem die in Abbildung 4 dargestellte blaue Schaltfläche „Akzeptieren“ angeklickt wird. Anschließend wird die Autorisierungssequenz durchlaufen, und es steht ein gültiger DriveService zur Verfügung.

Abb. 3: Anmeldung bei GDrive

Abb. 4: Applikation autorisieren

using System;
using System.Threading;
using System.Collections.Generic;
using Google;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Drive.v2;
using Google.Apis.Drive.v2.Data;
using Google.Apis.Services;
static void Main(string[] args)
{
  UserCredential credential = 
  GoogleWebAuthorizationBroker.AuthorizeAsync(new ClientSecrets
    {
      ClientId = "Client ID",  
      ClientSecret = "Client Secrect",
    },
    new[] { DriveService.Scope.Drive}, "user", CancellationToken.None).Result;
    var service = new DriveService(new BaseClientService.Initializer()
    {
      HttpClientInitializer = credential,
      ApplicationName = "Demo01", // Project Name 
  });
}

• Um auf GDrive-Dateien zugreifen zu können, wird ein gültiger DriveService benötigt (vgl. Listing 2). Wie in Listing 3 gezeigt, kann ein auf diesem DriveService basierender Request für das Abrufen einer Liste mit Metadaten herangezogen werden.
• Die Metadaten enthalten unter anderem eine File-ID in Form einer Zeichenkette (String). Diese File-ID wird benötigt, um direkt auf eine ausgewählte GDrive-Datei zuzugreifen und diese herunterzuladen, wie in Listing 4 gezeigt. Der Download wird mit der Klasse MediaDownloader aus dem GDrive-API bewerkstelligt, wobei als Puffer ein Byte-Array Verwendung findet. Damit kann sichergestellt werden, dass auch Dateien mit binärkodiertem Inhalt verarbeitet werden können.

private static List<File> GDriveGetMetaData(DriveService service)
{
  List<File> result = new List<File>();
  FilesResource.ListRequest request = service.Files.List();
  do
  {
    FileList files = request.Execute();
    result.AddRange(files.Items);
    request.PageToken = files.NextPageToken;
  }
  while (!String.IsNullOrEmpty(request.PageToken));
  return result;
}
private static byte[] GDriveDownloadBytes(DriveService service, string sFileID)
{
  File fDownload = service.Files.Get(sFileID).Execute();
  byte[] bArray = new byte[(int)file.FileSize];
  System.IO.Stream ios = new System.IO.MemoryStream(bArray);
  Google.Apis.Download.MediaDownloader mdl = new Google.Apis.Download.MediaDownloader(service);
  mdl.Download(file.DownloadUrl, ios);
  using (System.IO.BinaryReader br = new System.IO.BinaryReader(ios))
  {
    br.BaseStream.Position = 0;
    bArray = br.ReadBytes((int)file.FileSize);
    return bArray;
  }
}

• Gemäß Listing 5 kann das Hochladen einer Datei ebenso wie der Download auf einem Byte-Array basierend durchgeführt werden. Ist der Upload erfolgreich verlaufen, kann aus dem GDrive-Objekt File unter anderem die zugehörige File-ID extrahiert werden und zur weiteren Verarbeitung (Archivierung etc.) verwendet werden.

private static File GDriveUpload(DriveService service, string sFileName)
{
  File body = new File();
  body.Title = "GDriveUpload";
  body.Description = "A test document";
  body.MimeType = "text/plain";
  byte[] byteArray = System.IO.File.ReadAllBytes(sFileName);
  System.IO.MemoryStream stream = new System.IO.MemoryStream(byteArray);
  FilesResource.InsertMediaUpload request = service.Files.Insert(body, stream, 
                                           "text/plain");
  request.Upload();
  return request.ResponseBody;
}

Mit den in den Listings 2 bis 5 gezeigten Codesequenzen lassen sich komplette Dateitransfers, also Uploads und Downloads, innerhalb beliebiger eigener Applikationen realisieren, sodass weder ein Browserinterface, noch ein lokales Clientprogramm von Google erforderlich ist. Somit bleibt die Ausgestaltung eines übersichtlichen GUI und eines akzeptablen Look and Feel dem Applikationsentwickler überlassen.

Aufmacherbild: Secure Online Cloud Computing Concept with business man von Shutterstock / Urheberrecht: Melpomene

[ header = Seite 2: PKCS#12Cryptor ]

PKCS#12Cryptor

Das .NET-Projekt PKCS12Cryptor.sln veranschaulicht das Ver- und Entschlüsseln von Dateien beliebigen Formats. Die für die kryptografischen Operationen erforderlichen Schlüssel und Zertifikate entstammen der im ersten Teil dieses Artikels realisierten Anwendung PKCS#12Creator. Natürlich können auch zum Standard PKCS#12 kompatible PFX-Dateien aus anderen Quellen Verwendung finden.
Gemäß Abbildung 5 ist der Dateiname der Quelldatei entweder über einen Standarddialog, der mit der gleichnamigen Schaltfläche geöffnet werden kann, oder durch einen Rechtsklick im Dateiexplorer (siehe unten) vorzugegeben. PKCS12Cryptor erkennt automatisch, ob es sich um eine bereits verschlüsselte oder eine unverschlüsselte Datei handelt. Dem entsprechend lautet die Beschriftung der Schaltfläche entweder Verschlüsseln oder Entschlüsseln und die interne Programmlogik (Mode) wird darauf ausgerichtet. Der für die Speicherung der Zieldatei gewünschte Dateiname kann ebenfalls mit einem Standarddialog vorgegeben werden. Weiterhin lässt sich der Dateiname für die PFX-Datei mit einem Standarddialog auswählen, der mit der Schaltfläche „PFX Datei“ aktiviert werden kann.
Das Passwort wird für den Zugriff auf die PFX-Datei benötigt und ist sowohl für das Verschlüsseln als auch für das Entschlüsseln erforderlich.

Abb. 5: PKCS12Cryptor in Aktion

Eine verschlüsselte Datei enthält neben den verschlüsselten Nutzdaten so genannte Metadaten, nämlich Header- und Schlüsseldaten. Die der hier vorliegenden Lösung zugrunde liegende Dateistruktur umfasst genau vier binäre Sequenzen, die wie folgt definiert sind:

• 1. Sequenz: 34 Bytes, die als proprietäre Kennung dienen.
• 2. Sequenz: Verschlüsselter Sitzungsschlüssel (Session Key), dessen Länge von der bei der Erstellung der PFX-Datei verwendeten RSA-Schlüssellänge abhängt. Die Länge dieser Sequenz beträgt für RSA1024 genau 128 Bytes, für RSA2048 genau 256 Bytes und für RSA4096 genau 512 Bytes.
• 3. Sequenz: Initialisierungsvektor für die symmetrische Verschlüsselung
• 4. Sequenz: Verschlüsselte Nutzdaten, deren Länge sich von der Quelldatei ableitet.

Diese vier Sequenzen werden als Binärdaten ohne weitere Kennungen direkt nacheinander als zusammenhängender Bytestream in der Zieldatei gespeichert. Optional können die Daten signiert werden, sodass eine weitere Sequenz in Form einer digitalen Signatur generiert und gespeichert werden kann. In diesem Fall muss die digitale Signatur während des Entschlüsselns verifiziert werden.
Sämtliche in den folgenden Listings verwendeten kryptografischen Algorithmen werden von den .NET-Systembibliotheken System.Security.Cryptography und System.Security.Cryptography.X509Certificates bereitgestellt, d. h. es sind keine zusätzlichen Bibliotheken erforderlich. Anmerkung: In den nachstehenden Listings wird aus Gründen der Übersichtlichkeit sowohl auf die „Try/Catch“-Zweige als auch auf die einzubindenden Bibliotheken verzichtet.
Nachfolgend sind die wichtigsten kryptografischen Funktionen des Projekts PKCS12Cryptor.sln auszugsweise beschrieben. Die in Listing 6 gezeigte Funktion CreateAESKey generiert einen symmetrischen AES-Schlüssel, der im Kontext des PKCS12Cryptor als so genannter Sitzungsschlüssel fungiert. Falls die als „Managed Code“ ausgeführten Operationen erfolgreich verlaufen sind, wird der AES-Schlüssel als Bytesequenz zurückgeliefert. Mit diesem symmetrischen Schlüssel werden später die Nutzdaten verschlüsselt, da sich asymmetrische Algorithmen nur zur Verschlüsselung sehr kleiner Datenmengen eignen.

public static byte[] CreateAESKey(int nKeySize)
{
  // Managed AES Objekt
  AesManaged aes = new AesManaged();
  // Schlüssellänge per default = 256 bit, außerdem möglich: 128 or 192 bit
  // IV (Initialization Vector): 16 Byte
  if (nKeySize == 128 || nKeySize == 192 || nKeySize == 256)
  {
    aes.KeySize = nKeySize;
    aes.GenerateKey();
    return aes.Key;
  }
  return null;
}

Nachdem ein geeigneter symmetrischer Schlüssel zur Verfügung steht, kann mit der in Listing 7 dargestellten Funktion EncryptAES ein zu übergebendes Byte-Array mit diesem Schlüssel verschlüsselt werden. Zunächst sind jedoch der Ciphermode und der Initialisierungsvektor vorzugeben. Im so genannten CBC-Mode (Cypher Block Chaining) wird die gesamte zu verschlüsselnde Sequenz in einzelne Blöcke zerlegt und blockweise verschlüsselt. Der verschlüsselte erste Block wird mit dem Klartext des zweiten Blocks mit einer XOR-Operation verknüpft und erst danach verschlüsselt. Dieses Verfahren findet solange Anwendung, bis der letzte Block mit dem vorletzten Block verknüpft und anschließend verschlüsselt wurde. Da der erste Block keinen Vorgänger hat, wird hier der Initialisierungsvektor (IV) verwendet. IV ist eine Zufallsgröße mit definierter Länge, der nicht nur bei der Verschlüsselung, sondern auch bei der Entschlüsselung bekannt sein muss. Aus diesem Grund wird der innerhalb der Funktion EncryptAES generierte IV-Wert als Referenz zurückgegeben.

public static byte[] EncryptAES(byte[] bytePlain, byte[] byteKey, ref byte[] 
byteIV)
{
  AesManaged aes = new AesManaged();
  aes.Key = byteKey;
  aes.Mode = CipherMode.CBC;
  aes.GenerateIV();
  byteIV = aesManaged.IV;
  MemoryStream ms = new MemoryStream();
  CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), 
                    CryptoStreamMode.Write);
  cs.Write(bytePlain, 0, bytePlain.Length);
  cs.Close();
  return ms.ToArray();
}

Die verschlüsselten Blöcke werden sequenziell zum Chiffrat (Geheimtext) konkateniert. Auf diese Weise wird verhindert, dass das Entschlüsseln eines Geheimtexts parallel vorgenommen werden kann, da auch hier in ähnlicher Weise wie beim Verschlüsseln immer das Chiffrat des Vorgängerblockes bekannt sein muss.
DecryptAES ist das Pendant zu der zuletzt vorgestellten Funktion EncryptAES. Auch hier sind gemäß Listing 8 zunächst der Ciphermode und der Initialisierungsvektor zu setzen, bevor mit der Klasse CryptoStream die Entschlüsselung des übergebenen Geheimtexts gestartet werden kann. Falls der richtige Schlüssel, sowie der korrekte Initialisierungsvektor übergeben wurden und kein Fehler auftritt, liefert DecryptAES den Klartext als Bytesequenz zurück.

public static byte[] DecryptAES(byte[] byteCipher, byte[] byteKey, byte[] 
byteIV)
{
  AesManaged aes = new AesManaged();
  aes.Key = byteKey;
  aes.Mode = CipherMode.CBC;
  aes.IV = byteIV;
  MemoryStream ms = new MemoryStream();
  CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), 
                    CryptoStreamMode.Write);
  cs.Write(byteCipher, 0, byteCipher.Length);
  cs.Close();
  return ms.ToArray();
}

Bei dem hier vorgestellten Verschlüsselungsverfahren handelt es sich um ein so genanntes Hybridverfahren. Das bedeutet, es kommt sowohl symmetrische, als auch asymmetrische Kryptografie zum Einsatz. Wie bereits kurz erwähnt, sind asymmetrische Verfahren bestens innerhalb von PKI-Systemen für das Generieren und Verifizieren von digitalen Signaturen geeignet, jedoch nicht für das Verschlüsseln größerer Datenmengen. Deshalb greift man zusätzlich auf symmetrische Verfahren zurück, um das eigentliche Verschlüsseln der Nutzdaten vorzunehmen.
Demzufolge wird gemäß Listing 9 zunächst ein symmetrischer Sitzungsschlüssel (Ephemeral Key) auf der Basis von AES-256 generiert. Daran anschließend werden die einzelnen Datensequenzen kreiert, wobei mit einer Headersequenz begonnen wird. Bei dieser ersten Sequenz handelt es sich um einen Klartext, anhand dessen beim Einlesen der Datei erkannt werden kann, ob es sich um eine mit PKCS12Cryptor verschlüsselte Datei handelt. Falls diese vorgegebene Sequenz erkannt wird, wird die interne Programmlogik automatisch auf „Entschlüsseln“ ausgerichtet. Als zweite Sequenz wird der Sitzungsschlüssel asymmetrisch verschlüsselt, indem aus einer PFX-Datei das X.509-Zertifikat und der private Schlüssel geladen werden. Zu beachten ist jedoch, dass immer mit dem öffentlichen Schlüssel verschlüsselt wird, der aus dem X.509-Zertifikat entnommen wird. Neben dem Namen der PFX-Datei ist das bei der Generierung dieser Datei vergebene Passwort erforderlich. Die dritte Sequenz, der Initialisierungsvektor, wird von der Funktion EncryptAES als Referenz zurückgeliefert und muss ebenfalls gespeichert werden, da er für den Entschlüsselungsvorgang bekannt sein muss. Letztendlich werden die zuvor als Klartext eingelesenen Daten symmetrisch verschlüsselt und bilden die vierte Sequenz. Falls optional eine Signatur generiert werden soll, kann diese ebenfalls als Bytesequenz am Ende der Zieldatei gespeichert werden.

public static void DoEncryption()
{
  byte[] byteSessionKey = CreateAESKey(256);
  // 1. Header: Klartext 34 Bytes
  byte[] byteHeader = System.Text.Encoding.UTF8.GetBytes(StartForm.sHeader);

  // 2. Verschlüsselter Sitzungsschlüssel:  1024->128, 2048->256 ...
  X509Certificate2 cert = new X509Certificate2("P12File", "Password");
  // Extraction of the private key from P12 file
  RSACryptoServiceProvider rSACSP = (RSACryptoServiceProvider)cert.PrivateKey;
  // Asymmetrische RSA-Verschlüsselung des Sitzungsschlüssels
  byte[] byteEncryptedSessionKey = rSACSP.Encrypt(byteSessionKey, false);
  // Einlesen der Klartextdaten
  byte[] bytePlain = null;
  using (BinaryReader br = new BinaryReader(File.Open("SourceFile, 
                           FileMode.Open)))
  {
    bytePlain = br.ReadBytes((int)br.BaseStream.Length);
                br.Close();
  }
  // 3. IV (Initialization Vector)
  // 4. Symmetrisch verschlüsselte Daten
  byte[] byteIV = null;
  byte[] byteEncData = EncryptAES(bytePlain, byteSessionKey, ref byteIV);
  // Speicherung der vier Sequenzen in eine binäre Datei
  using (BinaryWriter bw = new BinaryWriter(File.Create("TargetFile")))
  {
    bw.Write(byteHeader);
    bw.Write(byteIV);
    bw.Write(byteEncryptedSessionKey);
    bw.Write(byteEncData);
    bw.Flush();
  }
}

Das Speichern der vier Sequenzen wird standardmäßig mit einem BinaryWriter vorgenommen, wobei die Reihenfolge genau eingehalten werden muss, da beim Entschlüsseln die einzelnen Bytesequenzen entsprechend gelesen werden. Das Entschlüsseln einer Datei, die nach dem oben beschriebenen Schema verschlüsselt wurde, besteht zunächst darin, das Zertifikat und den privaten Schlüssel aus der PFX-Datei zu laden und anschließend die einzelnen vier Bytesequenzen in der korrekten Reihenfolge einzulesen. Gemäß Listing 10 muss zunächst die Länge des öffentlichen Schlüssels ermittelt werden, da diese mit der Länge der Bytesequenz des verschlüsselten Sitzungsschlüssels korreliert ist und beim Lesen mit einem BinaryReader bekannt sein muss. Da der Initialisierungsvektor die feste Länge von 16 Bytes hat, kann direkt auf diesen zugegriffen werden. Die Länge der verschlüsselten Nutzdaten ergibt sich, indem die einzelnen Längen der drei ersten Sequenzen aufsummiert werden und von der gesamten Dateilänge subtrahiert werden. Nach dem Einlesen der einzelnen Sequenzen ist zunächst der Sitzungsschlüssel mit dem privaten Schlüssel zu entschlüsseln, damit anschließend die Nutzdaten mit diesem Schlüssel entschlüsselt werden können. Das Speichern der entschlüsselten Daten ist reine Formsache und wird mit einem BinaryWriter als letzter Schritt vorgenommen.

public static void DoDecryption()
{
  // PFX-Datei einlesen
  X509Certificate2 cert = new X509Certificate2("P12File", "Password");
  // Extraction des öffentlichen Schlüssels
  int nKeySize = cert.PublicKey.Key.KeySize / 8;
  // Einlesen der vier Sequenzen
  byte[] byteHeader = null;
  byte[] byteEncryptedSessionKey = null;
  byte[] byteIV = null;
  byte[] byteEncData = null;
  using (BinaryReader br = new BinaryReader(File.OpenRead("SourceFile")))
  {
    byteHeader = br.ReadBytes(34);
    byteIV = br.ReadBytes(16);
    byteEncryptedSessionKey = br.ReadBytes(nKeySize);
    byteEncData = br.ReadBytes((int)br.BaseStream.Length - 34 - nKeySize);
    br.Close();
  }
  // Sitzungsschlüssel entschlüsseln
  RSACryptoServiceProvider rSACSP = (RSACryptoServiceProvider)cert.PrivateKey;
  byte[] byteDecryptedSessionKey = rSACSP.Decrypt(byteEncryptedSessionKey, 
                                   false);
  // Nutzdaten entschlüsseln
  byte[] byteDecData = DecryptAES(byteEncData, byteDecryptedSessionKey, byteIV);
  // Nutzdaten als Klartext in Zieldatei speichern
  using (BinaryWriter bw = new BinaryWriter(File.Create("TargetFile")))
  {
    bw.Write(byteDecData);
   	 bw.Close();
  }
}

Sowohl bei der Verschlüsselung, als auch bei der Entschlüsselung wird auf die Quell- oder Zieldateien grundsätzlich im binären Format zugegriffen, da sonst nur eine Verarbeitung von reinen ASCII-Dateien möglich wäre.
Während bei den Standardverfahren wie beispielsweise PGP (Pretty Good Privacy) die Strukturen und die eingesetzten kryptografischen Algorithmen detailliert offen liegen und somit grundsätzlich einen gewissen Angriffspunkt liefern, sind bei selbst definierten Strukturen lediglich völlig indifferente Bytesequenzen aus den verschlüsselten Dateien lesbar. Ob die verschlüsselten Nutzdaten am Anfang, am Ende oder in der Mitte einer Datei gespeichert sind, und welche Länge die einzelnen Sequenzen haben, ist vollständig unbekannt. Eine Herstellung der unverschlüsselten Nutzdaten scheint unter diesen Umständen mit vertretbarem Aufwand an Zeit und Equipment nahezu völlig unmöglich.
Die im Abschnitt GDrive-API beschriebenen Funktionalitäten bezüglich Upload oder Download von Dateien sind ohne Weiteres in den hier vorgestellten PKCS12Cryptor integrierbar, sodass als Quell- oder Zieldatei eine GDrive-Datei selektiert werden kann. Alternativ können mit PKCS12Cryptor verschlüsselte Dateien einfach in das Transferverzeichnis von SkyDrive, GDrive oder anderen Anbietern kopiert werden. Die Synchronisierung, also beispielsweise das Hochladen einer Datei, sollte automatisch erfolgen.

Dateiexplorerintegration PKCS12Cryptor

Wird ein ausführbares Programm, wie die Applikation PKCS12Cryptor.exe, in geeigneter Weise im Windows-System registriert, kann es wie in Abbildung 6 gezeigt, via Dateiexplorer gestartet werden, und zwar so, dass durch einen Rechtsklick auf eine zu verarbeitende Datei ein Popup-Menü aktiviert wird, das den Programmnamen (PKCS12Cryptor) enthält. Durch einfaches Anklicken des Popup-Menüpunkts wird die gewählte Applikation gestartet, und es wird der Name der zu verarbeitenden Datei als Aufrufparameter an die gestartete Applikation übergeben. Im gezeigten Beispiel wurde die Datei 1.jpg.enc mit der rechten Maustaste angeklickt und daran anschließend mit einem weiteren Klick mit der linken Maustaste auf PKCS12Cryptor die Applikation gestartet.
Abb. 6: PKCS12Cryptor starten via Dateiexplorer

Der Aufrufparameter der via Popup-Menü gestarteten Applikation, in diesem Fall der Name der zu verarbeitenden Datei, kann gemäß Listing 11 direkt aus dem args-Array einer Main-Funktion übernommen werden, wobei diese Option für Konsolenanwendungen geeignet ist. Der Array-Index beträgt in diesem Fall null (0). Alternativ kann der Aufrufparameter auch via Environment.GetCommandLineArgs() abgerufen werden. Diese Methode bietet sich bei Windows-Programmen an, also beispielsweise wie ebenfalls in Listing 11 gezeigt, innerhalb der Ladeprozedur eines Formulars. Zu beachten ist hier, dass der Array-Index nun eins (1) beträgt.

static public string sFileName = "Default";
[STAThread]
static void Main(string[] args)
{
  if(args.Length == 1)    
  sFileName = args[0];
}
// Alternativ
private void StartForm_Load(object sender, EventArgs e)
{
  string[] sArgs = Environment.GetCommandLineArgs();
  sFileName = sCommandLineArgs[1];
}

Die erforderliche Registration ist gemäß Abbildung 7 im Registrierungseditor durchzuführen. Hierzu ist zunächst ein neuer Schlüssel mit der Bezeichnung der Applikation (PKCS12Cryptor) unter HKEY_CLASSES_ROOT*shell anzulegen. Unterhalb dieses neuen Schlüssels ist ein weiterer Schlüssel mit der Bezeichnung command anzulegen. Wie in Abbildung 7 dargestellt, enthält der Schlüssel command unter dem Namen Standard einen Eintrag vom Typ REG_SZ. Als Wert für diese Zeichenfolge ist die aufzurufende Applikation gefolgt von %1 vorzugeben. Der in Abbildung 5 gezeigte PKCS12Cryptor ist so programmiert, dass die im Dateiexplorer selektierte Datei direkt als „Quelldatei“ angezeigt, der Mode automatisch auf „Entschlüsseln“ oder „Verschlüsseln“ eingestellt und die Aufschrift der betreffenden Schaltfläche ebenfalls kontextsensitiv aktualisiert wird.

Abb. 7: PKCS12Cryptor registrieren

Fazit

Selbst lokale Dateien mit privaten oder sicherheitskritischen Geschäftsdaten sollten ausschließlich verschlüsselt abgespeichert werden, um sie vor unbefugten Dritten zu schützen. Diesbezüglich können natürlich gesamte Festplatten mit Microsoft-Bitlocker, dem frei verfügbaren Tool TrueCrypt oder Ähnlichem verschlüsselt werden. Letztendlich lässt sich jedoch nicht mit absoluter Sicherheit sagen, ob solche Tools nicht doch eine versteckte Hintertüre eingebaut haben. Weiterhin kann nicht per se gesagt werden, ob die aus diversen Downloadquellen stammenden Programme/Tools nicht schon vor oder während des Herunterladens manipuliert wurden. Implementiert man allerdings ein eigenes Tool, wie beispielsweise die diesen Artikel flankierende Anwendung „PKCS12Cryptor“, dann kann zumindest diese Unsicherheit ausgeschlossen werden.
Letztendlich muss allerdings jeder für sich selbst entscheiden, wie sorgsam oder sorglos mit Daten umgegangen wird, sodass sich der bekannte Cloud-Computing-Slogan nicht unfreiwillig wie folgt erweitert: „Zugriff immer und von überall – von jedermann“.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -