3
votes

My problem is with symmetric decryption. Not asymmetric decryption. So the correct answer is here Decrypt PGP encrypted file with passphrase only in Java

I use gpg to encrypt "hello":

[root@shc-sma-cd13 opt]# echo "hello" | gpg --symmetric --armor --cipher-algo AES256 --passphrase "2R79P7z5f8350VEp" --batch
-----BEGIN PGP MESSAGE-----
Version: GnuPG v2.0.22 (GNU/Linux)

jA0ECQMC1XpaSrXhBAfU0jsBXw817k4k4iT++AGV8MUev4/gKkuIwAW2VaJsEANa
+0ZuqZgFp/8N7AndRhyNj5WGcloQQkLkwvIV3Q==
=GwQi
-----END PGP MESSAGE-----

I use Java to decrypt the string:

public class AESUtils1 {
private static final String KEY_VAL = "2R79P7z5f8350VEp";

public static String AESDecode(String content) {
    try {
        SecretKey key = new SecretKeySpec(KEY_VAL.getBytes(), "AES");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] byte_content = new BASE64Decoder().decodeBuffer(content);
        byte[] byte_decode = cipher.doFinal(byte_content);
        String AES_decode = new String(byte_decode, "utf-8");
        return AES_decode;
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
        e.printStackTrace();
    } catch (BadPaddingException e) {
        e.printStackTrace();
    }
    //如果有错就返加nulll
    return null;
}

public static void main(String[] args) {
    String encryptString = "jA0ECQMC1XpaSrXhBAfU0jsBXw817k4k4iT++AGV8MUev4/gKkuIwAW2VaJsEANa\n" +
            "    +0ZuqZgFp/8N7AndRhyNj5WGcloQQkLkwvIV3Q==\n" +
            "    =GwQi";
    String decryptString = AESDecode(encryptString);
    System.out.println("decryptString: " + decryptString);
}

}

But it fails with error message:

javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:936)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:847)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
at javax.crypto.Cipher.doFinal(Cipher.java:2164)
at com.hpe.itsma.itsmaInstaller.AESUtils1.AESDecode(AESUtils1.java:33)
at com.hpe.itsma.itsmaInstaller.AESUtils1.main(AESUtils1.java:57)
decryptString: null

I am curious that what is the real encrypted string from gpg that I can put it into Java. The output of gpg is different from using Java to encrypt "hello". And another interesting thing is that every time I run command echo "hello" | gpg --symmetric --armor --cipher-algo AES256 --passphrase "2R79P7z5f8350VEp" --batch, the result is always different. Is that possible to decrypt the string which is encrypted by gpg. Or the wrong way I used of gpg?

1
Looks like your string consists of multiple Base64 encoded datagrams and needs to be decoded before decrypting. Also, I'm no gpg expert but I'm sure it's much more complicated than just AES.Mark Jeronimus
I found another interesting thing. Every time I run command echo "hello" | gpg --symmetric --armor --cipher-algo AES256 --passphrase "2R79P7z5f8350VEp" --batch The result is always different.Cain
I suppose the encryption is salted and the salt is somewhere concatenated to the result.Mark Jeronimus
@MarkJeronimus+ to be exact, PGP password-based key derivation can be and for GPG by default is salted, AND the 'bulk' (data/session) encryption is (always) randomized, although with a kind of pseudo-IV instead of the standard IV. Cain: PGP encryption, even password-based, is not even remotely similar to just encrypting the data with AES using the password. And it doesn't use ECB, as your Java code does. And last line of the body =GwQi is not part of the message, but rather a CRC value; see RFC4880. ...dave_thompson_085

1 Answers

1
votes

Thanks all. Finally, I figure out the solution. Cause my data was symmetric encrypted. The decryption will be different from the asymmetric decryption. I put my code below, also you can find the same answer here Decrypt PGP encrypted file with passphrase only in Java

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.*;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePBEDataDecryptorFactoryBuilder;
import org.bouncycastle.util.io.Streams;

import java.io.*;
import java.security.NoSuchProviderException;
import java.security.Security;

public class SymmetricDecyption {

  public static byte[] decrypt(byte[] var0, char[] var1) throws IOException, PGPException, NoSuchProviderException {
    ByteArrayInputStream var2 = new ByteArrayInputStream(var0);
    InputStream var11 = PGPUtil.getDecoderStream(var2);
    PGPObjectFactory var3 = new PGPObjectFactory(var11);
    Object var5 = var3.nextObject();
    PGPEncryptedDataList var4;
    if (var5 instanceof PGPEncryptedDataList) {
      var4 = (PGPEncryptedDataList) var5;
    } else {
      var4 = (PGPEncryptedDataList) var3.nextObject();
    }

    PGPPBEEncryptedData var6 = (PGPPBEEncryptedData) var4.get(0);
    InputStream var7 = var6.getDataStream((new JcePBEDataDecryptorFactoryBuilder((new JcaPGPDigestCalculatorProviderBuilder()).setProvider("BC").build())).setProvider("BC").build(var1));
    PGPObjectFactory var8 = new PGPObjectFactory(var7);
    PGPCompressedData var9 = (PGPCompressedData) var8.nextObject();
    var8 = new PGPObjectFactory(var9.getDataStream());
    PGPLiteralData var10 = (PGPLiteralData) var8.nextObject();
    return Streams.readAll(var10.getInputStream());
  }

  public static void main(String[] var0) throws Exception {
    String password = "2R79P7z5f8350VEp";
    File file = new File("C:\\Users\\zhongtao.CORPDOM\\Desktop\\file.txt.asc");
    InputStream input = new FileInputStream(file);
    byte[] byt = new byte[input.available()];
    input.read(byt);

    Security.addProvider(new BouncyCastleProvider());
    byte[] var5 = decrypt(byt, password.toCharArray());
    System.out.println("Decrypted data is: " + new String(var5));
  }
}