如何使用Java解密由gpg加密的字符串?

3

我的问题是对称解密,不是非对称解密。正确的答案在这里: Java中仅使用密语解密PGP加密文件

我使用gpg加密"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-----

我使用Java来解密字符串:

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

}

但是它失败了并显示错误信息:

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

我很好奇,gpg生成的加密字符串在Java中该如何使用。使用Java加密“hello”的输出结果与gpg不同。还有一个有趣的问题是,每次运行命令echo "hello" | gpg --symmetric --armor --cipher-algo AES256 --passphrase "2R79P7z5f8350VEp" --batch,结果都是不同的。是否可能解密由gpg加密的字符串?或者我使用gpg的方式有误?


1
看起来你的字符串由多个Base64编码数据包组成,在解密之前需要进行解码。此外,我不是gpg专家,但我确定它比仅使用AES要复杂得多。 - Mark Jeronimus
我发现了另一件有趣的事情。每次我执行命令 echo "hello" | gpg --symmetric --armor --cipher-algo AES256 --passphrase "2R79P7z5f8350VEp" --batch 结果总是不同的。 - Cain
1
我猜测加密是经过盐处理的,而盐被某处连接到结果中。 - Mark Jeronimus
@MarkJeronimus+ 确切地说,PGP基于密码的密钥派生可以进行,并且默认情况下为GPG加盐,且“批量”(数据/会话)加密始终是随机的,尽管使用一种伪-IV而不是标准IV。 Cain:PGP加密,即使是基于密码的,也与仅使用密码使用AES加密数据没有任何相似之处。它也不使用ECB,就像您的Java代码一样。正文的最后一行“= GwQi”不是消息的一部分,而是CRC值;请参阅RFC4880。... - dave_thompson_085
如果您只是想要一个解决方案(并且可以使用BouncyCastle),请参阅https://dev59.com/aKfja4cB1Zd3GeqPu2BV,特别是链接到Bouncy示例代码。如果您想自己完成,请先阅读RFC 4880,然后您将了解任务的重要性。 - dave_thompson_085
显示剩余2条评论
1个回答

1
感谢大家。最终,我找到了解决方案。因为我的数据被对称加密了。解密将与非对称解密不同。我在下面放置了我的代码,你也可以在这里找到相同的答案 使用Java仅通过密码破解PGP加密文件
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));
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接