Saltar al contenido

Hacer que el descifrado de GPG funcione en Java (Bouncy Castle)

Te sugerimos que pruebes esta respuesta en un entorno controlado antes de pasarlo a producción, saludos.

Solución:

Si alguien está interesado en saber cómo cifrar y descifrar archivos gpg utilizando la biblioteca openPGP del castillo hinchable, consulte el siguiente código java:

Los siguientes son los 4 métodos que necesitará:

El siguiente método leerá e importará su secreto key del archivo .asc:

public static PGPSecretKey readSecretKeyFromCol(InputStream in, long keyId) throws IOException, PGPException 
    in = PGPUtil.getDecoderStream(in);
    PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(in, new BcKeyFingerprintCalculator());

    PGPSecretKey key = pgpSec.getSecretKey(keyId);

    if (key == null) 
        throw new IllegalArgumentException("Can't find encryption key in key ring.");
    
    return key;

El siguiente método leerá e importará su público key del archivo .asc:

@SuppressWarnings("rawtypes")
    public static PGPPublicKey readPublicKeyFromCol(InputStream in) throws IOException, PGPException 
        in = PGPUtil.getDecoderStream(in);
        PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(in, new BcKeyFingerprintCalculator());
        PGPPublicKey key = null;
        Iterator rIt = pgpPub.getKeyRings();
        while (key == null && rIt.hasNext()) 
            PGPPublicKeyRing kRing = (PGPPublicKeyRing) rIt.next();
            Iterator kIt = kRing.getPublicKeys();
            while (key == null && kIt.hasNext()) 
                PGPPublicKey k = (PGPPublicKey) kIt.next();
                if (k.isEncryptionKey()) 
                    key = k;
                
            
        
        if (key == null) 
            throw new IllegalArgumentException("Can't find encryption key in key ring.");
        
        return key;
    

Los siguientes 2 métodos para descifrar y cifrar archivos gpg:

public void decryptFile(InputStream in, InputStream secKeyIn, InputStream pubKeyIn, char[] pass) throws IOException, PGPException, InvalidCipherTextException 
        Security.addProvider(new BouncyCastleProvider());

        PGPPublicKey pubKey = readPublicKeyFromCol(pubKeyIn);

        PGPSecretKey secKey = readSecretKeyFromCol(secKeyIn, pubKey.getKeyID());

        in = PGPUtil.getDecoderStream(in);

        JcaPGPObjectFactory pgpFact;


        PGPObjectFactory pgpF = new PGPObjectFactory(in, new BcKeyFingerprintCalculator());

        Object o = pgpF.nextObject();
        PGPEncryptedDataList encList;

        if (o instanceof PGPEncryptedDataList) 

            encList = (PGPEncryptedDataList) o;

         else 

            encList = (PGPEncryptedDataList) pgpF.nextObject();

        

        Iterator itt = encList.getEncryptedDataObjects();
        PGPPrivateKey sKey = null;
        PGPPublicKeyEncryptedData encP = null;
        while (sKey == null && itt.hasNext()) 
            encP = itt.next();
            secKey = readSecretKeyFromCol(new FileInputStream("PrivateKey.asc"), encP.getKeyID());
            sKey = secKey.extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(pass));
        
        if (sKey == null) 
            throw new IllegalArgumentException("Secret key for message not found.");
        

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

        pgpFact = new JcaPGPObjectFactory(clear);

        PGPCompressedData c1 = (PGPCompressedData) pgpFact.nextObject();

        pgpFact = new JcaPGPObjectFactory(c1.getDataStream());

        PGPLiteralData ld = (PGPLiteralData) pgpFact.nextObject();
        ByteArrayOutputStream bOut = new ByteArrayOutputStream();

        InputStream inLd = ld.getDataStream();

        int ch;
        while ((ch = inLd.read()) >= 0) 
            bOut.write(ch);
        

        //System.out.println(bOut.toString());

        bOut.writeTo(new FileOutputStream(ld.getFileName()));
        //return bOut;

    

    public static void encryptFile(OutputStream out, String fileName, PGPPublicKey encKey) throws IOException, NoSuchProviderException, PGPException 
        Security.addProvider(new BouncyCastleProvider());

        ByteArrayOutputStream bOut = new ByteArrayOutputStream();

        PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(PGPCompressedData.ZIP);

        PGPUtil.writeFileToLiteralData(comData.open(bOut), PGPLiteralData.BINARY, new File(fileName));

        comData.close();

        PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(new BcPGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.TRIPLE_DES).setSecureRandom(new SecureRandom()));

        cPk.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(encKey));

        byte[] bytes = bOut.toByteArray();

        OutputStream cOut = cPk.open(out, bytes.length);

        cOut.write(bytes);

        cOut.close();

        out.close();
    

Ahora aquí está cómo invocar/ejecutar lo anterior:

try 
             decryptFile(new FileInputStream("encryptedFile.gpg"), new FileInputStream("PrivateKey.asc"), new FileInputStream("PublicKey.asc"), "yourKeyPassword".toCharArray());

            PGPPublicKey pubKey = readPublicKeyFromCol(new FileInputStream("PublicKey.asc"));

            encryptFile(new FileOutputStream("encryptedFileOutput.gpg"), "fileToEncrypt.txt", pubKey);




         catch (PGPException e) 
            fail("exception: " + e.getMessage(), e.getUnderlyingException());
        

Decidí ir con un enfoque muy diferente, que es renunciar por completo al uso del castillo hinchable y simplemente usar un proceso de tiempo de ejecución en su lugar. Para mí, esta solución funciona y elimina por completo la complejidad que rodea al castillo hinchable:

String[] gpgCommands = new String[] 
        "gpg",
        "--passphrase",
        "password",
        "--decrypt",
        "test-files/accounts.txt.gpg"
;

Process gpgProcess = Runtime.getRuntime().exec(gpgCommands);
BufferedReader gpgOutput = new BufferedReader(new InputStreamReader(gpgProcess.getInputStream()));
BufferedReader gpgError = new BufferedReader(new InputStreamReader(gpgProcess.getErrorStream()));

Después de hacer eso, debe recordar drenar su flujo de entrada a medida que su proceso se está ejecutando o su programa probablemente se bloqueará dependiendo de cuánto esté generando. Vea mi respuesta en este hilo (y también la de Cameron Skinner y Matthew Wilson, quienes me guiaron por el camino correcto) para obtener un poco más de contexto: llamar a GnuPG en Java a través de un proceso de tiempo de ejecución para cifrar y descifrar archivos: el descifrado siempre se bloquea

Para cualquiera que busque una solución alternativa, consulte https://stackoverflow.com/a/42176529/7550201

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

Para resumir: la programación de Bouncycastle es a menudo una gran cantidad de programación de culto de carga y escribí una biblioteca para cambiar eso.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *