【问题标题】:How to sign and verify the file in JAVA如何在 JAVA 中对文件进行签名和验证
【发布时间】: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-jdk15on1.66bcprov-jdk16145

标签: java sign pgp verify openpgp


【解决方案1】:

首先,签名者正在寻找任何能够签名的密钥,而验证者正在寻找任何能够加密的密钥。根据您生成密钥的方式和时间,这些可能会有所不同:使用子密钥进行加密(仅)被认为是一种良好的做法,并且至少二十年来的默认设置 - 有时也用于数据签名的 不同 子密钥(仅保留用于密钥签名的主密钥,也就是仅用于“认证”)。但是从技术上讲,拥有一个具有数据签名和加密功能的 RSA 主密钥是可行的(并且还可以选择进行认证,尽管它没有被使用);在 GPG 中,这可以通过在“专家”模式下生成来完成,或者在最近的版本中通过在生成后进行编辑来完成。由于您没有向我们展示您的密钥/私钥的详细信息——除非这些是仅用于测试的密钥,否则您可以承担妥协——因此不可能告诉我们您的情况。如果您实际上使用不同的密钥来尝试签名和验证,那么它当然无法正常工作。

一般情况下,接收者应该使用消息中keyid 指定的密钥:发送者使用任何具有加密功能的公钥进行加密,在消息中标识该密钥,接收者使用私钥解密发送者选择的一半密钥;发送者使用任何具有签名能力的私钥进行签名,在消息中标识该密钥,接收者使用发送者选择的密钥的一半公钥进行验证。这将需要在读取签名包后重新组织您的代码以选择验证密钥。现在我刚刚在verifyFile 中添加了sig.getKeyID() == publicKey.getKeyID() 的检查。

这会在signFile 中留下更严重的数据处理错误

    byte[] buf = new byte[2048];
    int ch;
    while ((ch = fIn.read(buf)) >= 0) {
        lOut.write(ch);
        sGen.update(buf, 0, ch);
    }

您计算输入文件中所有数据的签名,但您将放入消息中对于每个缓冲的数据只有一个字节;请参阅OutputStream.write(int) 的 javadoc。由于验证者使用消息中的数据,该数据现在与已签名的数据完全不同,签名不应该也不应该验证。以及消息对接收者无用。而是这样做

  lOut.write(buf,0,ch);

或者像 verifyFile 那样切换到一次字节处理

  int ch; // no byte[] buf
  while( (ch = fIn.read()) >= 0 ){
    lOut.write((byte)ch); // cast not needed but clarifies intent
    sig.update((byte)ch); 
  }

【讨论】:

  • 谢谢。我改变了签名方法。现在,我在输出文件中获取签名数据。我在验证时遇到以下错误。你能告诉我我在哪里做错了吗? -------------------------------- 线程“main”java.io.IOException 中的异常:遇到未知的 PGP 公钥算法: 5 at org.bouncycastle.bcpg.PublicKeyPacket.(Unknown Source) at org.bouncycastle.bcpg.SecretKeyPacket.(Unknown Source) at org.bouncycastle.bcpg.BCPGInputStream.readPacket(Unknown Source) at org .bouncycastle.openpgp.PGPSecretKeyRing.(未知来源
  • 我发现了问题。感谢您提供宝贵的信息
猜你喜欢
  • 2020-07-11
  • 1970-01-01
  • 2020-03-13
  • 1970-01-01
  • 1970-01-01
  • 2018-11-09
  • 1970-01-01
  • 2010-10-22
  • 2016-04-28
相关资源
最近更新 更多