【发布时间】:2019-08-20 13:23:01
【问题描述】:
我必须先将文件放在远程 SFTP 服务器中,然后我必须使用私钥对文件进行签名,然后他们将使用公钥对其进行验证。我从响应文件中收到“PGP 签名验证失败”错误。
所以我尝试验证来自 JAVA 的签名。不过,我从签名验证方法中得到了错误的值。
任何帮助将不胜感激。
这是我整理的代码。
公共类 SignAndVerify {
static final KeyFingerPrintCalculator FP_CALC = new BcKeyFingerprintCalculator();
private static File publicKeyFile = new File("\\publicSign.asc");
private static File privateKeyFile = new File("\\privateSign.asc");
private static final BouncyCastleProvider provider = new BouncyCastleProvider();
static {
Security.addProvider(provider);
}
public static void signFile(String fileName, PGPSecretKey secretKey, String secretPwd, boolean armor, OutputStream out)
throws PGPException {
BCPGOutputStream bOut = null;
OutputStream lOut = null;
InputStream fIn = null;
try {
OutputStream theOut = armor ? new ArmoredOutputStream(out) : out;
PGPPrivateKey pgpPrivKey = secretKey.extractPrivateKey(
new JcePBESecretKeyDecryptorBuilder().setProvider(provider).build(secretPwd.toCharArray()));
PGPSignatureGenerator sGen = new PGPSignatureGenerator(
new JcaPGPContentSignerBuilder(secretKey.getPublicKey().getAlgorithm(), PGPUtil.SHA1)
.setProvider(provider));
sGen.init(PGPSignature.BINARY_DOCUMENT, pgpPrivKey);
Iterator<String> it = secretKey.getPublicKey().getUserIDs();
if (it.hasNext()) {
PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
spGen.setSignerUserID(false, (String) it.next());
sGen.setHashedSubpackets(spGen.generate());
}
bOut = new BCPGOutputStream(theOut);
sGen.generateOnePassVersion(false).encode(bOut);
PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator();
lOut = lGen.open(bOut, PGPLiteralData.BINARY, "filename", new Date(), new byte[2048]);
fIn = new BufferedInputStream(new FileInputStream(fileName));
byte[] buf = new byte[2048];
int ch;
while ((ch = fIn.read(buf)) >= 0) {
lOut.write(ch);
sGen.update(buf, 0, ch);
}
lGen.close();
sGen.generate().encode(bOut);
theOut.close();
} catch (Exception e) {
throw new PGPException("Error in sign", e);
} finally {
try {
if (bOut != null) {
bOut.close();
}
if(lOut != null) {
lOut.close();
}
if(fIn != null) {
fIn.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static boolean verifyFile(InputStream lin, PGPPublicKey publicKey) throws PGPException {
try {
InputStream in = PGPUtil.getDecoderStream(lin);
JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(in);
/*PGPCompressedData c1 = (PGPCompressedData) pgpFact.nextObject();
pgpFact = new JcaPGPObjectFactory(c1.getDataStream());*/
PGPOnePassSignatureList p1 = (PGPOnePassSignatureList) pgpFact.nextObject();
PGPOnePassSignature ops = p1.get(0);
PGPLiteralData p2 = (PGPLiteralData) pgpFact.nextObject();
InputStream dIn = p2.getInputStream();
int ch;
ops.init(new JcaPGPContentVerifierBuilderProvider().setProvider(provider), publicKey);
while ((ch = dIn.read()) >= 0) {
ops.update((byte) ch);
}
PGPSignatureList p3 = (PGPSignatureList) pgpFact.nextObject();
return ops.verify(p3.get(0));
} catch (Exception e) {
throw new PGPException("Error in verify", e);
}
}
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<PGPSecretKeyRing> keyRingIter = pgpSec.getKeyRings();
while (keyRingIter.hasNext()) {
PGPSecretKeyRing keyRing = keyRingIter.next();
Iterator<PGPSecretKey> keyIter = keyRing.getSecretKeys();
while (keyIter.hasNext()) {
PGPSecretKey key = keyIter.next();
if (key.isSigningKey()) {
return key;
}
}
}
throw new IllegalArgumentException("Can't find signing key in key ring..");
}
private static PGPPublicKey readPublicKeyFromCol(InputStream in) throws IOException, PGPException {
PGPPublicKeyRing pkRing = null;
PGPPublicKeyRingCollection pkCol = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(in), FP_CALC);
println("key ring size=" + pkCol.size());
Iterator<PGPPublicKeyRing> it = pkCol.getKeyRings();
while (it.hasNext()) {
pkRing = it.next();
Iterator<PGPPublicKey> pkIt = pkRing.getPublicKeys();
while (pkIt.hasNext()) {
PGPPublicKey key = pkIt.next();
println("Encryption key = " + key.isEncryptionKey() + ", Master key = " + key.isMasterKey());
if (key.isEncryptionKey())
return key;
}
}
return null;
}
public static void main(String[] args) throws Exception {
println("Inside Class..");
String fileName = "\\fileToBeSigned.xml";
String secretKey = "Passphrase";
String outFileName = "\\signedFile.xml";
OutputStream out = new BufferedOutputStream(new FileOutputStream(outFileName));
InputStream lin = new BufferedInputStream(new FileInputStream(outFileName));
PGPSecretKey pgpSec = readSecretKey(new BufferedInputStream(new FileInputStream(privateKeyFile)));
signFile(fileName, pgpSec, secretKey, true, out);
PGPPublicKey encKey = readPublicKeyFromCol(new FileInputStream(publicKeyFile));
Boolean lverify = verifyFile(lin, encKey);
println("result is ::" + lverify);
out.close();
lin.close();
}
private static void println(String msg) {
System.out.println(msg);
}
}
【问题讨论】:
-
代码的哪一部分抛出了异常?
-
我没有例外。签名验证方法 (verifyFile) 返回 false 值,表示签名验证失败。对吗?
-
我在 PGPPublicKeyRingCollection pkCol = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(in), FP_CALC) 处遇到错误;在读取公钥时自行排列。错误是“java.io.IOException:流中的未知对象:47”.. 我正在使用 .asc 文件将 CSV 文件加密为 pgp 并发送它。使用的罐子如下。有人可以告诉我这里有什么问题。
bcpg-jdk15on 1.66 bcprov-jdk16 145
标签: java sign pgp verify openpgp