我一直在使用 Bouncy Castle API 为 byte[] 进行 PGP 加密和解密并收到 "Invalid Armor" 错误消息
I have been working on PGP Encrypt and Decrypt for byte[] with Bouncy Castle API and getting "Invalid Armor" error message
我在 Java 中使用充气城堡 API 开发 PGP Encryption/Decryption 有一段时间了,我成功地处理了文件,但我需要使用inputStream/byte 数组,我在这样做时遇到了问题。使用以下代码,加密工作没有任何问题。但是对于解密,我遇到了 "Invalid Armor" 错误,请参阅下面的错误消息。我搜索了整个 google,但在任何地方都找不到类似的错误。任何帮助将非常感激。让我知道我需要在我的代码中修复什么。我也在使用 PGPUtil class 到 convert/read public 和私钥。
错误:
Encryption Success
Exception in thread "main" java.io.IOException: invalid armor
at org.bouncycastle.bcpg.ArmoredInputStream.readIgnoreSpace(Unknown Source)
at org.bouncycastle.bcpg.ArmoredInputStream.read(Unknown Source)
at org.bouncycastle.bcpg.BCPGInputStream.nextPacketTag(Unknown Source)
at org.bouncycastle.openpgp.PGPObjectFactory.nextObject(Unknown Source)
at com.iice.vega.unity.api.batch.pgp.PGPProcess.decrypt(PGPProcess.java:63)
at com.iice.vega.unity.api.batch.pgp.PGPTest.main(PGPTest.java:64)
这是我的代码:
public class PGPProcess {
private static String publicKeyPath = System.getProperty("user.dir")+"/keys/Public_Key.asc";
private static String privateKeyPath = System.getProperty("user.dir")+"/keys/Private_Key.asc";
private static String password = "";
public static byte[] decrypt(byte[] encrypted)
throws IOException, PGPException, NoSuchProviderException {
Security.addProvider(new BouncyCastleProvider());
InputStream keyIn = new BufferedInputStream(new FileInputStream(stsPrivateKeyPath));
char[] password = "".toCharArray();
InputStream in = new ByteArrayInputStream(encrypted);
in = PGPUtil.getDecoderStream(in);
JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(in);
PGPEncryptedDataList enc;
Object o = pgpF.nextObject();
if (o instanceof PGPEncryptedDataList) {
enc = (PGPEncryptedDataList) o;
} else {
enc = (PGPEncryptedDataList) pgpF.nextObject();
}
Iterator it = enc.getEncryptedDataObjects();
PGPPrivateKey sKey = null;
PGPPublicKeyEncryptedData pbe = null;
PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(
PGPUtil.getDecoderStream(keyIn), new JcaKeyFingerprintCalculator());
while (sKey == null && it.hasNext()) {
pbe = (PGPPublicKeyEncryptedData) it.next();
sKey = PGPExampleUtil.findSecretKey(pgpSec, pbe.getKeyID(), password);
}
if (sKey == null) {
throw new IllegalArgumentException(
"secret key for message not found.");
}
InputStream clear = pbe.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("BC").build(sKey));
JcaPGPObjectFactory plainFact = new JcaPGPObjectFactory(clear);
PGPCompressedData cData = (PGPCompressedData)plainFact.nextObject();
JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(cData.getDataStream());
PGPLiteralData ld = (PGPLiteralData) pgpFact.nextObject();
InputStream unc = ld.getInputStream();
ByteArrayOutputStream out = new ByteArrayOutputStream();
int ch;
while ((ch = unc.read()) >= 0) {
out.write(ch);
}
byte[] returnBytes = out.toByteArray();
out.close();
return returnBytes;
}
public static byte[] encrypt(byte[] clearData)
throws IOException, PGPException, NoSuchProviderException {
Security.addProvider(new BouncyCastleProvider());
String fileName=null;
boolean withIntegrityCheck =true;
boolean armor = false;
if (fileName == null) {
fileName = PGPLiteralData.CONSOLE;
}
PGPPublicKey encKey = PGPExampleUtil.readPublicKey(stsPublicKeyPath);
ByteArrayOutputStream encOut = new ByteArrayOutputStream();
OutputStream out = encOut;
if (armor) {
out = new ArmoredOutputStream(out);
}
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(
PGPCompressedData.ZIP);
OutputStream cos = comData.open(bOut); // open it with the final
// destination
PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
OutputStream pOut = lData.open(cos, // the compressed output stream
PGPLiteralData.BINARY, fileName, // "filename" to store
clearData.length, // length of clear data
new Date() // current time
);
pOut.write(clearData);
lData.close();
comData.close();
PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(new JcePGPDataEncryptorBuilder(PGPEncryptedData.CAST5).setWithIntegrityPacket(withIntegrityCheck).setSecureRandom(new SecureRandom()).setProvider("BC"));
cPk.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(encKey).setProvider("BC"));
byte[] bytes = bOut.toByteArray();
OutputStream cOut = cPk.open(out, bytes.length);
cOut.write(bytes); // obtain the actual bytes from the compressed stream
cOut.close();
out.close();
return encOut.toByteArray();
}
}
有时从一组新的文件开始是很好的。在我的 GitHub-Repository 中
https://github.com/java-crypto/Whosebug/tree/master/PGP_Encrypt_Decrypt_Armor_Error
您可以下载 secret_rsa_kleo passphrase.zip 内容如下:
Main3.java: simple test program as shown below
PGPExampleUtil.java: taken from Bouncy Castle PGP examples
secret_rsa_kleo.asc: brandnew generated private key (done with Kleopatra 3.1.11)
pub_rsa_kleo.asc: public key
bcprov-jdk15to18-165.jar + bcpg-jdk15on-165.jar: Bouncy Castle jars
我用密码"mypassphrase"(没有“”:-)生成了我的密钥对。输出结果如下:
测试Java版本:11.0.6+8-b520.43 BouncyCastle版本:BC版本1.65
明文:54686973206973206d7920706c61696e74657874
解密文本:54686973206973206d7920706c61696e74657874
明文等于解密文本:true
ciphetext: 85010c03f9a05b3a12b538270107ff4c960552ca571ff4a24518189e038bd574e64504398b10fc85375e5f6b62ea3f69f686ebd20a1ef7cd0bd59823c025470d85930b89a5ee2c97683d39685c32a607f8c4ecb7a8270c4aff359f0b20a4e76599894f6d987c3d2d710e56a6354001fd4bfa54770609e917915dc51994feb49155a6b2259f3f1c449baca58e43440e6aee527f56cbbd024b463ec76dceab40ffbd940297115b93a535f00ca6c7880b449077d04e35ef1e2c35f579a4df8267be809c7ce5b82f627f1e4b45e9ae0cbd79f88d3c1621b45b6a7c527e86529480949fe9f69b31b79612a91248f2f5fad6750c46d2b4d025da9b70b18d3377938e73e4f941c969f722d2b2b21a44233cf5d24701a6363eb6e28a9b4c2431db135ff4be3423a5138f70aba971173d72df910b6a336c7f15158abcd7d40c2b491d4af7732de9b0783fc8887f9ca068d8274632a42fa876d0986208
密文字符串:����[:��8'��L��R��W��E����t��E9����7^kb��?i����
������,��h=9h����취'J��5���e��Om�|=-qV��5@��K��Tw ��]������U ��%��?D����CDj�RV˽KF>��mΫ@����[��5��LjD��w��N5��,5��y��g����|��/bKE�� y����⊛L$1����4#��p��q=r��j3l����+IJ��s-��x?pos��h��'F2��/�� vИ
只需在您的原始系统上检查一件事:私钥取自此行:
String privateKeyPath = System.getProperty("user.dir")+"/keys/Private_Key.asc";
但在 encrypt/decrypt 方法中,变量是 stsPrivateKeyPath。
Main3.java:
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.*;
import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory;
import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
import java.io.*;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
public class Main3 {
//private static String publicKeyPath = System.getProperty("user.dir")+"/keys/Public_Key.asc";
private static String stsPublicKeyPath = "pub_rsa_kleo.asc";
//private static String privateKeyPath = System.getProperty("user.dir")+"/keys/Private_Key.asc";
private static String stsPrivateKeyPath = "secret_rsa_kleo.asc";
private static String passwordString = "mypassphrase";
public static void main(String[] args) throws NoSuchProviderException, IOException, PGPException {
System.out.println("");
Security.addProvider(new BouncyCastleProvider());
System.out.println("\nTest with Java version: " + Runtime.version() + " BouncyCastle Version: " + Security.getProvider("BC") + "\n");
byte[] plaintext = "This is my plaintext".getBytes("UTF-8");
byte[] ciphertext = encrypt(plaintext);
byte[] decryptedtext = decrypt(ciphertext);
System.out.println("plaintext: " + bytesToHex(plaintext));
System.out.println("decrytext: " + bytesToHex(decryptedtext));
System.out.println("plaintext equals decryptedtext: " + Arrays.equals(plaintext, decryptedtext));
System.out.println("\nciphetext: " + bytesToHex(ciphertext));
System.out.println("ciphertext String: " + new String(ciphertext, "UTF-8"));
// bcprov-jdk15to18-165.jar
// bcpg-jdk15on-165.jar
// OpenJDK 11.0.5
}
public static byte[] decrypt(byte[] encrypted)
throws IOException, PGPException, NoSuchProviderException {
Security.addProvider(new BouncyCastleProvider());
InputStream keyIn = new BufferedInputStream(new FileInputStream(stsPrivateKeyPath));
char[] password = passwordString.toCharArray();
//char[] password = "".toCharArray();
InputStream in = new ByteArrayInputStream(encrypted);
in = PGPUtil.getDecoderStream(in);
JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(in);
PGPEncryptedDataList enc;
Object o = pgpF.nextObject();
if (o instanceof PGPEncryptedDataList) {
enc = (PGPEncryptedDataList) o;
} else {
enc = (PGPEncryptedDataList) pgpF.nextObject();
}
Iterator it = enc.getEncryptedDataObjects();
PGPPrivateKey sKey = null;
PGPPublicKeyEncryptedData pbe = null;
PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(
PGPUtil.getDecoderStream(keyIn), new JcaKeyFingerprintCalculator());
while (sKey == null && it.hasNext()) {
pbe = (PGPPublicKeyEncryptedData) it.next();
sKey = PGPExampleUtil.findSecretKey(pgpSec, pbe.getKeyID(), password);
}
if (sKey == null) {
throw new IllegalArgumentException(
"secret key for message not found.");
}
InputStream clear = pbe.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("BC").build(sKey));
JcaPGPObjectFactory plainFact = new JcaPGPObjectFactory(clear);
PGPCompressedData cData = (PGPCompressedData)plainFact.nextObject();
JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(cData.getDataStream());
PGPLiteralData ld = (PGPLiteralData) pgpFact.nextObject();
InputStream unc = ld.getInputStream();
ByteArrayOutputStream out = new ByteArrayOutputStream();
int ch;
while ((ch = unc.read()) >= 0) {
out.write(ch);
}
byte[] returnBytes = out.toByteArray();
out.close();
return returnBytes;
}
public static byte[] encrypt(byte[] clearData)
throws IOException, PGPException {
Security.addProvider(new BouncyCastleProvider());
String fileName=null;
boolean withIntegrityCheck = true;
boolean armor = false; // org
if (fileName == null) {
fileName = PGPLiteralData.CONSOLE;
}
PGPPublicKey encKey = PGPExampleUtil.readPublicKey(stsPublicKeyPath);
ByteArrayOutputStream encOut = new ByteArrayOutputStream();
OutputStream out = encOut;
if (armor) {
out = new ArmoredOutputStream(out);
}
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(
PGPCompressedData.ZIP);
OutputStream cos = comData.open(bOut); // open it with the final
// destination
PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
OutputStream pOut = lData.open(cos, // the compressed output stream
PGPLiteralData.BINARY, fileName, // "filename" to store
clearData.length, // length of clear data
new Date() // current time
);
pOut.write(clearData);
lData.close();
comData.close();
PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(new JcePGPDataEncryptorBuilder(PGPEncryptedData.CAST5).setWithIntegrityPacket(withIntegrityCheck).setSecureRandom(new SecureRandom()).setProvider("BC"));
cPk.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(encKey).setProvider("BC"));
byte[] bytes = bOut.toByteArray();
OutputStream cOut = cPk.open(out, bytes.length);
cOut.write(bytes); // obtain the actual bytes from the compressed stream
cOut.close();
out.close();
return encOut.toByteArray();
}
private static String bytesToHex(byte[] bytes) {
StringBuffer result = new StringBuffer();
for (byte b : bytes) result.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
return result.toString();
}
}
PGPExampleUtil.java
package PGP_Encrypt_Decrypt_Armor_Error;
import org.bouncycastle.openpgp.*;
import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
import java.io.*;
import java.security.NoSuchProviderException;
import java.util.Iterator;
// https://github.com/bcgit/bc-java/blob/master/pg/src/main/java/org/bouncycastle/openpgp/examples/PGPExampleUtil.java
class PGPExampleUtil
{
static byte[] compressFile(String fileName, int algorithm) throws IOException
{
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(algorithm);
PGPUtil.writeFileToLiteralData(comData.open(bOut), PGPLiteralData.BINARY,
new File(fileName));
comData.close();
return bOut.toByteArray();
}
/**
* Search a secret key ring collection for a secret key corresponding to keyID if it
* exists.
*
* @param pgpSec a secret key ring collection.
* @param keyID keyID we want.
* @param pass passphrase to decrypt secret key with.
* @return the private key.
* @throws PGPException
* @throws NoSuchProviderException
*/
static PGPPrivateKey findSecretKey(PGPSecretKeyRingCollection pgpSec, long keyID, char[] pass)
throws PGPException, NoSuchProviderException
{
PGPSecretKey pgpSecKey = pgpSec.getSecretKey(keyID);
if (pgpSecKey == null)
{
return null;
}
return pgpSecKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider("BC").build(pass));
}
static PGPPublicKey readPublicKey(String fileName) throws IOException, PGPException
{
InputStream keyIn = new BufferedInputStream(new FileInputStream(fileName));
PGPPublicKey pubKey = readPublicKey(keyIn);
keyIn.close();
return pubKey;
}
/**
* A simple routine that opens a key ring file and loads the first available key
* suitable for encryption.
*
* @param input data stream containing the public key data
* @return the first public key found.
* @throws IOException
* @throws PGPException
*/
static PGPPublicKey readPublicKey(InputStream input) throws IOException, PGPException
{
PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(
PGPUtil.getDecoderStream(input), new JcaKeyFingerprintCalculator());
//
// we just loop through the collection till we find a key suitable for encryption, in the real
// world you would probably want to be a bit smarter about this.
//
Iterator keyRingIter = pgpPub.getKeyRings();
while (keyRingIter.hasNext())
{
PGPPublicKeyRing keyRing = (PGPPublicKeyRing)keyRingIter.next();
Iterator keyIter = keyRing.getPublicKeys();
while (keyIter.hasNext())
{
PGPPublicKey key = (PGPPublicKey)keyIter.next();
if (key.isEncryptionKey())
{
return key;
}
}
}
throw new IllegalArgumentException("Can't find encryption key in key ring.");
}
static PGPSecretKey readSecretKey(String fileName) throws IOException, PGPException
{
InputStream keyIn = new BufferedInputStream(new FileInputStream(fileName));
PGPSecretKey secKey = readSecretKey(keyIn);
keyIn.close();
return secKey;
}
/**
* A simple routine that opens a key ring file and loads the first available key
* suitable for signature generation.
*
* @param input stream to read the secret key ring collection from.
* @return a secret key.
* @throws IOException on a problem with using the input stream.
* @throws PGPException if there is an issue parsing the input stream.
*/
static PGPSecretKey readSecretKey(InputStream input) throws IOException, PGPException
{
PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(
PGPUtil.getDecoderStream(input), new JcaKeyFingerprintCalculator());
//
// we just loop through the collection till we find a key suitable for encryption, in the real
// world you would probably want to be a bit smarter about this.
//
Iterator keyRingIter = pgpSec.getKeyRings();
while (keyRingIter.hasNext())
{
PGPSecretKeyRing keyRing = (PGPSecretKeyRing)keyRingIter.next();
Iterator keyIter = keyRing.getSecretKeys();
while (keyIter.hasNext())
{
PGPSecretKey key = (PGPSecretKey)keyIter.next();
if (key.isSigningKey())
{
return key;
}
}
}
throw new IllegalArgumentException("Can't find signing key in key ring.");
}
}
secret_rsa_kleo.asc:
-----BEGIN PGP PRIVATE KEY BLOCK-----
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
=eGJl
-----END PGP PRIVATE KEY BLOCK-----
pub_rsa_kleo.asc:
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQENBF7hImoBCAC1YHtHUokERd9OqXiB0/ncVwQaqEBLdd3cxRZ0Kyd7K+OxHH5f
VCdYRWSyVANn4Z+3JjDGZFC5eAUFGWSMwVnWB6VlIW6+7UegGA2cIUAyH6fzBogs
W4hhoIVhUHXTsbUpqj2bhWj85db3GNuSnIhyu6ed0AavsnBbDooHFJYOYgXOvNqN
pq1gjbLIHvBZXZg/OvrpjSM0GoLX6bIDxofzh3ktFlBkUP1fGJ/Cx1xu1ANZ6mQq
6VF8DMcYBO08+HiQvaRkOYYI20AR5X3BOYA+UR63CiXjfvt9r2OX+GTExe3XJp8U
wkvm14JRCyad42ADOkik8fdiy4rGy0yVwe/BABEBAAG0GHRlc3QgdGVzdCA8dGVz
dEB0ZXN0LmRlPokBVAQTAQgAPhYhBOtbtDyOZRSPL5sgGfmgWzoStTgnBQJe4SJq
AhsDBQkDwfO2BQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEPmgWzoStTgnc2UH
/2cLGLIAQke/VT/Humfx0CwK9dHMgXT+BS52G43C8dzfTp1iwn31t/B/rfh9fDEx
uYT+nratO6hROME8ZzHcm6pLpyH4ZJCb35UO0KA/Eo8TN56VM69pEPzQbpc80AiF
gAQ0tLm58dAFIkMahKPfcOp5YpIw1wrfxiJkygV7e37wh9wiah/w2ho/8BawYEUG
arjoB13fYB5gNLzsmk1nd+/nMOZDaqOJXl3GhVI9i1pS5cqkT/T9WquybqW73whI
LpsSdBu9MWihhedCx6KtoDpSPrtzzXjKc7PJIjBPDN4pzH/0fqvN/k2736P1MP5z
yq/nOMOTevV6YZtN9SXA6Hq5AQ0EXuEiagEIAMN3rP9PhOm0ho14SXwjXKF/vXc+
EDT+vglwg7bZUpsJMYt5TMnT6dNHlV/ek8oMUEvBqBIHWrUplG/LFyaNJAjmgE4q
FoNHy1V9H9Jw439PH1T/8Mbw/n/k3xvanWcl03QcRcvPag8oaczYO+/+cbyl0R/X
lk2lAlBomfnM2+nfUFyTKVXJoG7TSHNRGbG3jmKyVzPi3Tb/JqbW2ITUBKkd+J6h
l5EK9NExqyXVoFHUf2KWfawXzEw9Dk83fKoDQHQkknzdQ+vm4l6MQ9m40OV7U3xd
6yd49p8h1+jpYv4bWguiWiJquAosABOF5DunpIUWel82uZ/PRCuLZpbGG38AEQEA
AYkBPAQYAQgAJhYhBOtbtDyOZRSPL5sgGfmgWzoStTgnBQJe4SJqAhsMBQkDwfO2
AAoJEPmgWzoStTgnFZ0H/3y9RhcPK65ssKjclr4gwMyquaDPqwKuXJLEZZNuapj0
G7j4AKJX6bN/RYJ3Nw51iC3vv5j5Pd4l6/d5PwZN5t54SV+T+6WPCbfbvBGn+jwj
mcE584hfwndioXjE+dVVoX4dhwkfZLOz6t825UTpKp2XEoFOeVpjTN8NhdiN5xe6
UHEUyHFBCkP9g81j1nKbgXXB6kss5r59WMIZrasVNOzh8WnAVLrTkuQC+/KZZqwi
8dseaBEeCR5vSzCZWjJULSeziiOGChn+e8CNKpgEn2QuNsWoOoaPe6wQVRoY/oxV
t4wc4dVh2W0HjzMOveo3Dvw66QT1NfXx4cmaOm5HWhc=
=bgyD
-----END PGP PUBLIC KEY BLOCK-----
"Invalid Armor"
此错误可能由于多种情况而发生。这是我的经历:
我格式化了键[加入行]而不是我应该按原样使用键。
密钥应始终采用以下文本格式。
AhsDBQkDwfO2BQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEPmgWzoStTgnc2UH
/2cLGLIAQke/VT/Humfx0CwK9dHMgXT+BS52G43C8dzfTp1iwn31t/B/rfh9fDEx
uYT+nratO6hROME8ZzHcm6pLpyH4ZJCb35UO0KA/Eo8TN56VM69pEPzQbpc80AiF
gAQ0tLm58dAFIkMahKPfcOp5YpIw1wrfxiJkygV7e37wh9wiah/w2ho/8BawYEUG
我在 Java 中使用充气城堡 API 开发 PGP Encryption/Decryption 有一段时间了,我成功地处理了文件,但我需要使用inputStream/byte 数组,我在这样做时遇到了问题。使用以下代码,加密工作没有任何问题。但是对于解密,我遇到了 "Invalid Armor" 错误,请参阅下面的错误消息。我搜索了整个 google,但在任何地方都找不到类似的错误。任何帮助将非常感激。让我知道我需要在我的代码中修复什么。我也在使用 PGPUtil class 到 convert/read public 和私钥。
错误:
Encryption Success
Exception in thread "main" java.io.IOException: invalid armor
at org.bouncycastle.bcpg.ArmoredInputStream.readIgnoreSpace(Unknown Source)
at org.bouncycastle.bcpg.ArmoredInputStream.read(Unknown Source)
at org.bouncycastle.bcpg.BCPGInputStream.nextPacketTag(Unknown Source)
at org.bouncycastle.openpgp.PGPObjectFactory.nextObject(Unknown Source)
at com.iice.vega.unity.api.batch.pgp.PGPProcess.decrypt(PGPProcess.java:63)
at com.iice.vega.unity.api.batch.pgp.PGPTest.main(PGPTest.java:64)
这是我的代码:
public class PGPProcess {
private static String publicKeyPath = System.getProperty("user.dir")+"/keys/Public_Key.asc";
private static String privateKeyPath = System.getProperty("user.dir")+"/keys/Private_Key.asc";
private static String password = "";
public static byte[] decrypt(byte[] encrypted)
throws IOException, PGPException, NoSuchProviderException {
Security.addProvider(new BouncyCastleProvider());
InputStream keyIn = new BufferedInputStream(new FileInputStream(stsPrivateKeyPath));
char[] password = "".toCharArray();
InputStream in = new ByteArrayInputStream(encrypted);
in = PGPUtil.getDecoderStream(in);
JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(in);
PGPEncryptedDataList enc;
Object o = pgpF.nextObject();
if (o instanceof PGPEncryptedDataList) {
enc = (PGPEncryptedDataList) o;
} else {
enc = (PGPEncryptedDataList) pgpF.nextObject();
}
Iterator it = enc.getEncryptedDataObjects();
PGPPrivateKey sKey = null;
PGPPublicKeyEncryptedData pbe = null;
PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(
PGPUtil.getDecoderStream(keyIn), new JcaKeyFingerprintCalculator());
while (sKey == null && it.hasNext()) {
pbe = (PGPPublicKeyEncryptedData) it.next();
sKey = PGPExampleUtil.findSecretKey(pgpSec, pbe.getKeyID(), password);
}
if (sKey == null) {
throw new IllegalArgumentException(
"secret key for message not found.");
}
InputStream clear = pbe.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("BC").build(sKey));
JcaPGPObjectFactory plainFact = new JcaPGPObjectFactory(clear);
PGPCompressedData cData = (PGPCompressedData)plainFact.nextObject();
JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(cData.getDataStream());
PGPLiteralData ld = (PGPLiteralData) pgpFact.nextObject();
InputStream unc = ld.getInputStream();
ByteArrayOutputStream out = new ByteArrayOutputStream();
int ch;
while ((ch = unc.read()) >= 0) {
out.write(ch);
}
byte[] returnBytes = out.toByteArray();
out.close();
return returnBytes;
}
public static byte[] encrypt(byte[] clearData)
throws IOException, PGPException, NoSuchProviderException {
Security.addProvider(new BouncyCastleProvider());
String fileName=null;
boolean withIntegrityCheck =true;
boolean armor = false;
if (fileName == null) {
fileName = PGPLiteralData.CONSOLE;
}
PGPPublicKey encKey = PGPExampleUtil.readPublicKey(stsPublicKeyPath);
ByteArrayOutputStream encOut = new ByteArrayOutputStream();
OutputStream out = encOut;
if (armor) {
out = new ArmoredOutputStream(out);
}
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(
PGPCompressedData.ZIP);
OutputStream cos = comData.open(bOut); // open it with the final
// destination
PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
OutputStream pOut = lData.open(cos, // the compressed output stream
PGPLiteralData.BINARY, fileName, // "filename" to store
clearData.length, // length of clear data
new Date() // current time
);
pOut.write(clearData);
lData.close();
comData.close();
PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(new JcePGPDataEncryptorBuilder(PGPEncryptedData.CAST5).setWithIntegrityPacket(withIntegrityCheck).setSecureRandom(new SecureRandom()).setProvider("BC"));
cPk.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(encKey).setProvider("BC"));
byte[] bytes = bOut.toByteArray();
OutputStream cOut = cPk.open(out, bytes.length);
cOut.write(bytes); // obtain the actual bytes from the compressed stream
cOut.close();
out.close();
return encOut.toByteArray();
}
}
有时从一组新的文件开始是很好的。在我的 GitHub-Repository 中 https://github.com/java-crypto/Whosebug/tree/master/PGP_Encrypt_Decrypt_Armor_Error 您可以下载 secret_rsa_kleo passphrase.zip 内容如下:
Main3.java: simple test program as shown below
PGPExampleUtil.java: taken from Bouncy Castle PGP examples
secret_rsa_kleo.asc: brandnew generated private key (done with Kleopatra 3.1.11)
pub_rsa_kleo.asc: public key
bcprov-jdk15to18-165.jar + bcpg-jdk15on-165.jar: Bouncy Castle jars
我用密码"mypassphrase"(没有“”:-)生成了我的密钥对。输出结果如下:
测试Java版本:11.0.6+8-b520.43 BouncyCastle版本:BC版本1.65
明文:54686973206973206d7920706c61696e74657874 解密文本:54686973206973206d7920706c61696e74657874 明文等于解密文本:true
ciphetext: 85010c03f9a05b3a12b538270107ff4c960552ca571ff4a24518189e038bd574e64504398b10fc85375e5f6b62ea3f69f686ebd20a1ef7cd0bd59823c025470d85930b89a5ee2c97683d39685c32a607f8c4ecb7a8270c4aff359f0b20a4e76599894f6d987c3d2d710e56a6354001fd4bfa54770609e917915dc51994feb49155a6b2259f3f1c449baca58e43440e6aee527f56cbbd024b463ec76dceab40ffbd940297115b93a535f00ca6c7880b449077d04e35ef1e2c35f579a4df8267be809c7ce5b82f627f1e4b45e9ae0cbd79f88d3c1621b45b6a7c527e86529480949fe9f69b31b79612a91248f2f5fad6750c46d2b4d025da9b70b18d3377938e73e4f941c969f722d2b2b21a44233cf5d24701a6363eb6e28a9b4c2431db135ff4be3423a5138f70aba971173d72df910b6a336c7f15158abcd7d40c2b491d4af7732de9b0783fc8887f9ca068d8274632a42fa876d0986208 密文字符串:����[:��8'��L��R��W��E����t��E9����7^kb��?i���� ������,��h=9h����취'J��5���e��Om�|=-qV��5@��K��Tw ��]������U ��%��?D����CDj�RV˽KF>��mΫ@����[��5��LjD��w��N5��,5��y��g����|��/bKE�� y����⊛L$1����4#��p��q=r��j3l����+IJ��s-��x?pos��h��'F2��/�� vИ
只需在您的原始系统上检查一件事:私钥取自此行:
String privateKeyPath = System.getProperty("user.dir")+"/keys/Private_Key.asc";
但在 encrypt/decrypt 方法中,变量是 stsPrivateKeyPath。
Main3.java:
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.*;
import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory;
import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
import java.io.*;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
public class Main3 {
//private static String publicKeyPath = System.getProperty("user.dir")+"/keys/Public_Key.asc";
private static String stsPublicKeyPath = "pub_rsa_kleo.asc";
//private static String privateKeyPath = System.getProperty("user.dir")+"/keys/Private_Key.asc";
private static String stsPrivateKeyPath = "secret_rsa_kleo.asc";
private static String passwordString = "mypassphrase";
public static void main(String[] args) throws NoSuchProviderException, IOException, PGPException {
System.out.println("");
Security.addProvider(new BouncyCastleProvider());
System.out.println("\nTest with Java version: " + Runtime.version() + " BouncyCastle Version: " + Security.getProvider("BC") + "\n");
byte[] plaintext = "This is my plaintext".getBytes("UTF-8");
byte[] ciphertext = encrypt(plaintext);
byte[] decryptedtext = decrypt(ciphertext);
System.out.println("plaintext: " + bytesToHex(plaintext));
System.out.println("decrytext: " + bytesToHex(decryptedtext));
System.out.println("plaintext equals decryptedtext: " + Arrays.equals(plaintext, decryptedtext));
System.out.println("\nciphetext: " + bytesToHex(ciphertext));
System.out.println("ciphertext String: " + new String(ciphertext, "UTF-8"));
// bcprov-jdk15to18-165.jar
// bcpg-jdk15on-165.jar
// OpenJDK 11.0.5
}
public static byte[] decrypt(byte[] encrypted)
throws IOException, PGPException, NoSuchProviderException {
Security.addProvider(new BouncyCastleProvider());
InputStream keyIn = new BufferedInputStream(new FileInputStream(stsPrivateKeyPath));
char[] password = passwordString.toCharArray();
//char[] password = "".toCharArray();
InputStream in = new ByteArrayInputStream(encrypted);
in = PGPUtil.getDecoderStream(in);
JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(in);
PGPEncryptedDataList enc;
Object o = pgpF.nextObject();
if (o instanceof PGPEncryptedDataList) {
enc = (PGPEncryptedDataList) o;
} else {
enc = (PGPEncryptedDataList) pgpF.nextObject();
}
Iterator it = enc.getEncryptedDataObjects();
PGPPrivateKey sKey = null;
PGPPublicKeyEncryptedData pbe = null;
PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(
PGPUtil.getDecoderStream(keyIn), new JcaKeyFingerprintCalculator());
while (sKey == null && it.hasNext()) {
pbe = (PGPPublicKeyEncryptedData) it.next();
sKey = PGPExampleUtil.findSecretKey(pgpSec, pbe.getKeyID(), password);
}
if (sKey == null) {
throw new IllegalArgumentException(
"secret key for message not found.");
}
InputStream clear = pbe.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("BC").build(sKey));
JcaPGPObjectFactory plainFact = new JcaPGPObjectFactory(clear);
PGPCompressedData cData = (PGPCompressedData)plainFact.nextObject();
JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(cData.getDataStream());
PGPLiteralData ld = (PGPLiteralData) pgpFact.nextObject();
InputStream unc = ld.getInputStream();
ByteArrayOutputStream out = new ByteArrayOutputStream();
int ch;
while ((ch = unc.read()) >= 0) {
out.write(ch);
}
byte[] returnBytes = out.toByteArray();
out.close();
return returnBytes;
}
public static byte[] encrypt(byte[] clearData)
throws IOException, PGPException {
Security.addProvider(new BouncyCastleProvider());
String fileName=null;
boolean withIntegrityCheck = true;
boolean armor = false; // org
if (fileName == null) {
fileName = PGPLiteralData.CONSOLE;
}
PGPPublicKey encKey = PGPExampleUtil.readPublicKey(stsPublicKeyPath);
ByteArrayOutputStream encOut = new ByteArrayOutputStream();
OutputStream out = encOut;
if (armor) {
out = new ArmoredOutputStream(out);
}
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(
PGPCompressedData.ZIP);
OutputStream cos = comData.open(bOut); // open it with the final
// destination
PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
OutputStream pOut = lData.open(cos, // the compressed output stream
PGPLiteralData.BINARY, fileName, // "filename" to store
clearData.length, // length of clear data
new Date() // current time
);
pOut.write(clearData);
lData.close();
comData.close();
PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(new JcePGPDataEncryptorBuilder(PGPEncryptedData.CAST5).setWithIntegrityPacket(withIntegrityCheck).setSecureRandom(new SecureRandom()).setProvider("BC"));
cPk.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(encKey).setProvider("BC"));
byte[] bytes = bOut.toByteArray();
OutputStream cOut = cPk.open(out, bytes.length);
cOut.write(bytes); // obtain the actual bytes from the compressed stream
cOut.close();
out.close();
return encOut.toByteArray();
}
private static String bytesToHex(byte[] bytes) {
StringBuffer result = new StringBuffer();
for (byte b : bytes) result.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
return result.toString();
}
}
PGPExampleUtil.java
package PGP_Encrypt_Decrypt_Armor_Error;
import org.bouncycastle.openpgp.*;
import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
import java.io.*;
import java.security.NoSuchProviderException;
import java.util.Iterator;
// https://github.com/bcgit/bc-java/blob/master/pg/src/main/java/org/bouncycastle/openpgp/examples/PGPExampleUtil.java
class PGPExampleUtil
{
static byte[] compressFile(String fileName, int algorithm) throws IOException
{
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(algorithm);
PGPUtil.writeFileToLiteralData(comData.open(bOut), PGPLiteralData.BINARY,
new File(fileName));
comData.close();
return bOut.toByteArray();
}
/**
* Search a secret key ring collection for a secret key corresponding to keyID if it
* exists.
*
* @param pgpSec a secret key ring collection.
* @param keyID keyID we want.
* @param pass passphrase to decrypt secret key with.
* @return the private key.
* @throws PGPException
* @throws NoSuchProviderException
*/
static PGPPrivateKey findSecretKey(PGPSecretKeyRingCollection pgpSec, long keyID, char[] pass)
throws PGPException, NoSuchProviderException
{
PGPSecretKey pgpSecKey = pgpSec.getSecretKey(keyID);
if (pgpSecKey == null)
{
return null;
}
return pgpSecKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider("BC").build(pass));
}
static PGPPublicKey readPublicKey(String fileName) throws IOException, PGPException
{
InputStream keyIn = new BufferedInputStream(new FileInputStream(fileName));
PGPPublicKey pubKey = readPublicKey(keyIn);
keyIn.close();
return pubKey;
}
/**
* A simple routine that opens a key ring file and loads the first available key
* suitable for encryption.
*
* @param input data stream containing the public key data
* @return the first public key found.
* @throws IOException
* @throws PGPException
*/
static PGPPublicKey readPublicKey(InputStream input) throws IOException, PGPException
{
PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(
PGPUtil.getDecoderStream(input), new JcaKeyFingerprintCalculator());
//
// we just loop through the collection till we find a key suitable for encryption, in the real
// world you would probably want to be a bit smarter about this.
//
Iterator keyRingIter = pgpPub.getKeyRings();
while (keyRingIter.hasNext())
{
PGPPublicKeyRing keyRing = (PGPPublicKeyRing)keyRingIter.next();
Iterator keyIter = keyRing.getPublicKeys();
while (keyIter.hasNext())
{
PGPPublicKey key = (PGPPublicKey)keyIter.next();
if (key.isEncryptionKey())
{
return key;
}
}
}
throw new IllegalArgumentException("Can't find encryption key in key ring.");
}
static PGPSecretKey readSecretKey(String fileName) throws IOException, PGPException
{
InputStream keyIn = new BufferedInputStream(new FileInputStream(fileName));
PGPSecretKey secKey = readSecretKey(keyIn);
keyIn.close();
return secKey;
}
/**
* A simple routine that opens a key ring file and loads the first available key
* suitable for signature generation.
*
* @param input stream to read the secret key ring collection from.
* @return a secret key.
* @throws IOException on a problem with using the input stream.
* @throws PGPException if there is an issue parsing the input stream.
*/
static PGPSecretKey readSecretKey(InputStream input) throws IOException, PGPException
{
PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(
PGPUtil.getDecoderStream(input), new JcaKeyFingerprintCalculator());
//
// we just loop through the collection till we find a key suitable for encryption, in the real
// world you would probably want to be a bit smarter about this.
//
Iterator keyRingIter = pgpSec.getKeyRings();
while (keyRingIter.hasNext())
{
PGPSecretKeyRing keyRing = (PGPSecretKeyRing)keyRingIter.next();
Iterator keyIter = keyRing.getSecretKeys();
while (keyIter.hasNext())
{
PGPSecretKey key = (PGPSecretKey)keyIter.next();
if (key.isSigningKey())
{
return key;
}
}
}
throw new IllegalArgumentException("Can't find signing key in key ring.");
}
}
secret_rsa_kleo.asc:
-----BEGIN PGP PRIVATE KEY BLOCK-----
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
=eGJl
-----END PGP PRIVATE KEY BLOCK-----
pub_rsa_kleo.asc:
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQENBF7hImoBCAC1YHtHUokERd9OqXiB0/ncVwQaqEBLdd3cxRZ0Kyd7K+OxHH5f
VCdYRWSyVANn4Z+3JjDGZFC5eAUFGWSMwVnWB6VlIW6+7UegGA2cIUAyH6fzBogs
W4hhoIVhUHXTsbUpqj2bhWj85db3GNuSnIhyu6ed0AavsnBbDooHFJYOYgXOvNqN
pq1gjbLIHvBZXZg/OvrpjSM0GoLX6bIDxofzh3ktFlBkUP1fGJ/Cx1xu1ANZ6mQq
6VF8DMcYBO08+HiQvaRkOYYI20AR5X3BOYA+UR63CiXjfvt9r2OX+GTExe3XJp8U
wkvm14JRCyad42ADOkik8fdiy4rGy0yVwe/BABEBAAG0GHRlc3QgdGVzdCA8dGVz
dEB0ZXN0LmRlPokBVAQTAQgAPhYhBOtbtDyOZRSPL5sgGfmgWzoStTgnBQJe4SJq
AhsDBQkDwfO2BQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEPmgWzoStTgnc2UH
/2cLGLIAQke/VT/Humfx0CwK9dHMgXT+BS52G43C8dzfTp1iwn31t/B/rfh9fDEx
uYT+nratO6hROME8ZzHcm6pLpyH4ZJCb35UO0KA/Eo8TN56VM69pEPzQbpc80AiF
gAQ0tLm58dAFIkMahKPfcOp5YpIw1wrfxiJkygV7e37wh9wiah/w2ho/8BawYEUG
arjoB13fYB5gNLzsmk1nd+/nMOZDaqOJXl3GhVI9i1pS5cqkT/T9WquybqW73whI
LpsSdBu9MWihhedCx6KtoDpSPrtzzXjKc7PJIjBPDN4pzH/0fqvN/k2736P1MP5z
yq/nOMOTevV6YZtN9SXA6Hq5AQ0EXuEiagEIAMN3rP9PhOm0ho14SXwjXKF/vXc+
EDT+vglwg7bZUpsJMYt5TMnT6dNHlV/ek8oMUEvBqBIHWrUplG/LFyaNJAjmgE4q
FoNHy1V9H9Jw439PH1T/8Mbw/n/k3xvanWcl03QcRcvPag8oaczYO+/+cbyl0R/X
lk2lAlBomfnM2+nfUFyTKVXJoG7TSHNRGbG3jmKyVzPi3Tb/JqbW2ITUBKkd+J6h
l5EK9NExqyXVoFHUf2KWfawXzEw9Dk83fKoDQHQkknzdQ+vm4l6MQ9m40OV7U3xd
6yd49p8h1+jpYv4bWguiWiJquAosABOF5DunpIUWel82uZ/PRCuLZpbGG38AEQEA
AYkBPAQYAQgAJhYhBOtbtDyOZRSPL5sgGfmgWzoStTgnBQJe4SJqAhsMBQkDwfO2
AAoJEPmgWzoStTgnFZ0H/3y9RhcPK65ssKjclr4gwMyquaDPqwKuXJLEZZNuapj0
G7j4AKJX6bN/RYJ3Nw51iC3vv5j5Pd4l6/d5PwZN5t54SV+T+6WPCbfbvBGn+jwj
mcE584hfwndioXjE+dVVoX4dhwkfZLOz6t825UTpKp2XEoFOeVpjTN8NhdiN5xe6
UHEUyHFBCkP9g81j1nKbgXXB6kss5r59WMIZrasVNOzh8WnAVLrTkuQC+/KZZqwi
8dseaBEeCR5vSzCZWjJULSeziiOGChn+e8CNKpgEn2QuNsWoOoaPe6wQVRoY/oxV
t4wc4dVh2W0HjzMOveo3Dvw66QT1NfXx4cmaOm5HWhc=
=bgyD
-----END PGP PUBLIC KEY BLOCK-----
"Invalid Armor"
此错误可能由于多种情况而发生。这是我的经历:
我格式化了键[加入行]而不是我应该按原样使用键。
密钥应始终采用以下文本格式。
AhsDBQkDwfO2BQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEPmgWzoStTgnc2UH /2cLGLIAQke/VT/Humfx0CwK9dHMgXT+BS52G43C8dzfTp1iwn31t/B/rfh9fDEx uYT+nratO6hROME8ZzHcm6pLpyH4ZJCb35UO0KA/Eo8TN56VM69pEPzQbpc80AiF gAQ0tLm58dAFIkMahKPfcOp5YpIw1wrfxiJkygV7e37wh9wiah/w2ho/8BawYEUG