Kryptographie mit Java

+ andere TechDocs
+ Kryptographie
+ Java SE Security Technologies
+ Java SE Security Guides/APIs
+




Inhalt

  1. Einige wichtige Begriffe
  2. Grober Vergleich einiger Vorgehensweisen zur Verschlüsselung von Dateien
  3. Symmetrische Verschlüsselung mit AES, Blowfish und DES
  4. Asymmetrische / hybride Verschlüsselung mit RSA und AES (oder Blowfish)
  5. OpenPGP-Verschlüsselung mit GnuPG (GNU Privacy Guard)
  6. OpenPGP-Verschlüsselung mit dem Bouncy Castle Crypto API
  7. Kooperation zwischen GnuPG und BC (Bouncy Castle Crypto API)
  8. Symmetrische WinZip-kompatible AES-Verschlüsselung
  9. Bemerkungen zur Performance und Verarbeitung großer Dateien


Einige wichtige Begriffe

Symmetrisches Kryptosystem
Beim symmetrischen Kryptosystem wird zum Ver- und Entschlüsseln derselbe Schlüssel verwendet (im Gegensatz zum asymmetrischen Kryptosystem).
Symmetrische Kryptosysteme sind schneller als asymmetrische, aber haben den Nachteil, dass der geheime Schlüssel zum Empfänger übertragen werden muss. Komprimierprogramme (z.B. WinZip und 7-Zip) bieten häufig symmetrische Verschlüsselung an. Wenn Verschlüssler und Entschlüssler dieselbe Person ist, entfällt der Nachteil der schwierigen Übertragung des geheimen Schlüssels.
Beispiele für symmetrische Kryptosysteme:
Asymmetrisches Kryptosystem (auch Public-Key-Verfahren genannt)
Beim asymmetrischen Kryptosystem besitzen die kommunizierenden Parteien jeweils ein Schlüsselpaar, das aus einem geheimen privaten Schlüssel und einem öffentlichen Schlüssel besteht. Der öffentliche Schlüssel ermöglicht es jedem, Daten für den Inhaber des dazu passenden privaten Schlüssels zu verschlüsseln, dessen digitale Signaturen zu prüfen oder ihn zu authentifizieren. Der private Schlüssel ermöglicht es dagegen seinem Inhaber, mit dem dazu passenden öffentlichen Schlüssel verschlüsselte Daten zu entschlüsseln, digitale Signaturen zu erzeugen oder sich zu authentisieren.
Asymmetrische Kryptosysteme sind langsamer als symmetrische, aber haben den Vorteil, dass kein geheimer Schlüssel zum Empfänger übertragen werden muss.
Beispiele für asymmetrische Kryptosysteme:
Hybride Verschlüsselung
Wenn man von asymmetrischer Verschlüsselung spricht, ist meistens hybride Verschlüsselung gemeint. Hybride Verschlüsselung vereint die Vorteile asymmetrischer und symmetrischer Verschlüsselung. Mit einem immer wieder neu generierten (möglichst "zufälligen") geheimen Schlüssel ("Secret Key", "Session Key") werden die zu schützenden Daten symmetrisch verschlüsselt. Anschließend wird der geheime Session-Key asymmetrisch mit dem öffentlichen Schlüssel des Empfängers verschlüsselt und verschlüsselt den verschlüsselten Daten hinzugefügt.
Die hybride Verschlüsselung nutzt die hohe Geschwindigkeit der symmetrischen Verschlüsselung. Trotzdem braucht kein geheimer Schlüssel übertragen zu werden, da nur der öffentliche Public Key benötigt wird.
Übliche Schlüssellängen sind 1024 Bit für den öffentlichen Public Key für die asymmetrische Verschlüsselung und 128 Bit für den internen Session Key für die symmetrische Verschlüsselung (oder bei erhöhten Sicherheitsanforderungen 2048 und 256 Bit).
Die hybride Verschlüsselung kann beispielsweise folgendermaßen erfolgen (im Beispiel inklusive Signatur):
  1. Aus der Klartextnachricht wird über eine Hash-Funktion (z.B. SHA oder MD5) ein kurzer Message Digest der Nachricht erzeugt.
  2. Aus diesem Message Digest wird mit dem privaten Schlüssel des Senders eine digitale Signatur erzeugt.
  3. Die Klartextnachricht und die digitale Signatur werden zusammen komprimiert.
  4. Das Ergebnis wird mit dem generierten Session Key symmetrisch zum Ciphertext verschlüsselt.
  5. Der generierte Session Key wird mit dem öffentlichen Schlüssel des Empfängers asymmetrisch verschlüsselt.
  6. Der symmetrisch verschlüsselte Ciphertext und der asymmetrisch verschlüsselte Session Key werden zusammengepackt.
  7. Falls das Ergebnis als E-Mail-Text versendet werden soll, wird es mittels Base64 in ASCII-Zeichen codiert.
Beispiele für hybride Verschlüsselungssysteme:
Kryptologische Hashfunktion (Einweg-Hash, eindeutiger Fingerprint, Fingerabdruck, Prüfsumme)
Mit der kryptologischen Hashfunktion wird aus den Nutzdaten eine eindeutige und möglichst individuelle Zeichenfolge (Hashwert) generiert (meistens von fester Länge). Jede Änderung an den Nutzdaten führt zu einem anderen Hashwert. Aus dem Hashwert kann nicht auf die Nutzdaten geschlossen werden.
Beispiele für Hashalgorithmen:
Folgendermaßen kann der Hashwert berechnet werden:
static byte[] messageDigest( InputStream is, String algo ) throws NoSuchAlgorithmException, IOException
{
   MessageDigest messageDigest = MessageDigest.getInstance( algo ); // algo z.B.: "MD5" oder "SHA-1"
   byte[] ba = new byte[8192];
   for( int n = 0; (n = is.read( ba )) > -1; ) { messageDigest.update( ba, 0, n ); }
   return messageDigest.digest(); // 16 Bytes fuer MD5, 20 Bytes fuer SHA-1
}
DSA (Digital Signature Algorithm)
DSA (Digital Signature Algorithm) standardisiert digitale Signaturen (bitte nicht verwechseln mit "E-Mail-Signatur" und auch nicht mit "qualifizierter elektronischer Signatur nach dem Signaturgesetz").
Folgendermaßen kann eine Signatur berechnet werden:
static byte[] signature( InputStream is, PrivateKey privateKey ) throws GeneralSecurityException, IOException
{
   Signature signature = Signature.getInstance( "SHA/DSA" );
   signature.initSign( privateKey );
   byte[] ba = new byte[8192];
   for( int n = 0; (n = is.read( ba )) > -1; ) { signature.update( ba, 0, n ); }
   return signature.sign();
}
Digitales Zertifikat, Public-Key-Zertifikat
Ein digitales Zertifikat ist ein digitaler Datensatz, der bestimmte Eigenschaften von Personen oder Objekten bestätigt, und dessen Authentizität und Integrität durch kryptografische Verfahren geprüft werden kann.
Meistens sind digitale Zertifikate Public-Key-Zertifikate und beinhalten einen öffentlichen Schlüssel, zum Beispiel für:
OpenPGP versus S/MIME
Beides sind zuverlässige Standards zum Signieren und Verschlüsseln von Dateien und E-Mails mit dem asymmetrischen "Public-Key-Verfahren", aber sie sind nicht kompatibel:
Gpg4win
Gpg4win ist ein Installationspaket für Windows mit Programmen zur E-Mail- und Dateiverschlüsselung. Gpg4win enthält GnuPG (GNU Privacy Guard) (die eigentliche Verschlüsselungs-Software), Kleopatra (zentrale Zertifikatsverwaltung und einheitliche Benutzerführung) und weitere Module.
Die in Gpg4win enthaltenen Programme sind "Freie Software" ("OSS, Open Source Software", GNU-GPL-Lizenz). GnuPG basiert auf dem Standard OpenPGP (RFC 2440, 4880), ist kompatibel zu PGP und benutzt die gleiche Infrastruktur (Zertifikatsserver etc.) wie PGP. Zusätzlich wird auch der Standard S/MIME (IETF RFC 3851, ITU-T X.509 und ISIS-MTT/Common PKI) unterstützt.
Zu Gpg4win gibt es ein leicht verständliches Kompendium.
Java SE Security Technologies, Java SE Security Guides/APIs
Beispiele:
Erweiterte Schlüssellängen per "Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files"
Folgender Code listet die Security-Provider und einige maximale Schlüssellängen auf:
import javax.crypto.Cipher;
import java.security.*;

public class MaximaleSchluessellaengen {
   public static void main( String[] args ) throws GeneralSecurityException {
      System.out.println( "\nSecurity-Provider:" );
      for( Provider prov : Security.getProviders() ) {
         System.out.println( "  " + prov + ": " + prov.getInfo() );
      }
      System.out.println( "\nMaxAllowedKeyLength (fuer '" + Cipher.getInstance( "AES" ).getProvider() + "' mit aktuellen 'JCE Policy Files'):\n"
            + "  DES        = " + Cipher.getMaxAllowedKeyLength( "DES"        ) + "\n"
            + "  Triple DES = " + Cipher.getMaxAllowedKeyLength( "Triple DES" ) + "\n"
            + "  AES        = " + Cipher.getMaxAllowedKeyLength( "AES"        ) + "\n"
            + "  Blowfish   = " + Cipher.getMaxAllowedKeyLength( "Blowfish"   ) + "\n"
            + "  RSA        = " + Cipher.getMaxAllowedKeyLength( "RSA"        ) + "\n" );
   }
}
Das in Java SE 8 enthaltene JCE unterstützt nur begrenzte Schlüssellängen (z.B. 128 Bit für AES). Bei dem Versuch, längere Schlüssel zu verwenden, erhalten Sie:
java.security.InvalidKeyException: Illegal key size or default parameters.
Um längere Schlüssel verwenden zu können, müssen Sie folgendermaßen Unlimited Strength Policy Files downloaden und installieren:
Downloaden Sie ziemlich weit unten von der Java-Download-Seite unter "Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files" jce_policy-8.zip. Entzippen Sie den Download.
Ersetzen Sie in Ihren JRE- und JDK-Installationen in den jeweiligen jre/lib/security-Unterverzeichnissen die beiden Dateien local_policy.jar und US_export_policy.jar durch die entsprechenden Dateien aus dem Download, beispielsweise in C:\Program Files\Java\jdk1.8\jre\lib\security und in C:\Program Files\Java\jre1.8\lib\security.
Falls Sie einen Java EE Application Server betreiben, der eine eigene Java-Version enthält, dann müssen Sie die Ersetzungen auch dort durchführen.
Bouncy Castle Crypto API
Das Bouncy Castle Crypto API bietet:
Folgendermaßen fügen Sie den BouncyCastleProvider hinzu und verwenden ihn zur Cipher-Erzeugung (im Beispiel für "AES"):
java.security.Security.addProvider( new org.bouncycastle.jce.provider.BouncyCastleProvider() );
Cipher bcCipher = Cipher.getInstance( "AES", "BC" ); // "BC" = BouncyCastleProvider
In einigen der downloadbaren zip-Dateien (z.B. bcpg-jdk15on-147.zip) finden Sie in examples-Unterverzeichnissen Programmierbeispiele (z.B. zu OpenPGP in bcpg-jdk15on-147\src.zip\org\bouncycastle\openpgp\examples).
Dateiendungen
Beispiele für übliche Dateiendungen im Zusammenhang mit OpenPGP und S/MIME:
.ascOpenPGP-Zertifikat, OpenPGP-Signatur oder per OpenPGP verschlüsselte Datei im Textformat (ASCII, "armor")
.bpgPer Bouncy Castle Crypto API verschlüsselte Datei im Binärformat
.crtX.509-Zertifikat (application/pkix-cert)
.derX.509-Zertifikat (application/x-x509-ca-cert)
.gpgOpenPGP-Zertifikat oder per OpenPGP verschlüsselte Datei im Binärformat (application/pgp-encrypted)
.p7mPer S/MIME verschlüsselte Datei im Binärformat (PKI PKCS#7-Format)
.p7sS/MIME-Signatur im Binärformat (PKI PKCS#7-Format)
.p12X.509-Zertifikat (PKI PKCS#12-Format)
.pemX.509-Zertifikat, S/MIME-Signatur oder per S/MIME verschlüsselte Datei oder E-Mail im Base64-Textformat (Privacy Enhanced Mail)
.sigOpenPGP-Signatur im Binärformat
Weitere Dateiendungen finden Sie unter Dateinamenserweiterungen für Zertifikate und Liste von Dateinamenserweiterungen.


Grober Vergleich einiger Vorgehensweisen zur Verschlüsselung von Dateien

OptionVorteileNachteile
Symmetrisch AES,
proprietär programmiert
+ keine Lib-Abhängigkeit - Übertragung des geheimen Passworts
- proprietär, genaue Absprachen notwendig
- Kompatibilität Java / C#/.NET schwierig
- Sicherheit schwieriger zu beurteilen
Asymmetrisch RSA + AES,
proprietär programmiert
+ öffentliche Schlüssel
+ keine Lib-Abhängigkeit
- proprietär, genaue Absprachen notwendig
- Kompatibilität Java / C#/.NET schwierig
- Sicherheit schwieriger zu beurteilen
Symmetrisch AES,
mit OpenPGP-Lib, z.B.
Bouncy Castle Crypto API
+ kompatibel zu OpenPGP
+ kompatibel zu GnuPG
+ Lib für Java und C#/.NET
- Übertragung des geheimen Passworts
- Abhängig von Fremd-Lib
Asymmetrisch RSA + AES,
mit OpenPGP-Lib, z.B.
Bouncy Castle Crypto API
+ öffentliche Schlüssel
+ kompatibel zu OpenPGP
+ kompatibel zu GnuPG
+ Lib für Java und C#/.NET
- Abhängig von Fremd-Lib
Asymmetrisch RSA + AES,
plus digitale Signatur,
mit OpenPGP-Lib, z.B.
Bouncy Castle Crypto API
+ öffentliche Schlüssel
+ etwas erweiterte Sicherheit
+ kompatibel zu OpenPGP
+ kompatibel zu GnuPG
+ Lib für Java und C#/.NET
- umständlicher, weil mehrere Schlüssel
- Absprachen erforderlich
- event. wesentlich schlechtere Performance
- Abhängig von Fremd-Lib
Asymmetrisch RSA + AES,
GnuPG per Batch-Skript
+ öffentliche Schlüssel
+ kompatibel zu OpenPGP
+ kompatibel zu GnuPG
- nur Kommandozeilentool für Skripte
- keine Java-Lib
- benötigt Extra-Prozess (z.B. cron-Job)


Symmetrische Verschlüsselung mit AES, Blowfish und DES

Das folgende rudimentäre Programmierbeispiel zeigt den Einsatz der Cipher-Klasse zur Ver- und Entschlüsselung nach dem symmetrischen AES-, Blowfish- und DES-Algorithmus.

Um das Beispiel einfach zu halten, wird vom Passwort lediglich ein MD5-Hash erzeugt, aber auf "Salt", "Initialization Vector (IV)", "Iterationen" etc. verzichtet (siehe auch PBE (Password-based Encryption)).

  1. Erzeugen Sie die Klasse: CryptoSimple.java

    import java.io.*;
    import java.security.*;
    import java.util.Arrays;
    import javax.crypto.*;
    import javax.crypto.spec.SecretKeySpec;
    
    /** Rudimentaeres Cipher-Beispiel, nicht fuer reale Verwendung geeignet */
    public class CryptoSimple
    {
       public static void main( String[] args ) throws GeneralSecurityException, IOException
       {
          if( args.length == 5 ) {
             if( args[0].toLowerCase().startsWith( "-e" ) ) {        // encrypt
                encrypt( args[1], args[2], args[3], args[4] );
                return;
             } else if( args[0].toLowerCase().startsWith( "-d" ) ) { // decrypt
                decrypt( args[1], args[2], args[3], args[4] );
                return;
             }
          }
          System.out.println( "Fehler: Es werden vier Parameter benoetigt:\n" +
                "Zum Verschluesseln:\n" +
                "  -e Quelldatei EncryptedZieldatei CipherAlgorithmus Passwort\n" +
                "Zum Entschluesseln:\n" +
                "  -d EncryptedQuelldatei DecryptedZieldatei CipherAlgorithmus Passwort\n" );
       }
    
       /** Verschluesseln */
       public static void encrypt( String srcFile, String encryptedDstFile, String algorithm, String password )
             throws GeneralSecurityException, IOException
       {
          encrypt( new FileInputStream( srcFile ), new FileOutputStream( encryptedDstFile ), algorithm, password );
       }
    
       /** Verschluesseln (Streams werden mit close() geschlossen) */
       public static void encrypt( InputStream inpStream, OutputStream encryptedOutStream, String algorithm, String password )
             throws GeneralSecurityException, IOException
       {
          SecretKey secKey = new SecretKeySpec( hashPwd( password, algorithm ), algorithm );
          Cipher    cipher = Cipher.getInstance( algorithm );
          byte[]    byteBuffer = new byte[64 * 1024];
          int       n;
          cipher.init( Cipher.ENCRYPT_MODE, secKey );
          CipherOutputStream cos = new CipherOutputStream( encryptedOutStream, cipher );
          try {
             while( (n = inpStream.read( byteBuffer )) > 0 ) { cos.write( byteBuffer, 0, n ); }
          } finally {
             cos.close();
             encryptedOutStream.close();
             inpStream.close();
          }
       }
    
       /** Entschluesseln */
       public static void decrypt( String encryptedSrcFile, String decryptedDstFile, String algorithm, String password )
             throws GeneralSecurityException, IOException
       {
          decrypt( new FileInputStream( encryptedSrcFile ), new FileOutputStream( decryptedDstFile ), algorithm, password );
       }
    
       /** Entschluesseln (Streams werden mit close() geschlossen) */
       public static void decrypt( InputStream encryptedInpStream, OutputStream decryptedOutStream, String algorithm, String password )
             throws GeneralSecurityException, IOException
       {
          SecretKey secKey = new SecretKeySpec( hashPwd( password, algorithm ), algorithm );
          Cipher    cipher = Cipher.getInstance( algorithm );
          byte[]    byteBuffer = new byte[64 * 1024];
          int       n;
          cipher.init( Cipher.DECRYPT_MODE, secKey );
          CipherInputStream cis = new CipherInputStream( encryptedInpStream, cipher );
          try {
             while( (n = cis.read( byteBuffer )) > 0 ) { decryptedOutStream.write( byteBuffer, 0, n ); }
          } finally {
             cis.close();
             encryptedInpStream.close();
             decryptedOutStream.close();
          }
       }
    
       /** MD5-Hash */
       private static byte[] hashPwd( String password, String algorithm ) throws NoSuchAlgorithmException, UnsupportedEncodingException
       {
          MessageDigest md = MessageDigest.getInstance( "MD5" );
          md.update( password.getBytes( "ISO-8859-1" ) );
          return ( "DES".equals( algorithm ) ) ? Arrays.copyOf( md.digest(), 8 ) : md.digest();
       }
    }
    
  2. Zur Vorbereitung:
    Kompilieren und Testdatei erstellen (es kann auch eine beliebige andere Datei verwendet werden, auch binäre Dateien):

    javac CryptoSimple.java

    echo Mein Text Abc Xyz > MeineDatei.txt

  3. AES-Ver- und -Entschlüsselung:

    java CryptoSimple -e MeineDatei.txt MeineDatei.txt.aes AES "geheim"

    java CryptoSimple -d MeineDatei.txt.aes MeineDatei.txt.aes.txt AES "geheim"

  4. Blowfish-Ver- und -Entschlüsselung:

    java CryptoSimple -e MeineDatei.txt MeineDatei.txt.blowfish Blowfish "geheim"

    java CryptoSimple -d MeineDatei.txt.blowfish MeineDatei.txt.blowfish.txt Blowfish "geheim"

  5. DES-Ver- und -Entschlüsselung:

    java CryptoSimple -e MeineDatei.txt MeineDatei.txt.des DES "geheim"

    java CryptoSimple -d MeineDatei.txt.des MeineDatei.txt.des.txt DES "geheim"

  6. In allen drei Fällen stimmt die Ergebnisdatei MeineDatei.txt...txt mit der ursprünglichen Datei MeineDatei.txt überein. Die drei nicht auf .txt endenden Dateien enthalten jeweils den verschlüsselten Inhalt.



Asymmetrische / hybride Verschlüsselung mit RSA und AES (oder Blowfish)

Das folgende Verschlüsselungsprogrammierbeispiel hat die Eigenschaften:

Führen Sie folgende Schritte durch:

  1. Erstellen Sie ein Projektverzeichnis:

    cd \MeinWorkspace

    md CryptoRsaAes

    cd CryptoRsaAes

    md src\main\java\de\meinefirma\meinprojekt\crypto

    md src\test\java\de\meinefirma\meinprojekt\crypto

    tree /F

  2. Erzeugen Sie im CryptoRsaAes-Projektverzeichnis die Maven-Projektkonfigurationsdatei: pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>de.meinefirma.meinprojekt</groupId>
      <artifactId>CryptoRsaAes</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>jar</packaging>
      <name>CryptoRsaAes</name>
      <properties>
        <project.build.sourceEncoding>ISO-8859-1</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
      </properties>
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.4</version>
            <configuration>
              <source>1.6</source>
              <target>1.6</target>
            </configuration>
          </plugin>
        </plugins>
      </build>
      <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.10</version>
          <scope>test</scope>
        </dependency>
      </dependencies>
    </project>
    
  3. Erzeugen Sie im Verzeichnis src\main\java\de\meinefirma\meinprojekt\crypto die Klasse: CryptoRsaAes.java

    package de.meinefirma.meinprojekt.crypto;
    
    import java.io.*;
    import java.security.*;
    import javax.crypto.*;
    
    public class CryptoRsaAes
    {
       static final String ASYMMETRIC_ALGO = "RSA";
       static final String SYMMETRIC_ALGO  = "AES"; // oder z.B. "Blowfish"
    
       public static void main( String[] args ) throws GeneralSecurityException, ClassNotFoundException, IOException
       {
          if( args.length == 4 ) {
             if( args[0].toLowerCase().startsWith( "-g" ) ) {        // generateKeyPair
                generateKeyPair( args[1], args[2], Integer.parseInt( args[3] ) );
                return;
             } else if( args[0].toLowerCase().startsWith( "-e" ) ) { // encrypt
                encrypt( args[1], args[2], args[3] );
                return;
             } else if( args[0].toLowerCase().startsWith( "-d" ) ) { // decrypt
                decrypt( args[1], args[2], args[3] );
                return;
             }
          }
          System.out.println( "\nFehler: Es werden vier Parameter benoetigt:\n" +
                "Zum Generieren des privaten und oeffentlichen RSA-Schluessels (RsaKeySize z.B. 2048):\n" +
                "  -g PrivateKeyFile PublicKeyFile RsaKeySize\n" +
                "Zum Verschluesseln:\n" +
                "  -e PublicKeyFile InputFile EncryptedFile\n" +
                "Zum Entschluesseln:\n" +
                "  -d PrivateKeyFile EncryptedFile OutputFile\n" );
       }
    
       /** Generiere privaten und oeffentlichen RSA-Schluessel */
       public static void generateKeyPair( String privateKeyFile, String publicKeyFile, int rsaKeySize )
             throws NoSuchAlgorithmException, IOException
       {
          generateKeyPair( new FileOutputStream( privateKeyFile ), new FileOutputStream( publicKeyFile ), rsaKeySize );
       }
    
       /** Generiere privaten und oeffentlichen RSA-Schluessel (Streams werden mit close() geschlossen) */
       public static void generateKeyPair( OutputStream privateKeyFile, OutputStream publicKeyFile, int rsaKeySize )
             throws NoSuchAlgorithmException, IOException
       {
          try {
             KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance( ASYMMETRIC_ALGO );
             keyPairGen.initialize( rsaKeySize );
             KeyPair keyPair = keyPairGen.generateKeyPair();
             ObjectOutputStream out = new ObjectOutputStream( publicKeyFile );
             try { out.writeObject( keyPair.getPublic() ); } finally { out.close(); }
             out = new ObjectOutputStream( privateKeyFile );
             try { out.writeObject( keyPair.getPrivate() ); } finally { out.close(); }
          } finally {
             privateKeyFile.close();
             publicKeyFile.close();
          }
       }
    
       /** Verschluesseln */
       public static void encrypt( String publicKeyFile, String inputFile, String encryptedFile )
             throws GeneralSecurityException, ClassNotFoundException, IOException
       {
          encrypt( new FileInputStream( publicKeyFile ), new FileInputStream( inputFile ), new FileOutputStream( encryptedFile ) );
       }
    
       /** Verschluesseln (Streams werden mit close() geschlossen) */
       public static void encrypt( InputStream publicKeyFile, InputStream inputFile, OutputStream encryptedFile )
             throws GeneralSecurityException, ClassNotFoundException, IOException
       {
          try {
             KeyGenerator keyGen = KeyGenerator.getInstance( SYMMETRIC_ALGO );
             keyGen.init( Math.min( 256, Cipher.getMaxAllowedKeyLength( SYMMETRIC_ALGO ) ) );
             SecretKey symKey = keyGen.generateKey();
             Key publicKey;
    
             ObjectInputStream keyIn = new ObjectInputStream( publicKeyFile );
             try { publicKey = (Key) keyIn.readObject(); } finally { keyIn.close(); }
    
             Cipher cipher = Cipher.getInstance( ASYMMETRIC_ALGO );
             cipher.init( Cipher.WRAP_MODE, publicKey );
             byte[] wrappedKey = cipher.wrap( symKey );
    
             DataOutputStream out = new DataOutputStream( encryptedFile );
             try {
                out.writeInt( wrappedKey.length );
                out.write( wrappedKey );
                cipher = Cipher.getInstance( SYMMETRIC_ALGO );
                cipher.init( Cipher.ENCRYPT_MODE, symKey );
                transform( inputFile, out, cipher );
             } finally {
                out.close();
             }
          } finally {
             publicKeyFile.close();
             inputFile.close();
             encryptedFile.close();
          }
       }
    
       /** Entschluesseln */
       public static void decrypt( String privateKeyFile, String encryptedFile, String outputFile )
             throws GeneralSecurityException, ClassNotFoundException, IOException
       {
          decrypt( new FileInputStream( privateKeyFile ), new FileInputStream( encryptedFile ), new FileOutputStream( outputFile ) );
       }
    
       /** Entschluesseln (Streams werden mit close() geschlossen) */
       public static void decrypt( InputStream privateKeyFile, InputStream encryptedFile, OutputStream outputFile )
             throws GeneralSecurityException, ClassNotFoundException, IOException
       {
          try {
             DataInputStream in = new DataInputStream( encryptedFile );
             try {
                int length = in.readInt();
                byte[] wrappedKey = new byte[length];
                in.read( wrappedKey, 0, length );
    
                Key privateKey;
                ObjectInputStream keyIn = new ObjectInputStream( privateKeyFile );
                try { privateKey = (Key) keyIn.readObject(); } finally { keyIn.close(); }
    
                Cipher cipher = Cipher.getInstance( ASYMMETRIC_ALGO );
                cipher.init( Cipher.UNWRAP_MODE, privateKey );
                Key symKey = cipher.unwrap( wrappedKey, SYMMETRIC_ALGO, Cipher.SECRET_KEY );
    
                cipher = Cipher.getInstance( SYMMETRIC_ALGO );
                cipher.init( Cipher.DECRYPT_MODE, symKey );
                transform( in, outputFile, cipher );
             } finally {
                in.close();
             }
          } finally {
             privateKeyFile.close();
             encryptedFile.close();
             outputFile.close();
          }
       }
    
       private static void transform( InputStream in, OutputStream out, Cipher cipher )
             throws IOException, GeneralSecurityException
       {
          int    blockSize = cipher.getBlockSize();
          byte[] input     = new byte[blockSize];
          byte[] output    = new byte[cipher.getOutputSize( blockSize )];
          int    len;
          while( (len = in.read( input )) == blockSize ) {
             int outLength = cipher.update( input, 0, blockSize, output );
             out.write( output, 0, outLength );
          }
          out.write( ( len > 0 ) ? cipher.doFinal( input, 0, len ) : cipher.doFinal() );
       }
    }
    
  4. Erzeugen Sie im Verzeichnis src\test\java\de\meinefirma\meinprojekt\crypto den JUnit-Test: CryptoRsaAesTest.java

    package de.meinefirma.meinprojekt.crypto;
    
    import java.io.*;
    import java.security.GeneralSecurityException;
    import java.util.*;
    import org.junit.*;
    
    public class CryptoRsaAesTest
    {
       @Test
       public void testCryptoRsaAes() throws GeneralSecurityException, ClassNotFoundException, IOException
       {
          String privateKeyFile = "target/PrivateKey.rsa";
          String publicKeyFile  = "target/PublicKey.rsa";
          String srcFile        = "target/MeineSrcDatei.txt";
          String encFile        = "target/MeineVerschluesselteDatei.aes.rsa";
          String dstFile        = "target/MeineDstDatei.txt";
          String text           = "Blablupp \u00E4\u00F6\u00FC\u00DF\u20AC"; // Umlaute und Eurozeichen
          String charEnc        = "UTF-8";
    
          BufferedWriter out = new BufferedWriter( new OutputStreamWriter( new FileOutputStream( srcFile ), charEnc ) );
          try { out.write( text ); } finally { out.close(); }
    
          CryptoRsaAes.generateKeyPair( privateKeyFile, publicKeyFile, 2048 );
          Assert.assertTrue( new File( privateKeyFile ).exists() );
          Assert.assertTrue( new File( publicKeyFile  ).exists() );
    
          CryptoRsaAes.encrypt( publicKeyFile, srcFile, encFile );
          Assert.assertTrue( new File( encFile ).exists() );
    
          CryptoRsaAes.decrypt( privateKeyFile, encFile, dstFile );
          Assert.assertTrue( new File( dstFile ).exists() );
    
          List<String>   ss = new ArrayList<String>();
          BufferedReader in = new BufferedReader( new InputStreamReader( new FileInputStream( dstFile ), charEnc ) );
          try {
             String line;
             while( (line = in.readLine()) != null ) {
                ss.add( line );
             }
          } finally {
             in.close();
          }
          Assert.assertEquals( 1, ss.size() );
          Assert.assertEquals( text, ss.get( 0 ) );
       }
    }
    
  5. Die Projektstruktur sieht jetzt so aus:

    cd \MeinWorkspace\CryptoRsaAes

    tree /F

    [\MeinWorkspace\CryptoRsaAes]
     |- [src]
     |   |- [main]
     |   |   '- [java]
     |   |       '- [de]
     |   |           '- [meinefirma]
     |   |               '- [meinprojekt]
     |   |                   '- [crypto]
     |   |                       '- CryptoRsaAes.java
     |   '- [test]
     |       '- [java]
     |           '- [de]
     |               '- [meinefirma]
     |                   '- [meinprojekt]
     |                       '- [crypto]
     |                           '- CryptoRsaAesTest.java
     '- pom.xml
    
  6. Führen Sie den JUnit-Test aus:

    mvn clean test

    Der Test läuft fehlerfrei durch und im target-Verzeichnis entstehen folgende Dateien:

    [\MeinWorkspace\CryptoRsaAes]
     |- [...]
     |   '- ...
     '- [target]
         |- [...]
         |   '- ...
         |- MeineDstDatei.txt  . . . . . . . . . . . [wiederhergestellte entschlüsselte Datei]
         |- MeineSrcDatei.txt  . . . . . . . . . . . [ursprüngliche Originaldatei]
         |- MeineVerschluesselteDatei.aes.rsa  . . . [verschlüsselte Datei]
         |- PrivateKey.rsa   . . . . . . . . . . . . [Privater Schlüssel]
         '- PublicKey.rsa  . . . . . . . . . . . . . [Öffentlicher Schlüssel]
    
  7. Die ursprüngliche Originaldatei und das Ergebnis der Entschlüsselung stimmen überein:

    notepad target\MeineSrcDatei.txt

    notepad target\MeineDstDatei.txt

  8. Folgendermaßen können Sie Public/Private-Key-Paare erzeugen und beliebige Input-Dateien verschlüsseln und wieder entschlüsseln:

    java -cp target\classes de.meinefirma.meinprojekt.crypto.CryptoRsaAes -g PrivateKeyFile.rsa PublicKeyFile.rsa 2048

    java -cp target\classes de.meinefirma.meinprojekt.crypto.CryptoRsaAes -e PublicKeyFile.rsa MeineInputDatei MeineVerschluesselteDatei.aes.rsa

    java -cp target\classes de.meinefirma.meinprojekt.crypto.CryptoRsaAes -d PrivateKeyFile.rsa MeineVerschluesselteDatei.aes.rsa MeineEntschluesselteDatei



OpenPGP-Verschlüsselung mit GnuPG (GNU Privacy Guard)

GnuPG (= GPG, GNU Privacy Guard) ist das bekannteste Open-Source-Verschlüsselungstool. Es implementiert OpenPGP und S/MIME und bietet beispielsweise: RSA, DSA, Elgamal, AES-256, AES-128, CAST5, Triple-DES, Blowfish, SHA-1, SHA-2, RIPEMD-160, ZIP. Hinweise zu präferierten Algorithmen finden Sie hier.

GnuPG gibt es sowohl für Windows als auch für Linux und kann wahlweise als mächtiges Kommandozeilentool oder bequem über grafische Aufsätze (z.B. Kleopatra) oder eingebettet im E-Mail-Programm verwendet werden.

Doku zu GnuPG finden Sie beispielsweise unter: GnuPG-Handbücher, Gpg4win-Kompendium und Deutsche GnuPG-Anleitung von Kai Billen.

Im Folgenden werden nur einige wenige der vielen Möglichkeiten von GnuPG als Kommandozeilentool demonstriert, um dann weiter unten die kompatible Zusammenarbeit mit dem Bouncy Castle Crypto API zeigen zu können.

  1. Der einfachste Weg, um GnuPG unter Windows zu installieren, führt über Gpg4win (für die hier gezeigten Beispiele genügt eine Minimalinstallation). Downloaden Sie Gpg4win (z.B. gpg4win-2.1.0.exe) von http://www.gpg4win.de/download-de.html.

  2. Starten Sie das Gpg4win-Installationsprogramm (z.B. gpg4win-2.1.0.exe). Beim Dialog "Komponenten auswählen" können Sie alles außer GnuPG deaktivieren (es sei denn, Sie wollen auch andere Komponenten nutzen). Bestätigen Sie in allen anderen Dialogen die Voreinstellungen mit "Weiter".
    Alternativ zur Dialog-gesteuerten Installation gibt es auch die Möglichkeit der Silent Installation.

  3. Unter Windows erweitert die Installation den Suchpfad um das GnuPG-Verzeichnis %ProgramFiles(x86)%\GNU\GnuPG\pub (z.B. C:\Program Files (x86)\GNU\GnuPG\pub), siehe je nach Windows-Version:

    dir "%ProgramFiles(x86)%\GNU\GnuPG\pub"

    dir "%ProgramFiles%\GNU\GnuPG\pub"

  4. Unter Windows werden persönliche GnuPG-Daten gespeichert in %APPDATA%\gnupg (z.B. C:\Users\<Benutzername>\AppData\Roaming\gnupg), siehe:

    dir "%APPDATA%\gnupg"

    Von diesem Verzeichnis sollten Sie regelmäßig ein Backup sichern.

  5. Öffnen Sie ein Kommandozeilenfenster und testen Sie folgende Kommandos:

    gpg2.exe --version

    gpg2.exe -h

  6. Generieren Sie für Tests mit asymmetrischer (hybrider) Verschlüsselung ein Test-Public/Private-Schlüsselpaar (wenn Sie als Kommentartext das vorgeschlagene "GPG-Test" eintragen, können Sie die weiter unten folgenden Beispiele leichter nachvollziehen):

    gpg2 --gen-key

       1    (für "RSA und RSA")

       2048 (Schlüssellänge)

       0    (verfällt nie)

       j    (richtig)

       Mein Name

       MeinName@MeinServer.de

       GPG-Test

       f

       Meine geheime GPG-Passphrase 42

    Sie erhalten:

    trust-db erzeugt
    uid: Mein Name (GPG-Test) <MeinName@MeinServer.de>

  7. Lassen Sie sich die gespeicherten Schlüssel anzeigen (mit verschiedenen Aufrufvarianten):

    gpg2 --list-keys

    gpg2 --list-keys "Mein Name"

    gpg2 --list-keys "MeinName@MeinServer.de"

    gpg2 --list-keys "GPG-Test"

    gpg2 --list-keys --fingerprint

    gpg2 --list-sigs --fingerprint

    Die erste Zahl (z.B. 1024, 2048) bedeutet die asymmetrische Schlüssellänge, dahinter der einzelne Buchstabe steht für den asymmetrischen Schlüssel (R = RSA, D = DSA, g = Elgamal) und nach dem Schrägstrich folgt die 8-stellige Schlüssel-ID (= letzte 8 Stellen des 40-stelligen Fingerprint).

    Weitere Erläuterungen finden Sie unter Schlüsseltypen, Algorithmen und Abkürzungen bei Schlüsseln.

  8. Exportieren Sie die erstellten Public und Private Keys (der Ausdruck "GPG-Test" identifiziert als Teilstring des Schlüsselnamens den Schlüssel):

    gpg2 -ao GPG-Test-pubkey.asc --export "GPG-Test"

    gpg2 -o GPG-Test-seckey.gpg --export-secret-keys "GPG-Test"

    Fügen Sie andere übergebene Schlüssel Ihrem Schlüsselring hinzu:

    gpg2 --import <Schlüsseldatei>

    gpg2 --fetch-keys <URL>

    Löschen Sie Schlüssel aus Ihrem Schlüsselring:

    gpg2 --batch --yes --delete-secret-and-public-key <Key-ID>

  9. Lassen Sie sich Eigenschaften des Schlüssels anzeigen, zum Beispiel die präferierten Algorithmen:

    gpg2 --edit-key "GPG-Test"

       pref       (Kurzversion)

       showpref   (ausführlichere Version)

       quit

    Weitere Infos zum Schlüssel:

    gpg2 --list-packets GPG-Test-pubkey.asc

    Erläuterungen finden Sie unter Schlüsseltypen, Algorithmen und Abkürzungen bei Schlüsseln.

  10. Erstellen Sie eine beliebige Testdatei (wahlweise Text oder binär), zum Beispiel so:

    echo Mein Text Abc Xyz > MeineDatei.txt

  11. Testen Sie symmetrische Ver- und Entschlüsselung ("-c" bedeutet symmetrisch, "-d" decrypt, "s2k" String-to-Key):

    gpg2 --cipher-algo AES --s2k-digest-algo SHA1 -c MeineDatei.txt

    gpg2 -o MeineDatei-AES-decrypted.txt -d MeineDatei.txt.gpg

    type MeineDatei-AES-decrypted.txt

  12. Testen Sie asymmetrische (hybride) Ver- und Entschlüsselung ("-e" steht für encrypt, "-d" für decrypt, "-r" für recipient):

    if exist MeineDatei.txt.gpg del MeineDatei.txt.gpg

    gpg2 -er "GPG-Test" MeineDatei.txt

    gpg2 -o MeineDatei-RSA-decrypted.txt -d MeineDatei.txt.gpg

    type MeineDatei-RSA-decrypted.txt

    (Weiter unten finden Sie eine realistischere Kommandofolge, falls Versender und Empfänger verschiedene Personen sind.)

    Wenn Sie nicht nur verschlüsseln, sondern zusätzlich vorher signieren wollen ("-s" für signieren):

    gpg2 -ser "GPG-Test" MeineDatei.txt

    (Auch hierzu finden Sie weiter unten eine realistischere Kommandofolge.)

    Wenn Sie beim Entschlüsseln die geheime Passphrase nicht per Dialog, sondern per Kommandozeile übergeben wollen (was Sie normalerweise vermeiden sollten, weil es ein Sicherheitsrisiko darstellt):

    gpg2 --batch --passphrase "Meine geheime GPG-Passphrase 42" -o MeineDatei-RSA-decrypted.txt -d MeineDatei.txt.gpg

    Oder alternativ per Passphrasen-Datei (achten Sie darauf, dass in der Passphrasen-Datei nach der Passphrase kein Zeilenendezeichen folgen darf):

    gpg2 --batch --passphrase-file MeinePassphrasenDatei -o MeineDatei-RSA-decrypted.txt -d MeineDatei.txt.gpg

  13. Anzeige des Message-Digest-Hash einer Datei (z.B. mit MD5, SHA1, RIPEMD160):

    gpg2 --print-md SHA1 MeineDatei.txt



OpenPGP-Verschlüsselung mit dem Bouncy Castle Crypto API

Wie bereits weiter oben erwähnt, bietet das Bouncy Castle Crypto API:

Im Folgenden wird die Verwendung einiger in den Bouncy-Castle-examples vorbereiteten Beispielen zu OpenPGP gezeigt.

  1. Downloaden Sie von http://www.bouncycastle.org/latest_releases.html:
    bcprov-jdk15on-147.jar, bcpg-jdk15on-147.jar und bcpg-jdk15on-147.zip.

  2. Entzippen Sie bcpg-jdk15on-147.zip und die darin enthaltene src.zip.

  3. Erstellen Sie ein neues Verzeichnis (z.B. \MeinWorkspace\CryptoOpenPgpBouncyCastle) und kopieren Sie dort hinein die beiden .jar-Libs bcprov-jdk15on-147.jar und bcpg-jdk15on-147.jar sowie aus bcpg-jdk15on-147\src.zip\org\bouncycastle\openpgp\examples die sechs .java-Dateien: KeyBasedFileProcessor.java, KeyBasedLargeFileProcessor.java, PBEFileProcessor.java, PGPExampleUtil.java, RSAKeyPairGenerator.java und SignedFileProcessor.java.

  4. Um kurze einfache Kommandozeilen zu ermöglichen, entfernen Sie aus allen sechs kopierten .java-Dateien jeweils die erste Zeile (package org.bouncycastle.openpgp.examples;).

  5. Ihr Verzeichnis sieht jetzt so aus:

    [\MeinWorkspace\CryptoOpenPgpBouncyCastle]
     |- bcpg-jdk15on-147.jar
     |- bcprov-jdk15on-147.jar
     |- KeyBasedFileProcessor.java
     |- KeyBasedLargeFileProcessor.java
     |- PBEFileProcessor.java
     |- PGPExampleUtil.java
     |- RSAKeyPairGenerator.java
     '- SignedFileProcessor.java
    
  6. Kompilieren Sie und erstellen Sie eine beliebige Testdatei (wahlweise Text oder binär), zum Beispiel so:

    javac -cp .;* *.java

    echo Mein Text Abc Xyz > _MeineDatei.txt

  7. Testen Sie die symmetrische Passwortverschlüsselung von Dateien:

    java -cp .;* PBEFileProcessor -e -i _MeineDatei.txt "geheim"

    del  _MeineDatei.txt

    java -cp .;* PBEFileProcessor -d _MeineDatei.txt.bpg "geheim"

    type _MeineDatei.txt

    Sehen Sie sich den Inhalt der verschlüsselten Datei _MeineDatei.txt.bpg an.

  8. Generieren Sie ein RSA-Public-/Private-Key-Paar:

    java -cp .;* RSAKeyPairGenerator -a "MeinName (BC-Test) <ich@myserver.de>" "Meine geheime BC-Passphrase 42"

    dir *.asc

    Durch den -a-Schalter werden nicht binäre, sondern stattdessen ASCII-Schlüsseldateien erstellt (pub.asc und secret.asc), so dass der öffentliche Schlüssel bequem per E-Mail versendet werden kann.

  9. Testen Sie die asymmetrische Public-Key-Based-Verschlüsselung von Dateien:

    java -cp .;* KeyBasedFileProcessor -e -i _MeineDatei.txt pub.asc

    del  _MeineDatei.txt

    java -cp .;* KeyBasedFileProcessor -d _MeineDatei.txt.bpg secret.asc "Meine geheime BC-Passphrase 42"

    type _MeineDatei.txt

  10. Wenn Sie besonders große Dateien haben, sollten Sie den KeyBasedLargeFileProcessor bevorzugen:

    java -cp .;* KeyBasedLargeFileProcessor -e -i _MeineDatei.txt pub.asc

    del  _MeineDatei.txt

    java -cp .;* KeyBasedLargeFileProcessor -d _MeineDatei.txt.bpg secret.asc "Meine geheime BC-Passphrase 42"

    type _MeineDatei.txt

  11. Falls Sie nicht nur verschlüsseln, sondern auch signieren wollen:

    Signieren ("-s") und verschlüsseln ("-e"):

    java -cp .;* SignedFileProcessor -s _MeineDatei.txt secret.asc "Meine geheime BC-Passphrase 42"

    java -cp .;* KeyBasedFileProcessor -e -i _MeineDatei.txt.bpg pub.asc

    dir _MeineDatei.*

  12. Entschlüsseln ("-d") und verifizieren ("-v"):

    del _MeineDatei.txt

    del _MeineDatei.txt.bpg

    java -cp .;* KeyBasedFileProcessor -d _MeineDatei.txt.bpg.bpg secret.asc "Meine geheime BC-Passphrase 42"

    java -cp .;* SignedFileProcessor -v _MeineDatei.txt.bpg pub.asc

    type _MeineDatei.txt

    (Weiter unten finden Sie eine realistischere Kommandofolge, falls Versender und Empfänger verschiedene Personen sind.)

  13. Beim Verschlüsseln sehr großer Dateien müssen Sie beim Aufruf von PBEFileProcessor, KeyBasedFileProcessor etc. mit dem "-Xmx"-Kommandozeilenparameter für ausreichend Heapspeicher sorgen (z.B.: java -Xmx1300M ...).

  14. Beim Signieren sehr großer Dateien mit SignedFileProcessor sollten Sie unbedingt die Hinweise unter Bemerkungen zur Performance und Verarbeitung großer Dateien beachten.

  15. Für den einfacheren Gebrauch können Sie die .jar-Libs und die .class-Dateien in eine einzige ausführbare .jar-Datei packen. Diese kann zum Beispiel mit dem Maven Assembly Plugin erzeugt werden.



Kooperation zwischen GnuPG und BC (Bouncy Castle Crypto API)

Im Folgenden wird angenommen, dass Nachrichten zwischen zwei Teilnehmern ausgetauscht werden sollen, wobei der eine Teilnehmer GnuPG und der andere BC (Bouncy Castle Crypto API) verwendet. Dies ist möglich, weil sowohl GnuPG als auch BC kompatibel zum OpenPGP-Standard sind.

Dieses Kapitel setzt die beiden vorangegangenen Kapitel OpenPGP-Verschlüsselung mit GnuPG (GNU Privacy Guard) und OpenPGP-Verschlüsselung mit dem Bouncy Castle Crypto API fort.

Symmetrisch verschlüsseln

  1. Erstellen Sie eine beliebige Testdatei (wahlweise Text oder binär), zum Beispiel so:

    echo Mein Text Abc Xyz > _MeineDatei.txt

  2. Mit BC symmetrisch verschlüsseln ("-e") zu .bpg:

    java -cp .;* PBEFileProcessor -e -i _MeineDatei.txt "geheim"

  3. .bpg mit GnuPG entschlüsseln ("-d"):

    del  _MeineDatei.txt

    gpg2 --batch --passphrase "geheim" -o _MeineDatei-mit-GnuPG-sym-decrypted.txt -d _MeineDatei.txt.bpg

    type _MeineDatei-mit-GnuPG-sym-decrypted.txt

  4. Mit GnuPG symmetrisch verschlüsseln ("-c") zu .gpg:

    gpg2 --batch --passphrase "geheim" --cipher-algo AES --s2k-digest-algo SHA1 -c _MeineDatei.txt

  5. .gpg mit BC entschlüsseln ("-d"):

    del  _MeineDatei.txt

    java -cp .;* PBEFileProcessor -d _MeineDatei.txt.gpg "geheim"

    type _MeineDatei.txt

Vorbereitung für asymmetrische Verschlüsselung

  1. Zur Vorbereitung müssen beide Teilnehmer jeweils in ihren Systemen Public/Private-Key-Paare generieren und anschließend jeweils den eigenen öffentlichen Public-Key veröffentlichen bzw. dem anderen Teilnehmer zur Verfügung stellen. Die geheimen Private-Keys dürfen niemals jemand anderem mitgeteilt werden.

  2. BC-Teilnehmer:

    Die Schlüsselgenerierung (mit "RSAKeyPairGenerator") ist weiter oben beschrieben. Sie haben als Ergebnis das Public/Private-Key-Paar pub.asc und secret.asc erhalten. pub.asc veröffentlichen Sie (oder übertragen Sie zu Ihrem Partner).

  3. GPG-Teilnehmer:

    Die Schlüsselgenerierung (mit "gpg2 --gen-key") ist weiter oben beschrieben. Überzeugen Sie sich, dass der Schlüssel mit dem Kommentar "GPG-Test" noch gespeichert ist:

    gpg2 --list-keys

    Importieren Sie den fremden Public-Key des anderen Teilnehmers:

    gpg2 --import pub.asc

    gpg2 --list-keys

    Exportieren Sie den eigenen Public-Key in die Datei GPG-Test-pubkey.asc:

    gpg2 -ao GPG-Test-pubkey.asc --export "GPG-Test"

    dir *.asc

    GPG-Test-pubkey.asc veröffentlichen Sie (oder übertragen Sie zu Ihrem Partner).

  4. Erstellen Sie eine beliebige Testdatei (wahlweise Text oder binär), zum Beispiel so:

    echo Mein Text Abc Xyz > _MeineDatei.txt

Asymmetrisch / hybrid verschlüsseln

  1. Mit BC verschlüsseln ("-e") (mit dem fremden Public Key des Empfängers):

    java -cp .;* KeyBasedFileProcessor -e -i _MeineDatei.txt GPG-Test-pubkey.asc

  2. Mit GnuPG entschlüsseln ("-d") (mit dem eigenen geheimen Private Key):

    gpg2 --batch --passphrase "Meine geheime GPG-Passphrase 42" -o _MeineDatei-mit-GnuPG-asym-decrypted.txt -d _MeineDatei.txt.bpg

    type _MeineDatei-mit-GnuPG-asym-decrypted.txt

  3. Mit GnuPG verschlüsseln ("-e" = encrypt, "-r" = recipient) (mit dem fremden Public Key des Empfängers):

    if exist _MeineDatei.txt.gpg del _MeineDatei.txt.gpg

    gpg2 --trust-model always -er "BC-Test" _MeineDatei.txt

  4. Mit BC entschlüsseln ("-d") (mit dem eigenen geheimen Private Key):

    del  _MeineDatei.txt

    java -cp .;* KeyBasedFileProcessor -d _MeineDatei.txt.gpg secret.asc "Meine geheime BC-Passphrase 42"

    type _MeineDatei.txt

Alternativ nicht nur verschlüsseln, sondern auch signieren

  1. Mit BC signieren ("-s") und verschlüsseln ("-e"):

    del *.bpg

    java -cp .;* SignedFileProcessor -s _MeineDatei.txt secret.asc "Meine geheime BC-Passphrase 42"

    java -cp .;* KeyBasedFileProcessor -e -i _MeineDatei.txt.bpg GPG-Test-pubkey.asc

    dir _MeineDatei.*

  2. Mit GnuPG entschlüsseln und verifizieren (beides mit "-d"):

    del _MeineDatei.txt

    del _MeineDatei.txt.bpg

    gpg2 --batch --passphrase "Meine geheime GPG-Passphrase 42" -o _MeineDatei-mit-GPG-asym-decr-verif.bpg -d _MeineDatei.txt.bpg.bpg

    gpg2 -o _MeineDatei-mit-GPG-asym-decr-verif.txt -d _MeineDatei-mit-GPG-asym-decr-verif.bpg

    type _MeineDatei-mit-GPG-asym-decr-verif.txt

  3. Mit GnuPG signieren ("-s") und verschlüsseln ("-e") ("-r" = recipient):

    gpg2 --batch --default-key "GPG-Test" --passphrase "Meine geheime GPG-Passphrase 42" -s _MeineDatei.txt

    gpg2 --trust-model always -er "BC-Test" _MeineDatei.txt.gpg

    dir _MeineDatei.*

  4. Mit BC entschlüsseln ("-d") und verifizieren ("-v"):

    del _MeineDatei.txt

    del _MeineDatei.txt.gpg

    java -cp .;* KeyBasedFileProcessor -d _MeineDatei.txt.gpg.gpg secret.asc "Meine geheime BC-Passphrase 42"

    java -cp .;* SignedFileProcessor -v _MeineDatei.txt.gpg GPG-Test-pubkey.asc

    type _MeineDatei.txt

Adele (adele@gnupp.de)

  1. Mit dem E-Mail-Roboter "Adele (adele@gnupp.de)" können Sie erste Verschlüsselungsversuche durchführen.

  2. Erzeugen Sie ein Schlüsselpaar, wie oben für GnuPG und BC beschrieben ist. Im Falle von GnuPG exportieren Sie den öffentlichen Schlüssel:

    gpg2 -ao GPG-Test-pubkey.asc --export "GPG-Test"

  3. Klicken Sie mit der rechten Maustaste auf die Datei des öffentlichen Schlüssels (z.B. GPG-Test-pubkey.asc) und wählen Sie "Senden an | E-Mail-Empfänger", um das Zertifikat als E-Mail-Anhang zu versenden.

    Tragen Sie im E-Mail-Programm als Empfänger adele@gnupp.de ein und versenden Sie die E-Mail. Sie erhalten nach kurzer Zeit eine mit Ihrem Public Key verschlüsselte Antwort-E-Mail.

  4. Speichern Sie den Antworttext von "-----BEGIN PGP MESSAGE-----" bis inklusive "-----END PGP MESSAGE-----" in die Textdatei AdelesEmail.asc. Entschlüsseln Sie im Falle von GnuPG mit:

    gpg2 --batch --passphrase "Meine geheime GPG-Passphrase 42" -o AdelesEmail.asc.txt -d AdelesEmail.asc

    Die entschlüsselte Antwort in AdelesEmail.asc.txt enthält einen kurzen Text und den Public Key von Adele.

  5. Extrahieren Sie den Public Key von "-----BEGIN PGP PUBLIC KEY BLOCK-----" bis inklusive "-----END PGP PUBLIC KEY BLOCK-----" und speichern ihn in die Textdatei AdelesPublicKey.asc. Importieren Sie Adeles Public Key:

    gpg2 --import AdelesPublicKey.asc

    gpg2 --list-keys

  6. Speichern Sie eine beliebige Nachricht in einer Textdatei, zum Beispiel so:

    echo Hallo Adele, hier ist meine verschluesselte Nachricht > MeineNachrichtAnAdele.txt

    Verschlüsseln Sie diese mit dem Public Key von Adele:

    gpg2 --trust-model always -a -er "Adele" MeineNachrichtAnAdele.txt

    Es entsteht die verschlüsselte Datei MeineNachrichtAnAdele.txt.asc. Versenden Sie diese Datei an adele@gnupp.de.

  7. Nach kurzer Zeit antwortet Adele. Extrahieren Sie aus dem Antworttext den Teil von "-----BEGIN PGP MESSAGE-----" bis inklusive "-----END PGP MESSAGE-----" in die Datei AdelesAntwort.asc und entschlüsseln Sie diese Datei:

    gpg2 --batch --passphrase "Meine geheime GPG-Passphrase 42" -o AdelesAntwort.asc.txt -d AdelesAntwort.asc

    type AdelesAntwort.asc.txt

  8. Adele hat die verschlüsselte Nachricht entschlüsselt und zurückgesendet. Das bedeutet: Adele kann Nachrichten entschlüsseln, die Sie mit Adeles Public Key verschlüsselt haben, und Sie können Nachrichten entschlüsseln, die Adele mit Ihrem Public Key verschlüsselt hat.



Symmetrische WinZip-kompatible AES-Verschlüsselung

Das folgende Verschlüsselungsprogrammierbeispiel hat die Eigenschaften:

Führen Sie folgende Schritte durch:

  1. Erstellen Sie ein Projektverzeichnis:

    cd \MeinWorkspace

    md CryptoWinZipAES

    cd CryptoWinZipAES

    Downloaden Sie winzipaes (z.B. winzipaes_src_20110911.zip) in das neue Projektverzeichnis und führen Sie folgende Kommandos aus:

    jar xf winzipaes_src_20110911.zip

    md src\main\java

    move src\de src\main\java

    md src\main\java\de\meinefirma\meinprojekt\crypto

    md src\test\java\de\meinefirma\meinprojekt\crypto

    tree /F

  2. Erzeugen Sie im CryptoWinZipAES-Projektverzeichnis die Maven-Projektkonfigurationsdatei: pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>de.meinefirma.meinprojekt</groupId>
      <artifactId>CryptoWinZipAES</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>jar</packaging>
      <name>CryptoWinZipAES</name>
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
      </properties>
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.4</version>
            <configuration>
              <source>1.6</source>
              <target>1.6</target>
            </configuration>
          </plugin>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.12</version>
            <configuration>
              <argLine>-Xmx1300M</argLine>
            </configuration>
          </plugin>
        </plugins>
      </build>
      <dependencies>
        <dependency>
          <groupId>org.bouncycastle</groupId>
          <artifactId>bcprov-jdk15on</artifactId>
          <version>1.47</version>
        </dependency>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.10</version>
          <scope>test</scope>
        </dependency>
      </dependencies>
    </project>
    
  3. Erzeugen Sie im Verzeichnis src\main\java\de\meinefirma\meinprojekt\crypto die Klasse: CryptoWinZipAES.java

    package de.meinefirma.meinprojekt.crypto;
    
    import java.io.*;
    import java.util.List;
    import java.util.zip.DataFormatException;
    import de.idyl.winzipaes.*;
    import de.idyl.winzipaes.impl.*;
    
    /**
     * @see http://code.google.com/p/winzipaes
     * @see http://www.bouncycastle.org
     * @see http://www.winzip.com/aes_info.htm
    */
    public class CryptoWinZipAES
    {
       public static void main( String[] args ) throws IOException, DataFormatException
       {
          if( args.length == 4 ) {
             if( args[0].toLowerCase().startsWith( "e" ) || args[0].toLowerCase().startsWith( "z" ) ) {
                zipAndEncrypt( args[1], args[2], args[3] );
                return;
             } else if( args[0].toLowerCase().startsWith( "d" ) || args[0].toLowerCase().startsWith( "u" ) ) {
                unzipAndDecrypt( args[1], args[2], args[3] );
                return;
             }
          }
          System.out.println( "Fehler: Es werden vier Parameter benoetigt:\n" +
                "Zum Zippen und Verschluesseln:\n" +
                "  zip SrcFile DstZipFile Passwort\n" +
                "Zum Unzippen und Entschluesseln:\n" +
                "  unzip SrcZipFile DstDir Passwort\n" );
       }
    
       public static void zipAndEncrypt( String srcFile, String dstZipFile, String password ) throws IOException
       {
          AesZipFileEncrypter.zipAndEncrypt( new File( srcFile ), new File( dstZipFile ), password, new AESEncrypterBC() );
       }
    
       public static void zipAndEncrypt( List<String> srcFiles, String dstZipFile, String password ) throws IOException
       {
          AesZipFileEncrypter aesZip = new AesZipFileEncrypter( dstZipFile, new AESEncrypterBC() );
          for( String srcFile : srcFiles ) {
             aesZip.add( new File( srcFile ), password );
          }
          aesZip.close();
       }
    
       public static void unzipAndDecrypt( String srcZipFile, String dstDir, String password ) throws IOException, DataFormatException
       {
          String dir = ( dstDir == null ) ? "" : ( dstDir.endsWith( "/" ) || dstDir.endsWith( "\\" ) ) ? dstDir : (dstDir + "/");
          AesZipFileDecrypter decrypter = new AesZipFileDecrypter( new File( srcZipFile ), new AESDecrypterBC() );
          List<ExtZipEntry> zipEntries = decrypter.getEntryList();
          for( ExtZipEntry zipEntry : zipEntries ) {
             File outFile = new File( dir + zipEntry.getName() );
             String parentPath = outFile.getParent();
             if( parentPath != null && parentPath.trim().length() > 0 ) {
                File f = new File( parentPath );
                if( !f.exists() ) { f.mkdirs(); }
             }
             decrypter.extractEntry( zipEntry, outFile, password );
          }
       }
    }
    
  4. Erzeugen Sie im Verzeichnis src\test\java\de\meinefirma\meinprojekt\crypto den JUnit-Test: CryptoWinZipAESTest.java

    package de.meinefirma.meinprojekt.crypto;
    
    import java.io.*;
    import java.util.*;
    import java.util.zip.DataFormatException;
    import org.junit.*;
    
    public class CryptoWinZipAESTest
    {
       @Test
       public void testWinZipAES() throws IOException, DataFormatException
       {
          String srcFile  = "target/MeineDatei.txt";
          String zipFile  = "target/MeineVerschluesselteZipDatei.zip";
          String dstDir   = "target/testergebnis";
          String dstFile  = dstDir + File.separator + srcFile;
          String password = "geheim";
          String text     = "Blablupp \u00E4\u00F6\u00FC\u00DF\u20AC"; // Umlaute und Eurozeichen
          String charEnc  = "UTF-8";
    
          BufferedWriter out = new BufferedWriter( new OutputStreamWriter( new FileOutputStream( srcFile ), charEnc ) );
          try { out.write( text ); } finally { out.close(); }
    
          CryptoWinZipAES.zipAndEncrypt( srcFile, zipFile, password );
          Assert.assertTrue( new File( zipFile ).exists() );
    
          CryptoWinZipAES.unzipAndDecrypt( zipFile, dstDir, password );
          Assert.assertTrue( new File( dstFile ).exists() );
    
          List<String>   ss = new ArrayList<String>();
          BufferedReader in = new BufferedReader( new InputStreamReader( new FileInputStream( dstFile ), charEnc ) );
          try {
             String line;
             while( (line = in.readLine()) != null ) {
                ss.add( line );
             }
          } finally {
             in.close();
          }
          Assert.assertEquals( 1, ss.size() );
          Assert.assertEquals( text, ss.get( 0 ) );
       }
    }
    
  5. Die Projektstruktur sieht jetzt so aus:

    cd \MeinWorkspace\CryptoWinZipAES

    tree /F

    [\MeinWorkspace\CryptoWinZipAES]
     |- [src]
     |   |- [main]
     |   |   '- [java]
     |   |       '- [de]
     |   |           |- [idyl]
     |   |           |   '- [winzipaes]
     |   |           |       |- [impl]
     |   |           |       |   '- ...
     |   |           |       |- AesZipFileDecrypter.java
     |   |           |       '- AesZipFileEncrypter.java
     |   |           '- [meinefirma]
     |   |               '- [meinprojekt]
     |   |                   '- [crypto]
     |   |                       '- CryptoWinZipAES.java
     |   '- [test]
     |       '- [java]
     |           '- [de]
     |               '- [meinefirma]
     |                   '- [meinprojekt]
     |                       '- [crypto]
     |                           '- CryptoWinZipAESTest.java
     |- pom.xml
     '- winzipaes_src_20110911.zip
    
  6. Führen Sie den JUnit-Test aus:

    mvn clean test

    Der Test läuft fehlerfrei durch und im target-Verzeichnis entstehen folgende Dateien:

    [\MeinWorkspace\CryptoWinZipAES]
     |- [...]
     |   '- ...
     '- [target]
         |- [...]
         |   '- ...
         |- [testergebnis]
         |   '- [target]
         |       '- MeineDatei.txt  . . . . . . . . [Ergebnis der Entschlüsselung]
         |- MeineDatei.txt  . . . . . . . . . . . . [ursprüngliche Originaldatei]
         '- MeineVerschluesselteZipDatei.zip  . . . [verschlüsselte Zip-Datei]
    
  7. Die ursprüngliche Originaldatei und das Ergebnis der Entschlüsselung stimmen überein:

    notepad target\MeineDatei.txt

    notepad target\testergebnis\target\MeineDatei.txt

  8. Sie können die verschlüsselte Datei auch mit WinZip entpacken. Klicken Sie entweder mit der rechten Maustaste auf MeineVerschluesselteZipDatei.zip oder führen Sie aus:

    C:\Programme\WinZip\WinZip32.exe target\MeineVerschluesselteZipDatei.zip

    WinZip fragt dann nach dem Passwort.

  9. Auch diverse andere Programme unterstützen diese Art der Verschlüsselung, zum Beispiel 7-Zip. Wenn Sie das Passwort kennen, erfolgt eine Entschlüsselung entweder per rechter Maustaste oder mit dem Kommando:

    C:\Programme\7-Zip\7z.exe x -oZielverzeichnis -pgeheim target\MeineVerschluesselteZipDatei.zip



Bemerkungen zur Performance und Verarbeitung großer Dateien

Buffering für SignedFileProcessor vom Bouncy Castle Crypto API

SignedFileProcessor.java aus bcpg-jdk15on-147.zip arbeitet bei großen Dateien extrem langsam. Signieren und Verifizieren können in der Summe je nach PC bei einer 1-GByte-XML-Datei über 1 Stunde dauern.

Durch folgende einfache Maßnahme erreichen Sie eine deutliche Verbesserung: Kopieren Sie SignedFileProcessor.java nach SignedFileProcessorBuffered.java. Ersetzen Sie in SignedFileProcessorBuffered.java überall:

FileInputStream ... = new FileInputStream( ... )
durch
InputStream ... = new BufferedInputStream( new FileInputStream( ... ) )

und

FileOutputStream ... = new FileOutputStream( ... )
durch
OutputStream ... = new BufferedOutputStream( new FileOutputStream( ... ) )

Ergänzen Sie entsprechende "import java.io.Buffered..."-Anweisungen und ersetzen Sie "class SignedFileProcessor" durch "class SignedFileProcessorBuffered".

Zip-Komprimierung für SignedFileProcessor vom Bouncy Castle Crypto API
Selbst die gebufferte Version SignedFileProcessorBuffered ist immer noch recht langsam bei großen Dateien, deshalb kann es bei unkomprimierten Dateien empfehlenswert sein, vorher eine Zip-Komprimierung durchzuführen (z.B. mit jar cvfM):

jar cvfM MeineGrosseDatei.zip MeineGrosseDatei

... signieren/verschlüsseln mit MeineGrosseDatei.zip statt MeineGrosseDatei ...

... beim Empfänger nach dem Entschlüsseln zuletzt:

jar xf MeineGrosseDatei.zip

KeyBasedFileProcessor vom Bouncy Castle Crypto API

Entschlüsseln mit "-d" verbraucht wenig Heap-Speicher. Aber Verschlüsseln mit "-e" benötigt bei großen Dateien viel Heap-Speicher, dessen Limit Sie mit "java -Xmx..." erweitern müssen. Dabei gibt es eine Besonderheit: Nicht nur bei einem zu niedrigen, sondern auch bei einem zu hohen Heap-Speicher-Limit kann KeyBasedFileProcessor eine OutOfMemoryError-Exception werfen. Letzteres passiert reproduzierbar bei einer unkomprimierten 1-GByte-XML-Datei mit folgender Kommandozeile (BC 1.46, JDK 1.6.0_26, Windows XP 32 Bit):

java -Xmx1400M -cp .;* KeyBasedFileProcessor -e Meine-1GByte-Datei.xml pub.asc

Mit "java -Xmx1300M ..." funktioniert alles fehlerfrei.

WinZipAES
WinZipAES ist zumindest in der Version "winzipaes_src_20110608.zip" kaum für große Dateien geeignet:
Unter 32-bit-Windows mit "java -Xmx1300M ..." wirft AesZipFileDecrypter.extractEntry() eine OutOfMemoryError-Exception.
Unter 64-bit-Windows kann die OutOfMemoryError-Exception nur vermieden werden, wenn mit "java -Xmx3500M ..." unverhältnismäßig viel Heap-Speicher angeboten wird.
Grober Performancevergleich

Der folgende Performancevergleich soll nur als erster Anhaltspunkt dienen. Die Messwerte variieren stark, abhängig von PC-Performance, Dateiinhalt, Algorithmus, Schlüssellänge etc. Bitte beachten Sie, dass der Vergleich insbesondere deshalb unfair ist, weil meistens die Defaulteinstellungen übernommen wurden, die bei unterschiedlichen Tools zu unterschiedlichen Algorithmen und Schlüssellängen führen.
Auffällig ist die sehr schlechte Performance der Signierung beim Bouncy Castle Crypto API.

Programm, Algorithmus, Kommandozeile i7-920, Windows XP, 32 Bit
1 GByte XML
Verschlüsseln   Entschlüsseln 
i7-950, Windows 7, 64 Bit
1 GByte XML
 Verschlüsseln   Entschlüsseln
Keine Verschlüsselung, nur Zip-Komprimierung mit jar.exe:
jar cvfM x.zip x
jar xf x.zip
34 s12 s26 s6 s
GnuPG, symmetrisch:
gpg2 --cipher-algo AES --s2k-digest-algo SHA1 -c ...
43 s71 s37 s63 s
GnuPG, asymmetrisch/hybrid:
gpg2 -e ...
42 s73 s36 s65 s
GnuPG, asymmetrisch/hybrid, mit signieren, 1 Kommando:
gpg2 -se ...
99 s72 s86 s63 s
GnuPG, asymmetrisch/hybrid, mit signieren, 2 Kommandos:
gpg2 -s ...
gpg2 -e ...
71 s40 s61 s35 s
Bouncy Castle, symmetrisch, ohne Integrity Check:
java -Xmx1300M PBEFileProcessor -e ...
38 s27 s29 s8 s
Bouncy Castle, symmetrisch, mit Integrity Check:
java -Xmx1300M PBEFileProcessor -e -i ...
40 s29 s30 s10 s
Bouncy Castle, asymmetr./hybrid, ohne Integrity Check:
java -Xmx1300M KeyBasedFileProcessor -e ...
35 s27 s29 s8 s
Bouncy Castle, asymmetr./hybrid, mit Integrity Check:
java -Xmx1300M KeyBasedFileProcessor -e -i ...
40 s30 s30 s10 s
Bouncy Castle, asymmetr./hybrid, mit Integr. Check, LargeFileProc.:
java -Xmx1300M KeyBasedLargeFileProcessor -e -i ...
39 s21 s28 s10 s
Bouncy Castle, asymmetr./hybrid, signieren, vorher zippen, Buffered:
jar  cvfM ...
java SignedFileProcessorBuffered -s ...
java -Xmx1300M KeyBasedFileProcessor -e ...
jar  xf ...
154 s103 s84 s40 s
Bouncy Castle, asymmetr./hybrid, signieren, ohne Zip, Buffered:
java SignedFileProcessorBuffered -s ...
java -Xmx1300M KeyBasedFileProcessor -e ...
840 s700 s377 s252 s
Bouncy Castle, asymmetr./hybrid, signieren, ohne Zip, ohne Buff.:
java SignedFileProcessor -s ...
java -Xmx1300M KeyBasedFileProcessor -e ...
1.800 s2.600 s1.700 s1.970 s
Stream-Util für Bouncy-Castle, asymmetr./hybrid, mit Integr. Check:
java -Xmx1300M OpenPgpBouncyCastleStreamUtilMain -e ...
40 s30 s30 s10 s
CryptoRsaAes, vorher zippen:
jar  cvfM ...
java CryptoRsaAes -e ...
jar  xf ...
63 s42 s54 s34 s
CryptoSimple, vorher zippen:
jar  cvfM ...
java CryptoSimple -e ... AES ...
jar  xf ...
37 s18 s28 s9 s
CryptoWinZipAES:
java -Xmx3500M CryptoWinZipAES ...
OutOfMemoryError:
Java heap space
83 s31 s


Erläuterungen:

Erläuterungen zu den verwendeten Programmen und Kommandozeilen finden Sie unter GnuPG, Bouncy Castle, Kooperation GnuPG und BC, CryptoRsaAes, CryptoSimple und CryptoWinZipAES.

"Buffered" bedeutet: Statt der Original-SignedFileProcessor.java-Klasse aus bcpg-jdk15on-147.zip wird die oben beschriebene SignedFileProcessorBuffered.java verwendet.

"vorher zippen" bedeutet: Der Versender zip-komprimiert vor der Signierung/Verschlüsselung und der Empfänger entkomprimiert nach dem Entschlüsseln/Verifizieren, so wie oben beschrieben. Die angegebenen Zeitmesswerte sind inklusive der Zip- und Unzip-Zeiten.

"Stream-Util für Bouncy-Castle": Das CryptoOpenPgpBouncyCastleStream-Projekt mit der OpenPgpBouncyCastleStreamUtil-Klasse finden Sie in Crypto.zip. Darin finden Sie auch ein Beispiel, wie Streams vom FTP-Server entschlüsselt und Streams zum FTP-Server verschlüsselt werden können (in OpenPgpBouncyCastleStreamUtilFtpTest.java).





Weitere Themen: andere TechDocs | Kryptowährungen | Kryptographie
© 2011-2012 Torsten Horn, Aachen