JAVA中如何对文件进行签名和验证

我必须在远程 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];


        }



紫衣仙女
浏览 204回答 1
1回答

慕桂英3389331

首先,签名者正在寻找任何可签名的密钥,而验证者正在寻找任何可加密的密钥。根据您生成密钥的方式和时间,这些可能不相同:使用子密钥进行加密(仅)被认为是一种好的做法,并且至少二十年来都是默认设置——有时也一个不同的用于数据签名的子密钥(仅保留用于密钥签名的主密钥,也称为“仅认证”)。但是从技术上讲,拥有一个具有数据签名和加密功能的 RSA 主密钥是可能的(并且还可以选择进行认证,尽管它未被使用);在 GPG 中,这可以通过在“专家”模式下生成来完成,或者在最新版本中通过生成后编辑来完成。由于您没有向我们展示您的秘密/私钥的详细信息 - 除非这些是仅测试密钥,否则您不应该向我们展示您可以妥协 - 不可能告诉您的情况。如果您实际上使用不同的密钥来尝试签名和验证,那么它当然永远无法正常工作。一般来说,接收方应使用消息中keyid 指定的密钥:发送方使用任何具有加密能力的公钥进行加密,在消息中识别该密钥,接收方使用发送方选择的密钥的一半私钥进行解密;发送方使用任何可签名的私钥进行签名,在消息中识别该密钥,接收方使用发送方选择的密钥的一半公钥进行验证。这将需要重新组织您的代码以仅在读取签名包后选择验证密钥。现在我只是在其中添加了一张verifyFile支票sig.getKeyID() == publicKey.getKeyID()。这在您的数据处理中留下了更严重的错误signFile&nbsp; &nbsp;byte[] buf = new byte[2048];&nbsp; &nbsp; int ch;&nbsp; &nbsp; while ((ch = fIn.read(buf)) >= 0) {&nbsp; &nbsp; &nbsp; &nbsp; lOut.write(ch);&nbsp; &nbsp; &nbsp; &nbsp; sGen.update(buf, 0, ch);&nbsp; &nbsp; }您计算输入文件中所有数据的签名,但您只为每个缓冲数据在消息中放入一个字节;请参阅 javadoc OutputStream.write(int)。由于验证者使用消息中的数据,该数据现在与已签名的数据完全不同,签名不应该也不会验证。以及消息对接收者无用。相反做&nbsp; lOut.write(buf,0,ch);或者像你一样切换到一次一个字节的处理verifyFile&nbsp; int ch; // no byte[] buf&nbsp; while( (ch = fIn.read()) >= 0 ){&nbsp; &nbsp; lOut.write((byte)ch); // cast not needed but clarifies intent&nbsp; &nbsp; sig.update((byte)ch);&nbsp;&nbsp; }
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java