2013-10-04 9 views
6

Java BouncyCastle 라이브러리를 사용하여 PGP 메시지의 암호를 해독하고 확인하려고하지만 PartialInputStream의 조기 종료에 대해 불만을 제기하면서 문제가 발생합니다.Bouncycastle PGP 암호 해독 및 확인

명령 줄에서 gpg를 사용하여 암호화 된 함수로 만든 메시지를 해독하고 확인할 수 있기 때문에 암호화가 제대로 작동한다는 것을 알고 있습니다. 예외가 슬로우됩니다 message = plainFact.nextObject();의 몇 가지를 실행 한 후에는

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(); 
     } 
    } 

:

-----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) 

모든 아이디어를 여기

코드인가?

사이드 노트,이 암호 해독 코드는 How to decrypt a signed pgp encrypted file?에서 약간 수정되었습니다. 메시지는 해당 암호화 방법으로 만 전달되며 키 스트림 대신 직접 키를 처리합니다.

건배

라모스

답변

8

는 최근 물건의 같은 종류의 일을 함께 나는 Bouncycastle 예에 내가 웹에서 발견 자습서에서 찾을 코드를 기반으로이 방법을 넣어하려고했다. 내 목적을 위해, 내 코드에는 공개/개인 키 쌍이있는 싱글 톤 암호화 객체가 있습니다. 예제 코드에서는

INSTANCE._secretKeyRingCollection.getSecretKey(pbe.getKeyID()); 

을 비밀 키로 바꿀 수 있습니다. 수십 개의 암호화를 & sign/decrypt & 작업을 검증하고보고있는 예외를 얻지 못했던 수명이 긴 프로세스로이 방법을 테스트했습니다.

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

재미있는 사실 : 실제로 수행의 실제 C#을 예로들보다 더 나은 일을 C#이 코드를 포팅 이. –

1

당신은 요구하고있다 : 당신은 아마 의미

encryptedDataGenerator.open(out, 4096) 

:

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

는 첫 번째 버전이 (잘못이다) 열 크기를주고있다가, 두 번째 버전은주고있다 byte 버퍼 탄력 성 연주 살펴

(나는 다른 사람이 오래 알고 있지만, 나는 몇 가지 예제 코드와 같은 문제가 있었기 때문에 여기 온 등 수도)

3

항상 쉬운 일이 아닙니다. Stackoverflow의 코드 스 니펫을 사용하면 이 제대로 작동하므로이지만 사용자가 실제로 이해하지 못하는 대부분의 코드 조각입니다. 이와

문제는 : 생산 시스템 copy'n'paste 조각에서 빠르게 "더 가서"와 "만지지 마세요"분야가 없습니다. 모든 이상이 명령 줄 매개 변수를 처리하는 몇 가지 심각한 보안 문제, 할 수 있습니다 실행을 포격

(어떻게 알 수 있습니까 ... 공백이있는 파일 이름에 대해 이야기를? 묻지 마세요 ...)

I (그리고 더 ..) 문제를 모두 가지고 있었고 약간의 야크 면도 후에 Bouncycastle과 PGP를 처리하기위한 라이브러리를 썼습니다.이 같은

암호 해독 작품 :

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

도서관은 https://github.com/neuhalje/bouncy-gpg에서 찾을 수 있습니다

// 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

안녕하세요, Jens, 저는 귀하의 도서관을 사용하고 있으며 정말 좋습니다. 나는이 파일을 암호화하고 [email protected]이라는 사용자와 서명 한 다음 Mac의 Open PGP를 사용하여 암호 해독을 시도 할 때 파일이 해독되었지만 [email protected]에 대한 인증에 실패했다고 말합니다. plz를 도울 수 있습니까 –

+0

Github bugtracker에서 문제를 생성하고 여기에 연결하십시오 (트래커에서 문제를 해결하고 이후에 답변을 업데이트 할 수 있도록) – Jens

+0

지난 2 일 동안 Bouncy Castle과 싸웠다면 이 라이브러리가 마약인지 확인하십시오. –