繁体   English   中英

使用商店中可用的证书验证文件的签名

[英]Verifying signature of a file using the certificates available in store

我是安全和签名验证的新手,到目前为止,我找不到找到解释签名验证基础知识的地方。 我需要通过从证书存储中提供的适当证书中获取公钥来验证文件的签名。 Java教程( https://docs.oracle.com/javase/tutorial/security/apisign/versig.html )没有教导如何从可信证书存储中获取证书并进行验证。 我浏览了Bouncy城​​堡WIKI http://www.bouncycastle.org/wiki/display/JA1/BC+Version+2+APIs,但是对于初学者来说,这并不是真正的解释。 我该怎么做呢? 给定已签名的文件,我如何从证书存储中检查其公钥,并验证其是否是发送文件的正确人员? 请指教。

因为您没有提供使用的构建管理,所以我假设它将是Maven。

首先,在您的依赖项中包含BouncyCastle

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.53</version>
</dependency>

之后,您需要创建一个将用于签名或验证证书的util类。 像这样:

package your.pack.location;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * Author: harunalfat
 */
public class SignatureUtils {

    private static final Logger log = LogManager.getLogger(SignatureUtils.class);


    public static String sign(String plainText, PrivateKey privateKey) throws Exception {

        byte[] data = plainText.getBytes("ISO-8859-1");

        Signature signature = Signature.getInstance("SHA1WithRSA", "BC");
        signature.initSign(privateKey);
        signature.update(data);

        return Base64.toBase64String(signature.sign());
    }

    public static boolean verify(String plainText, String signString, PublicKey publicKey) throws Exception{

        byte[] data = plainText.getBytes("ISO-8859-1");

        Signature signature = Signature.getInstance("SHA1WithRSA", "BC");
        signature.initVerify(publicKey);
        signature.update(data);

        byte[] signByte = Base64.decode(signString);
        return signature.verify(signByte);
    }

    private static PemObject getPemObjectFromResource(String fileLocation) throws IOException {

        Resource resource = new ClassPathResource(fileLocation);
        InputStream is = resource.getInputStream();

        PemObject pemObject = new PemReader(new InputStreamReader( is )).readPemObject();
        return pemObject;
    }

    private static X509EncodedKeySpec getPubKeySpec(String fileLocation) throws IOException, NoSuchAlgorithmException {

        PemObject pemObject = getPemObjectFromResource(fileLocation);
        byte[] data = pemObject.getContent();

        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(data);
        return keySpec;
    }

    private static PKCS8EncodedKeySpec getPriKeySpec(String fileLocation) throws IOException, NoSuchAlgorithmException {

        PemObject pemObject = getPemObjectFromResource(fileLocation);
        byte[] data = pemObject.getContent();

        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(data);
        return keySpec;
    }

    public static PublicKey getPublicKey(String fileLocation) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
        KeyFactory kf = KeyFactory.getInstance("RSA");
        KeySpec keySpec = getPubKeySpec(fileLocation);
        return kf.generatePublic(keySpec);
    }

    public static PrivateKey getPrivateKey(String fileLocation) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
        KeyFactory kf = KeyFactory.getInstance("RSA");
        KeySpec keySpec = getPriKeySpec(fileLocation);
        return kf.generatePrivate(keySpec);
    }
}

然后您将像这样使用它

package your.another.pack;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.tomcat.util.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.Test;
import org.mockito.MockitoAnnotations;

import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;

import static org.junit.Assert.assertTrue;

/**
 * Author: harunalfat
 */
public class SignatureUtilsTest {


    private static final Logger log = LogManager.getLogger(SignatureUtilsTest.class);
    private static final String PLAIN = "attack at dawn";

    @Test
    public void testSignAndVerify() throws Exception {
        Security.addProvider(new BouncyCastleProvider()); // <-- IMPORTANT!!! This will add BouncyCastle as provider in Java Security
        PrivateKey privateKey = SignatureUtils.getPrivateKey("key/private2.pem"); // This is located on src/main/resources/key/private2.pem 
        PublicKey publicKey = SignatureUtils.getPublicKey("key/public2.pem"); // This is located on src/main/resources/key/public2.pem 

    // In this example, I use junit test, so it will be on src/test/resources/...

        log.info("Private Key  : "+Base64.encodeBase64String(privateKey.getEncoded()));
        log.info("Public Key   : "+Base64.encodeBase64String(publicKey.getEncoded()));

        String sign = SignatureUtils.sign(PLAIN, privateKey);
        log.info("Plain String : "+PLAIN);
        log.info("Sign         : "+sign);

        boolean result = SignatureUtils.verify(PLAIN,sign, publicKey);
        log.info("Result       : "+result);

        assertTrue(result);
    }

}

当然,您可以使用其他算法来更改Signature实例。 在我的情况下,我使用"SHA1WithRSA" ,但是您明白了吗?

这样,某人将使用其私钥加密其数据,并将其发送给您。 之后,您将使用它们提供的公钥来验证数据。

例如,Bob向您发送有关他向您发送的金额( $5000 )的消息,并使用其私钥对其进行签名,从而被加密。 当数据到达您时,您知道Bob应该发送$ 5000,然后您用文本$5000和公钥Bob共享来验证加密的数据,但实际上是$5000 还是来自Bob?

如果数据已更改,或者某天您向鲍勃索要钱,但是消息被他人窃听,他/她会使用鲍勃以外的私钥向您发送金额消息。

随便问:)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM