OpenXML Password Protection

In diesem Post möchte ich Quelltext vorstellen mit dessen Hilfe ein Word-Dokument per OpenXML mit einem Passwort-Schutz versehen werden kann. Die statische Methode “ApplyDocumentProtection” setzt ein per Zufall ausgewähltes Passwort (Hash und Salt) und liefert das Passwort im Klartext (Pass) zurück. Die Liste der vordefinierten Passworte kann beliebig erweitert werden. Siehe dazu auch die Kommentare im Quelltext.
using System;
using System.Linq;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;

namespace OpenXMLTools
{
  // Diese Klasse enthält eine statische Methode zum Setzen eines Forms-Dokumentschutzes.
  // Das Passwort wird zufällig aus einer Liste ausgewählt.
  // Die Liste der Passworte kann erweitert werden.
  // Dazu einfach ein Passwort in Word setzen. Dokument anschließend mit dem OpenXML SDK Productiviy-Tool öffnen und Hash- und Salt-Wert
  // bei der Initialisierung der Passworte ergänzen.
  //
  // Außerdem muss anschließend in der Zeile
  // index = Convert.ToInt32(Math.Floor((3 * new Random().NextDouble())));
  // der Wert "3" entsprechend erhöht werden.
  public static class Tools
  {
    private static Protection[] protection = new Protection[3];

    static Tools()
    {
      // Initialisierung von Passworten
      protection[0].Pass = "Passwort1";
      protection[0].Hash = "gmfbcju55A0DSckelTAvyaHnbn0=";
      protection[0].Salt = "1IcXKEEmed1hRQQUnhX2zg==";

      protection[1].Pass = "Passwort2";
      protection[1].Hash = "i1WC8gI6AkPJSDfZK1ELMYG/anU=";
      protection[1].Salt = "q96ar2VXAk/LuO2glF+u4w==";

      protection[2].Pass = "Passwort3";
      protection[2].Hash = "ycHxPRqF4IE4iZKXIW4RzZKAeyo=";
      protection[2].Salt = "bC2+DsLquk3QnKg7rA5eug==";
    }

    // Dokumentschutz setzen. Es wird per Zufall eins von 3 vordefinierten Passworten verwendet.
    public static string ApplyDocumentProtection(WordprocessingDocument document, bool setPassword = true)
    {
      int index = 0;

      // Setzen des Dokumentschutzes
      DocumentProtection documentProtection = new DocumentProtection();
      documentProtection.Edit = DocumentProtectionValues.Forms;
      documentProtection.Enforcement = new OnOffValue(true);

      if (setPassword)
      {
        // Auswahl des Passworts
        index = Convert.ToInt32(Math.Floor((3 * new Random().NextDouble())));

        documentProtection.CryptographicAlgorithmClass = CryptAlgorithmClassValues.Hash;
        documentProtection.CryptographicProviderType = CryptProviderValues.RsaFull;
        documentProtection.CryptographicAlgorithmType = CryptAlgorithmValues.TypeAny;
        documentProtection.CryptographicAlgorithmSid = 4; // SHA1
        documentProtection.CryptographicSpinCount = 50000;
        documentProtection.Hash = Tools.protection[index].Hash;
        documentProtection.Salt = Tools.protection[index].Salt;
      }

      // Fall DocumentProtection bereits vorhanden, vorher löschen.
      DocumentProtection existingDocumentProtection = document.MainDocumentPart.DocumentSettingsPart.Settings.Descendants<DocumentProtection>().FirstOrDefault();
      if (existingDocumentProtection != null)
      {
        existingDocumentProtection.Remove();
      }

      // DocumentProtection muss vor DefaultTabStop stehen. Ansonsten gibt es einen Validation-Error!
      DefaultTabStop defaultTabStop = document.MainDocumentPart.DocumentSettingsPart.Settings.Descendants<DefaultTabStop>().FirstOrDefault();
      defaultTabStop.InsertBeforeSelf(documentProtection);

      document.MainDocumentPart.DocumentSettingsPart.Settings.Save();

      if (setPassword)
      {
        // Rückgabe des unverschlüsselten Passworts
        return protection[index].Pass;
      }
      else
      {
        return string.Empty;
      }
    }

    // Struktur wird von ApplyDocumentProtection benötigt
    private struct Protection
    {
      // Unverschlüsseltes Password
      public string Pass { get; set; }

      // Hash-Wert mit dem der Passwortschutz gesetzt wird.
      public string Hash { get; set; }

      // Salt-Wert mit dem der Passwortschutz gesetzt wird.
      public string Salt { get; set; }
    }
  }
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s