【发布时间】:2021-02-25 00:53:25
【问题描述】:
我的任务是构建一个使用 PGP 加密数据(字符串或 InputStream)的 java 方法。我按照指南here 生成了一个测试公钥和带有密码的私钥。然后我使用下面的命令导出公钥并将其复制并粘贴到我的 java 代码中。
gpg --armor --output pubkey.txt --export 'Your Name'
我可以使用以下命令加密文件
gpg --encrypt --armor -r 'Your Name' plaintext.txt
我得到以下内容,这是我想要在我的 java 程序中实现的。作为要求的一部分,我可能需要稍后对其进行签名,但我现在要做的就是能够像这样成功加密它。
-----BEGIN PGP MESSAGE-----
Version: GnuPG v2.0.22 (GNU/Linux)
hQEMA0PxXau0Q30VAQf/RuWsN3f4L2HW2GJWOZUjetJsw0odXYbDc7Sug1gZULP8
I0KRrvxnHgiiJgSlBZsws8E8iB1/LDCYJ8oJGj6olicz83iUT8VLdzdJZlc0+96/
BHAvtSTtEv2PWZlh307nU+Zn9cuGAccaijyekCosS5/0JpDyXSFefsLTexMgphAL
veXsxtsISyUU6S0xUux6Ac9HgUWTpCrlNaSdqBN1bk7y8YuvbZgbQ5akwY5FEbq1
f9rxmgXgEgz3N+7f8n5yN2OvWiEyXb+qngVgDLzysD8NTtKDqtw5nViscvVF1h3v
AebdxYxOKGYnWk6XAWhpIgIZdY0ZXG0yu9NJH5VfLtJSAc3c6d2/Nhb7g+k+f2Mn
srZW6XzHCeyGQQqSfr5YJfyUVdsW12udmhnc+ErbRkz84oDkMvFaxes6+2AAKrP/
jdWXsp4fTPl454m+tG5ec/Kn0Q==
=cZH2
-----END PGP MESSAGE-----
我需要构建的 java 方法接受公钥作为字符串参数,然后我使用以下方法将其转换为 PGPPublicKey。
private static PGPPublicKey getPublicKey(String keyAscii) throws IOException, PGPException, Exception {
InputStream encodedKey = new ByteArrayInputStream(keyAscii.getBytes());
InputStream decodedKey = PGPUtil.getDecoderStream(encodedKey);
JcaPGPPublicKeyRingCollection pgpPub = new JcaPGPPublicKeyRingCollection(decodedKey);
decodedKey.close();
PGPPublicKey key = null;
Iterator<PGPPublicKeyRing> rIt = pgpPub.getKeyRings();
while (key == null && rIt.hasNext()) {
PGPPublicKeyRing kRing = rIt.next();
Iterator<PGPPublicKey> kIt = kRing.getPublicKeys();
while (key == null && kIt.hasNext()) {
PGPPublicKey k = kIt.next();
if (k.isEncryptionKey()) {
key = k;
}
}
}
if (key == null) {
throw new Exception("Can't find key");
}
return key;
}
但是,当我运行 java 程序时,我在以下代码行中收到错误“构造公钥的异常”。
OutputStream cOut = encGen.open(encOut, new byte[4096]);
以下完全错误
org.bouncycastle.openpgp.PGPException: exception constructing public key
at org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyConverter.getPublicKey(Unknown Source)
at org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator.encryptSessionInfo(Unknown Source)
at org.bouncycastle.openpgp.operator.PublicKeyKeyEncryptionMethodGenerator.generate(Unknown Source)
at org.bouncycastle.openpgp.PGPEncryptedDataGenerator.open(Unknown Source)
at org.bouncycastle.openpgp.PGPEncryptedDataGenerator.open(Unknown Source)
at pgp.PgpImpl.encrypt(PgpImpl.java:84)
at pgp.PgpImpl.main(PgpImpl.java:216)
Caused by: java.security.NoSuchProviderException: no such provider: BC
at sun.security.jca.GetInstance.getService(GetInstance.java:83)
at sun.security.jca.GetInstance.getInstance(GetInstance.java:206)
at java.security.KeyFactory.getInstance(KeyFactory.java:211)
at org.bouncycastle.jcajce.util.NamedJcaJceHelper.createKeyFactory(Unknown Source)
at org.bouncycastle.openpgp.operator.jcajce.OperatorHelper.createKeyFactory(Unknown Source)
at org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyConverter.implGeneratePublic(Unknown Source)
... 7 more
我遵循了示例here,但它没有提供任何关于如何构造来自字符串的公钥的信息。
这是我目前的代码。
package pgp;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.SecureRandom;
import java.util.Date;
import java.util.Iterator;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.bouncycastle.openpgp.PGPEncryptedDataGenerator;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPLiteralData;
import org.bouncycastle.openpgp.PGPLiteralDataGenerator;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPUtil;
import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator;
import org.bouncycastle.openpgp.operator.PGPDataEncryptorBuilder;
import org.bouncycastle.openpgp.operator.PGPKeyEncryptionMethodGenerator;
import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.bouncycastle.openpgp.jcajce.JcaPGPPublicKeyRingCollection;
public class PgpImpl {
public PgpImpl() {
}
private static String encrypt(byte[] data, PGPPublicKey encryptionKey) throws Exception {
String step = "Step-0";
try {
step = "Step-1";
PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(
new JcePGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.AES_256)
.setWithIntegrityPacket(true)
.setSecureRandom(new SecureRandom())
.setProvider("BC"));
step = "Step-2";
encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(encryptionKey)
.setSecureRandom(new SecureRandom()).setProvider("BC"));
step = "Step-3";
ByteArrayOutputStream encOut = new ByteArrayOutputStream();
step = "Step-4";
// create an indefinite length encrypted stream
OutputStream cOut = encGen.open(encOut, new byte[4096]);
step = "Step-5";
// write out the literal data
PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
OutputStream pOut = lData.open(cOut, PGPLiteralData.BINARY, PGPLiteralData.CONSOLE, data.length,
new Date());
pOut.write(data);
pOut.close();
// finish the encryption
cOut.close();
step = "Step-6";
return new String(encOut.toByteArray());
} catch (Exception e) {
//throw new Exception(String.format("%s: %s", e.getMessage(), step));
e.printStackTrace();
}
return new String(step);
}
private static PGPPublicKey getPublicKey(String keyAscii) throws IOException, PGPException, Exception {
InputStream encodedKey = new ByteArrayInputStream(keyAscii.getBytes());
InputStream decodedKey = PGPUtil.getDecoderStream(encodedKey);
JcaPGPPublicKeyRingCollection pgpPub = new JcaPGPPublicKeyRingCollection(decodedKey);
decodedKey.close();
PGPPublicKey key = null;
Iterator<PGPPublicKeyRing> rIt = pgpPub.getKeyRings();
while (key == null && rIt.hasNext()) {
PGPPublicKeyRing kRing = rIt.next();
Iterator<PGPPublicKey> kIt = kRing.getPublicKeys();
while (key == null && kIt.hasNext()) {
PGPPublicKey k = kIt.next();
if (k.isEncryptionKey()) {
key = k;
}
}
}
if (key == null) {
throw new Exception("Can't find key");
}
return key;
}
public static void main(String[] args) {
String publicKey = "-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n" + "Version: GnuPG v2.0.22 (GNU/Linux)\r\n"
+ "\r\n" + "mQENBGA1A70BCADK8BnH6GgMbnS1TJSpJvgH+D9VIw0sN8XZWQsUmWWV9WSqhqXt\r\n"
+ "5wNC4XJDcaWtMCapaekQXV5S52T7QCxAz/E5oZzIDe+IUCHQz0WUs37S4Wnw+SZ6\r\n"
+ "QNPXOFaC4nNByRq6gvg0+wtD2Bo/3OJur3f0O0aRSHNiwfd0PdFgG0NU5vGV9PwE\r\n"
+ "xbTMpGssWexIC0MwJaYfJkxzov33CkwLaITvBTCn/J3oeX6JarMkgpurp1FAW0Jk\r\n"
+ "YzgGMOOxwuEVedwP4NtEPce+UtLv2NHHfqsW6xSxjWqsJkMdJ9afzu1jvn9M6e0j\r\n"
+ "MOTmPUCYVCioXK59It8ngN8NLtwaPgfnBwcbABEBAAG0BWFsbGVuiQE5BBMBAgAj\r\n"
+ "BQJgNQO9AhsDBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQxzGJxIrjAlxq\r\n"
+ "aggAgoiO82MZZMHyhZ3uLD4qTQ2vsT6+onhCr83kw0eFNM5AH0r3xlVARXHaViWC\r\n"
+ "SFutpb/34lrCTpJfLfKwdFU2bJP2SI3hAujtTg45UFklswu6GZaqQno6JKkZM4hw\r\n"
+ "ltFIXU1dMpIud7nsJ2QU46TI97n+HeD7DvOSGY/CFPnNot0YFHxXCKtHdPHk8JO3\r\n"
+ "JdOG0X90Yi9XSI1USv8HL/WjOTvhSqo7Qps2MpcUZrfNsa0H9Adk9xVYiz0nKNPY\r\n"
+ "qLQxFAiHb34vdav4e28anJ8th93SfiRn5OFK2G6R3DlhLlvn3h1dSAT6vSOrzx80\r\n"
+ "EylyMg2BIbRfp+JEgwCMf2V8X7kBDQRgNQO9AQgA3qV0wYvdH5M4XBzVwDtuGuIs\r\n"
+ "+GRcSRQqmvnt94e8ZE4Kv2w2Pf/JxPMwnPC92lVRypdOjmTZrT3R0z7g+D8mU5A9\r\n"
+ "o/CPvvSShA8Jh3z69S+hLP0nSaajsVsQlBGrI8ehI1EVJDsNh15PZrl27OK0aBb4\r\n"
+ "Fp0BYm0D2HaLnQPD4/jhTR13i1mt5E5hmBwiZiiWr/Wa1i1g1o/XaT4CApu91zgg\r\n"
+ "cmJBz9DL/C2hYC5lkp/cz5IJYp5BsvfA2lwamca33aHxFj8+Bz3+REWa8zvEqQ9U\r\n"
+ "a26RbPVjkeGChwNWLxNTuj1rNDdqB/KZO6iM02orqW86L45SKTBWYqPcpD7GeQAR\r\n"
+ "AQABiQEfBBgBAgAJBQJgNQO9AhsMAAoJEMcxicSK4wJcOLEIAMevvOk9iZ13T3yA\r\n"
+ "+ZW8mWKKE5aXy93VPKAvplP/WlW2VVGeb+6rEkFFsdN4doYIJPEIr+U7K0GDR6XX\r\n"
+ "TKLyI7BtUZPegOdjgcFWVGFnFogDnkrO+IPY+JUy1VMg8fGStThfa2dYEgd7yqpq\r\n"
+ "fZ97q5RQun1B+wyRdPDgC39roSGEwtXbRCZnuSMVNT7J9a2qnXkenvQRSoPjY7wQ\r\n"
+ "tn1wUfnHyjyS9OzfXTSHDi2A5JDRCh5L/V7Q93/P5Isv/U4QzIWudGM6AjuaoZ6i\r\n"
+ "chksRI9EchNKnSut9ebTyTkIJ80sB7Eyfp8TtORAnz8/Xf8A8aYD73r9rD4poSmo\r\n" + "FV15pP8=\r\n" + "=Yc74\r\n"
+ "-----END PGP PUBLIC KEY BLOCK-----";
try {
PGPPublicKey key = getPublicKey(publicKey);
System.out.println(encrypt("Test".getBytes(), key));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (PGPException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
感谢任何帮助。
更新 #1:获取堆栈跟踪后,我发现错误是由于无效的提供程序引起的,然后我使用它进行了更改
BouncyCastleProvider provider = new BouncyCastleProvider();
所以我不得不更改对提供者的所有引用。
private static String encrypt(byte[] data, PGPPublicKey encryptionKey) {
BouncyCastleProvider provider = new BouncyCastleProvider();
String step = "Step-0";
try {
step = "Step-1";
PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(
new JcePGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.AES_256)
.setWithIntegrityPacket(true)
.setSecureRandom(new SecureRandom())
.setProvider(provider));
step = "Step-2";
encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(encryptionKey)
.setSecureRandom(new SecureRandom()).setProvider(provider));
step = "Step-3";
ByteArrayOutputStream encOut = new ByteArrayOutputStream();
step = "Step-4";
// create an indefinite length encrypted stream
OutputStream cOut = encGen.open(encOut, new byte[1 << 16]);
step = "Step-5";
// write out the literal data
PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
OutputStream pOut = lData.open(cOut, PGPLiteralData.BINARY, PGPLiteralData.CONSOLE, data.length,
new Date());
pOut.write(data);
pOut.close();
// finish the encryption
cOut.close();
step = "Step-6";
return new String(encOut.toByteArray());
} catch (Exception e) {
//throw new Exception(String.format("%s: %s", e.getMessage(), step));
e.printStackTrace();
}
return new String("");
}
但现在我遇到了另一个错误。
org.bouncycastle.openpgp.PGPException: Exception creating cipher
at org.bouncycastle.openpgp.PGPEncryptedDataGenerator.open(Unknown Source)
at org.bouncycastle.openpgp.PGPEncryptedDataGenerator.open(Unknown Source)
at pgp.PgpImpl.encrypt(PgpImpl.java:85)
at pgp.PgpImpl.main(PgpImpl.java:217)
Caused by: org.bouncycastle.openpgp.PGPException: invalid key: Illegal key size
at org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder$MyPGPDataEncryptor.<init>(Unknown Source)
at org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder.build(Unknown Source)
... 4 more
Caused by: java.security.InvalidKeyException: Illegal key size
at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1034)
at javax.crypto.Cipher.init(Cipher.java:1367)
at javax.crypto.Cipher.init(Cipher.java:1301)
... 6 more
更新#2:做了一些研究,发现了this。按照那里的说明进行操作,一切正常。
【问题讨论】:
-
请将异常的完整堆栈跟踪添加到您的问题中。
-
@tgdavies 完成。谢谢。
-
当您像在
throw new Exception(String.format("%s: %s", e.getMessage(), step));中那样抛出一个新异常时,您必须将原始异常包含为您要抛出的新异常的cause。否则,您将失去必要的上下文。请修复该问题并添加完整的 stackttrace。 -
@tgdavies 对此感到抱歉。按照建议完成。多亏了您的建议,我现在收到了更多信息错误。
标签: java bouncycastle public-key-encryption pgp