在 JAVA 中使用 PKCS #7 签署数据

问题描述 投票:0回答:3

我想签署一个文本文件(将来可能是

.exe
文件或其他文件) 使用 PKCS#7 并使用 Java 验证签名。

  1. 我需要知道什么?
  2. 在哪里可以找到 API(
    .jar
    和文档)?
  3. 为了签署数据和验证数据,我需要遵循哪些步骤?

如果可能,请向我提供代码片段。

java cryptography pkcs#7
3个回答
15
投票

我认为您需要以下 2 个 Bouncy Castle jar 来生成 PKCS7 数字签名:

  • bcprov-jdk15on-147.jar(适用于 JDK 1.5 - JDK 1.7)

  • bcmail-jdk15on-147.jar(适用于 JDK 1.5 - JDK 1.7)

您可以从这里下载 Bouncy Castle 罐子。

您需要使用公钥和私钥对设置密钥库。 您只需要私钥来生成数字签名和公钥来验证它。

以下是 pkcs7 签名内容的方法(为简洁起见,省略了异常处理):

import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import org.bouncycastle.cert.jcajce.JcaCertStore;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.cms.CMSTypedData;
import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.bouncycastle.util.Store;
import org.bouncycastle.util.encoders.Base64;

public final class PKCS7Signer {

    private static final String PATH_TO_KEYSTORE = "/path/to/keyStore";
    private static final String KEY_ALIAS_IN_KEYSTORE = "My_Private_Key";
    private static final String KEYSTORE_PASSWORD = "MyPassword";
    private static final String SIGNATUREALGO = "SHA1withRSA";

    public PKCS7Signer() {
    }

    KeyStore loadKeyStore() throws Exception {

        KeyStore keystore = KeyStore.getInstance("JKS");
        InputStream is = new FileInputStream(PATH_TO_KEYSTORE);
        keystore.load(is, KEYSTORE_PASSWORD.toCharArray());
        return keystore;
    }

    CMSSignedDataGenerator setUpProvider(final KeyStore keystore) throws Exception {

        Security.addProvider(new BouncyCastleProvider());

        Certificate[] certchain = (Certificate[]) keystore.getCertificateChain(KEY_ALIAS_IN_KEYSTORE);

        final List<Certificate> certlist = new ArrayList<Certificate>();

        for (int i = 0, length = certchain == null ? 0 : certchain.length; i < length; i++) {
            certlist.add(certchain[i]);
        }

        Store certstore = new JcaCertStore(certlist);

        Certificate cert = keystore.getCertificate(KEY_ALIAS_IN_KEYSTORE);

        ContentSigner signer = new JcaContentSignerBuilder(SIGNATUREALGO).setProvider("BC").
                build((PrivateKey) (keystore.getKey(KEY_ALIAS_IN_KEYSTORE, KEYSTORE_PASSWORD.toCharArray())));

        CMSSignedDataGenerator generator = new CMSSignedDataGenerator();

        generator.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").
                build()).build(signer, (X509Certificate) cert));

        generator.addCertificates(certstore);

        return generator;
    }

    byte[] signPkcs7(final byte[] content, final CMSSignedDataGenerator generator) throws Exception {

        CMSTypedData cmsdata = new CMSProcessableByteArray(content);
        CMSSignedData signeddata = generator.generate(cmsdata, true);
        return signeddata.getEncoded();
    }

    public static void main(String[] args) throws Exception {

        PKCS7Signer signer = new PKCS7Signer();
        KeyStore keyStore = signer.loadKeyStore();
        CMSSignedDataGenerator signatureGenerator = signer.setUpProvider(keyStore);
        String content = "some bytes to be signed";
        byte[] signedBytes = signer.signPkcs7(content.getBytes("UTF-8"), signatureGenerator);
        System.out.println("Signed Encoded Bytes: " + new String(Base64.encode(signedBytes)));
    }
}

4
投票

PKCS#7 现在被称为 CMS(加密消息语法),您将需要 Bouncy Castle PKIX 库来创建一个。它有充足的文档和完善的邮件列表。

我不会提供代码片段,这违反了内部规则。先自己试试吧。


0
投票

对于 java 8,假设您使用 sun.security.* 类,这是可能的

import sun.security.pkcs.ContentInfo;
import sun.security.pkcs.PKCS7;
import sun.security.pkcs.SignerInfo;
import sun.security.util.DerOutputStream;
import sun.security.util.DerValue;
import sun.security.x509.AlgorithmId;
import sun.security.x509.X500Name;



X509Certificate [] certChain = ...; // all certificate chain
X509Certificate c = ...;            // first certificate

PrivateKey privateKey = ...; // private key
//Data to sign
//compute signature:
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(dataToSign);
byte[] signedData = signature.sign();

//load X500Name
X500Name xName = X500Name.asX500Name(c.getIssuerX500Principal());
//load serial number
BigInteger serial = c.getSerialNumber();
//laod digest algorithm
AlgorithmId digestAlgorithmId = new AlgorithmId(AlgorithmId.SHA256_oid);
//load signing algorithm
AlgorithmId signAlgorithmId = new AlgorithmId(AlgorithmId.RSAEncryption_oid);

//Create SignerInfo:
SignerInfo sInfo = new SignerInfo(xName, serial, digestAlgorithmId, signAlgorithmId, signedData);
//Create ContentInfo:
ContentInfo cInfo = new ContentInfo(ContentInfo.DATA_OID,
        new DerValue(DerValue.tag_OctetString, dataToSign));
//Create PKCS7 Signed data
PKCS7 p7 = new PKCS7(new AlgorithmId[]{digestAlgorithmId}, cInfo,
        certChain,
        new SignerInfo[]{sInfo});
//Write PKCS7 to bYteArray
DerOutputStream bOut = new DerOutputStream();
p7.encodeSignedData(bOut);
byte[] encodedPKCS7 = bOut.toByteArray();
© www.soinside.com 2019 - 2024. All rights reserved.