2013-10-04 13 views
6

Ich versuche, eine PGP-Nachricht mit den Java-BouncyCastle-Bibliotheken zu entschlüsseln und zu verifizieren, stoße aber auf Probleme und beklagte mich über vorzeitige Beendigungen von PartialInputStream.Bouncycastle PGP entschlüsseln und verifizieren

Ich weiß, die Verschlüsselung funktioniert gut, weil ich Nachrichten entschlüsseln und verifizieren kann, die mit der Verschlüsselungsfunktion mit gpg in der Befehlszeile erstellt wurden.

Hier ist der Code:

public static void signEncryptMessage(InputStream in, OutputStream out, PGPPublicKey publicKey, PGPPrivateKey secretKey, SecureRandom rand) throws Exception { 
     out = new ArmoredOutputStream(out); 

     PGPEncryptedDataGenerator encryptedDataGenerator = new PGPEncryptedDataGenerator(new BcPGPDataEncryptorBuilder(PGPEncryptedData.AES_256).setWithIntegrityPacket(true).setSecureRandom(rand)); 
     encryptedDataGenerator.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(publicKey)); 

     OutputStream compressedOut = new PGPCompressedDataGenerator(PGPCompressedData.ZIP).open(encryptedDataGenerator.open(out, 4096), new byte[4096]); 

     PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(new BcPGPContentSignerBuilder(publicKey.getAlgorithm(), HashAlgorithmTags.SHA512)); 
     signatureGenerator.init(PGPSignature.BINARY_DOCUMENT, secretKey); 
     signatureGenerator.generateOnePassVersion(true).encode(compressedOut); 

     OutputStream finalOut = new PGPLiteralDataGenerator().open(compressedOut, PGPLiteralData.BINARY, "", new Date(), new byte[4096]); 

     byte[] buf = new byte[4096]; 
     int len; 
     while ((len = in.read(buf)) > 0) { 
      finalOut.write(buf, 0, len); 
      signatureGenerator.update(buf, 0, len); 
     } 

     finalOut.close(); 
     in.close(); 
     signatureGenerator.generate().encode(compressedOut); 
     compressedOut.close(); 
     encryptedDataGenerator.close(); 
     out.close(); 
    } 

    public static void decryptVerifyMessage(InputStream in, OutputStream out, PGPPrivateKey secretKey, PGPPublicKey publicKey) throws Exception { 
     in = new ArmoredInputStream(in); 

     PGPObjectFactory pgpF = new PGPObjectFactory(in); 
     PGPEncryptedDataList enc = (PGPEncryptedDataList) pgpF.nextObject(); 

     PGPObjectFactory plainFact = new PGPObjectFactory(((PGPPublicKeyEncryptedData) enc.getEncryptedDataObjects().next()).getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("BC").build(secretKey))); 

     Object message = null; 

     PGPOnePassSignatureList onePassSignatureList = null; 
     PGPSignatureList signatureList = null; 
     PGPCompressedData compressedData = null; 

     message = plainFact.nextObject(); 
     ByteArrayOutputStream actualOutput = new ByteArrayOutputStream(); 

     while (message != null) { 
      System.out.println(message.toString()); 
      if (message instanceof PGPCompressedData) { 
       compressedData = (PGPCompressedData) message; 
       plainFact = new PGPObjectFactory(compressedData.getDataStream()); 
       message = plainFact.nextObject(); 
       System.out.println(message.toString()); 
      } 

      if (message instanceof PGPLiteralData) { 
       Streams.pipeAll(((PGPLiteralData) message).getInputStream(), actualOutput); 
      } else if (message instanceof PGPOnePassSignatureList) { 
       onePassSignatureList = (PGPOnePassSignatureList) message; 
      } else if (message instanceof PGPSignatureList) { 
       signatureList = (PGPSignatureList) message; 
      } else { 
       throw new PGPException("message unknown message type."); 
      } 
      message = plainFact.nextObject(); 
     } 
     actualOutput.close(); 
     byte[] output = actualOutput.toByteArray(); 
     if (onePassSignatureList == null || signatureList == null) { 
      throw new PGPException("Poor PGP. Signatures not found."); 
     } else { 

      for (int i = 0; i < onePassSignatureList.size(); i++) { 
       PGPOnePassSignature ops = onePassSignatureList.get(0); 
       System.out.println("verifier : " + ops.getKeyID()); 
       if (publicKey != null) { 
        ops.init(new JcaPGPContentVerifierBuilderProvider().setProvider("BC"), publicKey); 
        ops.update(output); 
        PGPSignature signature = signatureList.get(i); 
        if (ops.verify(signature)) { 
         Iterator<?> userIds = publicKey.getUserIDs(); 
         while (userIds.hasNext()) { 
          String userId = (String) userIds.next(); 
          System.out.println("Signed by " + userId); 
         } 
         System.out.println("Signature verified"); 
        } else { 
         throw new SignatureException("Signature verification failed"); 
        } 
       } 
      } 

     } 

     out.write(output); 
     out.flush(); 
     out.close(); 
    } 

    public static void main(String args[]) { 
     Security.insertProviderAt(new BouncyCastleProvider(), 0); 
     byte inBytes[] = "The quick brown fox jumps over the lazy dog.".getBytes(); 

     try { 
      SecureRandom rand = new SecureRandom(); 

      RSAKeyPairGenerator kpg = new RSAKeyPairGenerator(); 
      kpg.init(new RSAKeyGenerationParameters(BigInteger.valueOf(0x10001), rand, 1024, 90)); 

      BcPGPKeyPair sender = new BcPGPKeyPair(PGPPublicKey.RSA_GENERAL, kpg.generateKeyPair(), new Date()); 
      BcPGPKeyPair recip = new BcPGPKeyPair(PGPPublicKey.RSA_GENERAL, kpg.generateKeyPair(), new Date()); 

      ByteArrayOutputStream sendMessage = new ByteArrayOutputStream(); 
      ByteArrayOutputStream recvMessage = new ByteArrayOutputStream(); 
      signEncryptMessage(new ByteArrayInputStream(inBytes), sendMessage, recip.getPublicKey(), sender.getPrivateKey(), rand); 

      System.out.println(sendMessage.toString()); 

      decryptVerifyMessage(new ByteArrayInputStream(sendMessage.toByteArray()), recvMessage, recip.getPrivateKey(), sender.getPublicKey()); 

      System.out.println(recvMessage.toString()); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

Nach einigen Durchläufen von message = plainFact.nextObject(); die Ausnahme ausgelöst wird:

-----BEGIN PGP MESSAGE----- 
Version: BCPG v1.49 

hIwDbgERMnl/xpUBA/98O/by9Ib6/nzXiYWuwT2CYulTqzcY07iuHKB4KQc6m+H1 
ZBVAx+HozgxQXQdQcBTcp+YS7Xn3tsReiH28Z9805f65tmASoqrzdf35qiVgFhfA 
CbCfIq7cqC4rKut3Y8pNOs1mmhpeVNa+AqTZ1r46uyuloBTllI8OWzWoxjTcZdLP 
aQHe2BQnfYk+dFgXZ2LMBMtL9mcsEqRLWIdisJQ4gppyIbQNNE7q5gV1Es63yVoM 
3dpfYHxlnIZASuynSZyGorHpYMV6tWNwSRQ9Ziwaw4DwvQGyAHpb1O/tLqrfjLqN 
5dj5qNY6nElT1EM94Dd4FOBzI6x6JkfuCH3/Jp8lCA/p8K7jmYu9Xvdld8BgHmRF 
ymasPf1JC4xYFa9YQVnn4fK2l//2iVcVayv0On32kxD9XfkPUysYVH38glPaHb48 
qWk9i/x0Y3mmCy1RVAGWqimR5DEhZPubJ+Kjk3UsB1m90Pm/6a+/ZfpAEHcxshdX 
JeVBr7aQIX3PQIUl+ZPQsgAGEmo0abQVufuKfkfjX0Gh 
=ApMf 
-----END PGP MESSAGE----- 

[email protected] 
[email protected] 
[email protected] 
java.io.EOFException: premature end of stream in PartialInputStream 
    at org.bouncycastle.bcpg.BCPGInputStream$PartialInputStream.read(Unknown Source) 
    at org.bouncycastle.bcpg.BCPGInputStream.read(Unknown Source) 
    at java.io.InputStream.read(InputStream.java:101) 
    at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:103) 
    at javax.crypto.CipherInputStream.read(CipherInputStream.java:177) 
    at org.bouncycastle.bcpg.BCPGInputStream.read(Unknown Source) 
    at org.bouncycastle.openpgp.PGPEncryptedData$TruncatedStream.read(Unknown Source) 
    at java.io.InputStream.read(InputStream.java:170) 
    at org.bouncycastle.util.io.TeeInputStream.read(Unknown Source) 
    at org.bouncycastle.bcpg.BCPGInputStream.read(Unknown Source) 
    at org.bouncycastle.bcpg.BCPGInputStream$PartialInputStream.read(Unknown Source) 
    at org.bouncycastle.bcpg.BCPGInputStream.read(Unknown Source) 
    at org.bouncycastle.openpgp.PGPCompressedData$1.fill(Unknown Source) 
    at java.util.zip.InflaterInputStream.read(InflaterInputStream.java:158) 
    at org.bouncycastle.bcpg.BCPGInputStream.read(Unknown Source) 
    at org.bouncycastle.bcpg.BCPGInputStream$PartialInputStream.read(Unknown Source) 
    at org.bouncycastle.bcpg.BCPGInputStream.read(Unknown Source) 
    at org.bouncycastle.util.io.Streams.readFully(Unknown Source) 
    at org.bouncycastle.bcpg.BCPGInputStream.readFully(Unknown Source) 
    at org.bouncycastle.bcpg.BCPGInputStream.readFully(Unknown Source) 
    at org.bouncycastle.bcpg.MPInteger.<init>(Unknown Source) 
    at org.bouncycastle.bcpg.SignaturePacket.<init>(Unknown Source) 
    at org.bouncycastle.bcpg.BCPGInputStream.readPacket(Unknown Source) 
    at org.bouncycastle.openpgp.PGPSignature.<init>(Unknown Source) 
    at org.bouncycastle.openpgp.PGPObjectFactory.nextObject(Unknown Source) 
    at main.decryptVerifyMessage(main.java:113) 
    at main.main(main.java:167) 

Irgendwelche Ideen?

Seitennotiz, kam dieser Entschlüsselungscode von How to decrypt a signed pgp encrypted file?, leicht geändert, um zu passen: Nachrichten kommen nur von dieser Verschlüsselungsmethode, und die Behandlung der Schlüssel direkt anstelle von Schlüsselströmen.

Prost

Ramo

Antwort

8

Ich versuchte vor kurzem die gleiche Art der Sache zu tun, und diese Methode auf Code zusammengestellt, die sich ich in den BouncyCastle Beispiele und Tutorials fand ich im Internet gefunden. Für meinen Zweck hat mein Code ein Singleton-Kryptoobjekt mit einem öffentlichen/privaten Schlüsselpaar. Im Beispielcode könnten Sie

mit Ihrem geheimen Schlüssel ersetzen. Ich habe diese Methode mit einem langlebigen Prozess getestet, der mehrere Dutzend von & signieren/entschlüsseln & Verify-Aktionen und nicht die Ausnahme bekommen, die Sie sehen.

public static void decryptAndVerify(InputStream in, OutputStream fOut, InputStream publicKeyIn) throws IOException, SignatureException, PGPException { 
    in = PGPUtil.getDecoderStream(in); 

    PGPObjectFactory pgpF = new PGPObjectFactory(in); 
    PGPEncryptedDataList enc; 

    Object o = pgpF.nextObject(); 
    // 
    // the first object might be a PGP marker packet. 
    // 
    if (o instanceof PGPEncryptedDataList) { 
     enc = (PGPEncryptedDataList) o; 
    } else { 
     enc = (PGPEncryptedDataList) pgpF.nextObject(); 
    } 

    // 
    // find the secret key 
    // 
    Iterator<PGPPublicKeyEncryptedData> it = enc.getEncryptedDataObjects(); 
    PGPPrivateKey sKey = null; 
    PGPPublicKeyEncryptedData pbe = null; 
    while (sKey == null && it.hasNext()) { 
     pbe = it.next(); 
     PBESecretKeyDecryptor decryptor = new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(INSTANCE._secretKeyPass.toCharArray()); 
     PGPSecretKey psKey = INSTANCE._secretKeyRingCollection.getSecretKey(pbe.getKeyID()); 
     if (psKey != null) { 
      sKey = psKey.extractPrivateKey(decryptor); 
     } 
    } 
    if (sKey == null) { 
     throw new IllegalArgumentException("Unable to find secret key to decrypt the message"); 
    } 

    InputStream clear = pbe.getDataStream(new BcPublicKeyDataDecryptorFactory(sKey)); 

    PGPObjectFactory plainFact = new PGPObjectFactory(clear); 

    Object message; 

    PGPOnePassSignatureList onePassSignatureList = null; 
    PGPSignatureList signatureList = null; 
    PGPCompressedData compressedData; 

    message = plainFact.nextObject(); 
    ByteArrayOutputStream actualOutput = new ByteArrayOutputStream(); 

    while (message != null) { 
     __l.trace(message.toString()); 
     if (message instanceof PGPCompressedData) { 
      compressedData = (PGPCompressedData) message; 
      plainFact = new PGPObjectFactory(compressedData.getDataStream()); 
      message = plainFact.nextObject(); 
     } 

     if (message instanceof PGPLiteralData) { 
      // have to read it and keep it somewhere. 
      Streams.pipeAll(((PGPLiteralData) message).getInputStream(), actualOutput); 
     } else if (message instanceof PGPOnePassSignatureList) { 
      onePassSignatureList = (PGPOnePassSignatureList) message; 
     } else if (message instanceof PGPSignatureList) { 
      signatureList = (PGPSignatureList) message; 
     } else { 
      throw new PGPException("message unknown message type."); 
     } 
     message = plainFact.nextObject(); 
    } 
    actualOutput.close(); 
    PGPPublicKey publicKey = null; 
    byte[] output = actualOutput.toByteArray(); 
    if (onePassSignatureList == null || signatureList == null) { 
     throw new PGPException("Poor PGP. Signatures not found."); 
    } else { 

     for (int i = 0; i < onePassSignatureList.size(); i++) { 
      PGPOnePassSignature ops = onePassSignatureList.get(0); 
      __l.trace("verifier : " + ops.getKeyID()); 
      PGPPublicKeyRingCollection pgpRing = new PGPPublicKeyRingCollection(
        PGPUtil.getDecoderStream(publicKeyIn)); 
      publicKey = pgpRing.getPublicKey(ops.getKeyID()); 
      if (publicKey != null) { 
       ops.init(new JcaPGPContentVerifierBuilderProvider().setProvider("BC"), publicKey); 
       ops.update(output); 
       PGPSignature signature = signatureList.get(i); 
       if (ops.verify(signature)) { 
        Iterator<?> userIds = publicKey.getUserIDs(); 
        while (userIds.hasNext()) { 
         String userId = (String) userIds.next(); 
         __l.trace(String.format("Signed by {%s}", userId)); 
        } 
        __l.trace("Signature verified"); 
       } else { 
        throw new SignatureException("Signature verification failed"); 
       } 
      } 
     } 

    } 

    if (pbe.isIntegrityProtected() && !pbe.verify()) { 
     throw new PGPException("Data is integrity protected but integrity is lost."); 
    } else if (publicKey == null) { 
     throw new SignatureException("Signature not found"); 
    } else { 
     fOut.write(output); 
     fOut.flush(); 
     fOut.close(); 
    } 
} 
+4

Fun Fact: Portieren von Code zu C# gearbeitet tatsächlich besser als jede der tatsächlichen C# Beispiele dafür Dies. –

1

Sie rufen:

encryptedDataGenerator.open(out, 4096) 

wo Sie wahrscheinlich gemeint:

encryptedDataGenerator.open(out, new byte[4096]) 

Die erste Version mit einer Größe zu öffnen geben (was falsch ist), die zweite Version geben ein Byte-Puffer.

(Ich weiß, das ist alt, aber hierher gekommen, weil ich das gleiche Problem mit einigen Beispiel-Code hatte und so könnten andere)

3

Hüpfburg Immer entlang zu spielen, ist nicht immer einfach. Code-Snipets von Stackoverflow machen es funktionieren nur so, aber sie sind meist geheimnisvolle Teile des Codes, die keiner der Benutzer wirklich verstehen.

Das Problem dabei ist: in einem Produktionssystem copy'n'paste Schnipsel schnell „no go“ und Flächen „nicht berührt“ werden.

Executables Beschuss aus können einige gravierende Auswirkungen auf die Sicherheit haben, am allerwenigsten Kommandozeilen-Parameter ist der Umgang mit (reden über Dateinamen mit Leerzeichen ... wie kann ich wissen? Fragen Sie nicht, ...)

I hatte alle diese (und mehr ..) Probleme, und nach ein paar Yaks Rasur schrieb ich eine Bibliothek, um mit PGP mit Bouncycastle umzugehen.

Decrypting funktioniert wie folgt:

final InputStream plaintextStream = BouncyGPG 
       .decryptAndVerifyStream() 
       .withConfig(keyringConfig) 
       .andRequireSignatureFromAllKeys("[email protected]") 
       .fromEncryptedInputStream(cipherTextStream) 

Die Bibliothek kann auf https://github.com/neuhalje/bouncy-gpg finden:

// in build.gradle add a dependency to bouncy castle and bouncy-gpg 
// ... 
dependencies { 
    compile 'org.bouncycastle:bcprov-jdk15on:1.56' 
    compile 'org.bouncycastle:bcpg-jdk15on:1.56' 
    // ... 
    compile 'name.neuhalfen.projects.crypto.bouncycastle.openpgp:bouncy-gpg:2.+' 
+0

Hallo Jens, ich benutze deine Bibliothek und es ist wirklich gut. Ich habe dieses Problem obwohl, wo ich die Datei verschlüsselt und mit einem Benutzer [email protected] unterzeichnet und dann, als ich versuchte, mit Open PGP von Mac zu entschlüsseln, heißt es, dass die Überprüfung für [email protected] fehlschlug, obwohl die Datei entschlüsselt wurde. Kannst du helfen, plz –

+0

Bitte erstellen Sie ein Problem in der Github Bugtracker und verknüpfen Sie es hier (so dass wir das Problem im Tracker lösen und die Antwort hier aktualisieren können) – Jens

+0

Nachdem ich in den letzten Tagen mit Bouncy Castle gekämpft habe, kann ich Überprüfen Sie, ob diese Bibliothek dope ist. –

Verwandte Themen