当前位置: 首页 > 知识库问答 >
问题:

使用DSS(数字签名服务)对哈希进行签名

越欣怡
2023-03-14

我正在尝试用DSS签署PDF文档,我的问题是我无法在服务器a中计算文档的哈希值,然后在服务器B中签署它。

知道服务器A包含PDF文档,我们在服务器B中检索用于签名的证书

我的问题是如何在不需要证书的情况下计算服务器a中文档的哈希值。然后在服务器B上发送签名?

更新:

******散列的准备和计算********

    IPdfObjFactory pdfObjFactory = new ServiceLoaderPdfObjFactory();
    PDFSignatureService pdfSignatureService = pdfObjFactory.newPAdESSignatureService();

    PAdESSignatureParameters parameters = new PAdESSignatureParameters();

    parameters.setDigestAlgorithm(DigestAlgorithm.SHA512);
    parameters.setReason("Preuve de signature");
    parameters.setLocation("MAROC");
    parameters.setGenerateTBSWithoutCertificate(true);

    SignatureImageParameters imageParameters = new SignatureImageParameters();

    imageParameters.setPage(1);
    FileDocument imageFile = new FileDocument("logo.png");
    RemoteDocument fileImage = RemoteDocumentConverter.toRemoteDocument(imageFile);
    DSSDocument image = RemoteDocumentConverter.toDSSDocument(fileImage);
    // set an image
    imageParameters.setImage(image);

    imageParameters.setxAxis(350);
    imageParameters.setyAxis(400);
    imageParameters.setWidth(200);
    imageParameters.setHeight(100);
    parameters.setImageParameters(imageParameters);
    SignatureImageTextParameters textParameters = new SignatureImageTextParameters();
    DSSFont font = new DSSJavaFont(Font.SERIF);
    font.setSize(16); // Specifies the text size value (the default font size is 12pt)
    textParameters.setFont(font);
    textParameters.setTextColor(Color.BLUE);

    textParameters.setSignerTextPosition(SignerTextPosition.RIGHT);
    // Specifies a horizontal alignment of a text with respect to its area
    textParameters.setSignerTextHorizontalAlignment(SignerTextHorizontalAlignment.LEFT);
    // Specifies a vertical alignment of a text block with respect to a signature field area
    textParameters.setSignerTextVerticalAlignment(SignerTextVerticalAlignment.TOP);
    imageParameters.setTextParameters(textParameters);

    FileDocument fileToSign = new FileDocument("file.pdf");
    RemoteDocument fileSign = RemoteDocumentConverter.toRemoteDocument(fileToSign);
    DSSDocument toSignDocument = RemoteDocumentConverter.toDSSDocument(fileSign);

    byte[] hash = pdfSignatureService.digest(toSignDocument, parameters);

    DSSDocument signatureValue = SignHashDocument.signHash(hash);

    DSSDocument signedDocument = pdfSignatureService.sign(toSignDocument, DSSUtils.toByteArray(signatureValue), parameters);

    save(signedDocument);

******散列签名********

     // Create common certificate verifier
    CommonCertificateVerifier commonCertificateVerifier = new CommonCertificateVerifier();
        // Create CAdESService for signature
    CAdESService service = new CAdESService(commonCertificateVerifier);

    CAdESSignatureParameters parameters = new CAdESSignatureParameters();
    DSSPrivateKeyEntry privateKey = getKey("certificate.p12","123456");


    // We choose the level of the signature (-B, -T, -LT, -LTA).
    parameters.setSignatureLevel(SignatureLevel.CAdES_BASELINE_B);
    parameters.setSignaturePackaging(SignaturePackaging.ENVELOPING);

    parameters.setDigestAlgorithm(DigestAlgorithm.SHA512);
    // We set the signing certificate
    parameters.setSigningCertificate(privateKey.getCertificate());
    // We set the certificate chain
    parameters.setCertificateChain(privateKey.getCertificateChain());


    SignatureTokenConnection signingToken = new Pkcs12SignatureToken("certificate.p12",
            new KeyStore.PasswordProtection("123456".toCharArray()));


    convertByteArrayToFile(hashToSign,"filetosign.hash");
    FileDocument fileToSign = new FileDocument("filetosign.hash");
    RemoteDocument fileSign = RemoteDocumentConverter.toRemoteDocument(fileToSign);
    DSSDocument toSignDocument = RemoteDocumentConverter.toDSSDocument(fileSign);

    //ToBeSigned dataToSign = service.getDataToSign(toSignDocument, parameters);

    ToBeSigned dataToSign = new ToBeSigned(hashToSign);

    DigestAlgorithm digestAlgorithm = parameters.getDigestAlgorithm();
    SignatureValue signatureValue = signingToken.sign(dataToSign, digestAlgorithm, privateKey);

    DSSDocument signedDocument = service.signDocument(toSignDocument, parameters, signatureValue);

    return  signedDocument;

********PDF错误:*********

共有3个答案

长孙阳泽
2023-03-14

这是可能的,在这里可以看到一个完整的开源实现https://github.com/eideasy/eideasy-external-pades-digital-signatures

您需要以签名后的格式创建PDF,删除所有签名,然后计算哈希。

在得到凯德的签名后,只需将此添加到拜特兰奇。这将为您提供基线-T签名。

对于基线LT,您需要添加带有所有已使用证书、OCSP响应和CRL的DSS。

如果有更多问题,请使用我个人资料中的详细信息与我联系。

以下是完整应用程序中最重要的部分,它将为您计算要签名的摘要。计算摘要时,signatureBytes可以是新字节[0]。

    public byte[] signDetached(SignatureParameters parameters, PDDocument document, byte[] signatureBytes, OutputStream out)
        throws IOException, NoSuchAlgorithmException {

    if (document.getDocumentId() == null) {
        document.setDocumentId(parameters.getSignatureTime());
    }

    PDSignature signature = createSignatureDictionary(parameters);
    SignatureOptions options = new SignatureOptions();

    // Enough room for signature, timestamp and OCSP for baseline-LT profile.
    options.setPreferredSignatureSize(SignatureOptions.DEFAULT_SIGNATURE_SIZE * 2);
    document.addSignature(signature, options);
    ExternalSigningSupport externalSigning = document.saveIncrementalForExternalSigning(out);

    byte[] dataToSign = IOUtils.toByteArray(externalSigning.getContent());
    final MessageDigest digest = MessageDigest.getInstance("SHA-256");
    byte[] digestBytes = digest.digest(dataToSign);

    if (signatureBytes != null) {
        externalSigning.setSignature(signatureBytes);
    }

    return digestBytes;
}

private PDSignature createSignatureDictionary(final SignatureParameters parameters) {
    PDSignature signature = new PDSignature();

    signature.setType(COSName.getPDFName("Sig"));
    signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
    signature.setSubFilter(PDSignature.SUBFILTER_ETSI_CADES_DETACHED);

    if (notEmpty(parameters.getSignerName())) {
        signature.setName(parameters.getSignerName());
    }

    if (notEmpty(parameters.getContactInfo())) {
        signature.setContactInfo(parameters.getContactInfo());
    }

    if (notEmpty(parameters.getLocation())) {
        signature.setLocation(parameters.getLocation());
    }

    if (notEmpty(parameters.getReason())) {
        signature.setReason(parameters.getReason());
    }

    // the signing date, needed for valid signature
    final Calendar cal = Calendar.getInstance();
    final Date signingDate = new Date(parameters.getSignatureTime());
    cal.setTime(signingDate);
    signature.setSignDate(cal);

    return signature;
}
谷梁波
2023-03-14

在对github dss esig存储库进行了一些研究后,我找到了一个似乎正确的解决方案:

********************* 服务器A **********************

public class ServerA {
private static PAdESSignatureParameters signatureParameters;
private static DSSDocument documentToSign;
public static ExternalCMSPAdESService service;


public static void main(String[] args) throws Exception {
    documentToSign = new FileDocument(new File("file.pdf"));

    signatureParameters = new PAdESSignatureParameters();
    signatureParameters.setSignatureLevel(SignatureLevel.PAdES_BASELINE_B);
    signatureParameters.setLocation("Luxembourg");
    signatureParameters.setReason("DSS testing");
    signatureParameters.setContactInfo("Jira");
    signatureParameters.setGenerateTBSWithoutCertificate(true);

    service = new ExternalCMSPAdESService(getOfflineCertificateVerifier());
    byte[] documentDigest = computeDocumentDigest(documentToSign, signatureParameters);

    // Embedded CAdES is generated by a third party
    byte[] cmsSignedData = ServerB.getSignedCMSignedData(documentDigest);

    service.setCmsSignedData(cmsSignedData);
    DSSDocument finalDoc = service.signDocument(documentToSign, signatureParameters, null);

    save(finalDoc);
}

private static void save(DSSDocument signedDocument) {
    try (FileOutputStream fos = new FileOutputStream("DSS.pdf")) {
        Utils.copy(signedDocument.openStream(), fos);
    } catch (Exception e) {
        Alert alert = new Alert(Alert.AlertType.ERROR, "Unable to save file : " + e.getMessage(), ButtonType.CLOSE);
        alert.showAndWait();
        return;
    }
}

public static CertificateVerifier getOfflineCertificateVerifier() {
    CertificateVerifier cv = new CommonCertificateVerifier();
    cv.setDataLoader(new IgnoreDataLoader());
    return cv;
}

protected static byte[] computeDocumentDigest(final DSSDocument toSignDocument, final PAdESSignatureParameters parameters) {
    IPdfObjFactory pdfObjFactory = new ServiceLoaderPdfObjFactory();
    final PDFSignatureService pdfSignatureService = pdfObjFactory.newPAdESSignatureService();
    return pdfSignatureService.digest(toSignDocument, parameters);
}

private static class ExternalCMSPAdESService extends PAdESService {

    private static final long serialVersionUID = -2003453716888412577L;

    private byte[] cmsSignedData;

    public ExternalCMSPAdESService(CertificateVerifier certificateVerifier) {
        super(certificateVerifier);
    }

    @Override
    protected byte[] generateCMSSignedData(final DSSDocument toSignDocument, final PAdESSignatureParameters parameters,
                                           final SignatureValue signatureValue) {
        if (this.cmsSignedData == null) {
            throw new NullPointerException("A CMS signed data must be provided");
        }
        return this.cmsSignedData;
    }

    public void setCmsSignedData(final byte[] cmsSignedData) {
        this.cmsSignedData = cmsSignedData;
    }

}
}

并且能够对计算出的哈希进行签名:

********************* B服务器 **********************

public class ServerB {

private static PAdESSignatureParameters signatureParameters;
private static DSSDocument documentToSign;
public static ExternalCMSPAdESService service;

/**
 * Computes a CAdES with specific things for PAdES
 */
public static byte[] getSignedCMSignedData(byte[] documentDigest) throws Exception {
    signatureParameters = new PAdESSignatureParameters();
    signatureParameters.setSigningCertificate(getSigningCert());
    signatureParameters.setCertificateChain(getCertificateChain());
    signatureParameters.setSignatureLevel(SignatureLevel.PAdES_BASELINE_B);
    signatureParameters.setLocation("Luxembourg");
    signatureParameters.setReason("DSS testing");
    signatureParameters.setContactInfo("Jira");

    CMSProcessableByteArray content = new CMSProcessableByteArray(documentDigest);

    PadesCMSSignedDataBuilder padesCMSSignedDataBuilder = new PadesCMSSignedDataBuilder(getOfflineCertificateVerifier());
    SignatureAlgorithm signatureAlgorithm = signatureParameters.getSignatureAlgorithm();

    CustomContentSigner customContentSigner = new CustomContentSigner(signatureAlgorithm.getJCEId());
    SignerInfoGeneratorBuilder signerInfoGeneratorBuilder = padesCMSSignedDataBuilder.getSignerInfoGeneratorBuilder(signatureParameters, documentDigest);

    CMSSignedDataGenerator generator = padesCMSSignedDataBuilder.createCMSSignedDataGenerator(signatureParameters, customContentSigner,
            signerInfoGeneratorBuilder, null);

    CMSUtils.generateDetachedCMSSignedData(generator, content);

    SignatureTokenConnection signingToken = new Pkcs12SignatureToken("certificate.p12",
            new KeyStore.PasswordProtection("123456".toCharArray()));
    DSSPrivateKeyEntry privateKey = getKey("certificate.p12","123456");

    SignatureValue signatureValue = signingToken.sign(new ToBeSigned(customContentSigner.getOutputStream().toByteArray()),
            signatureParameters.getDigestAlgorithm(), privateKey);

    customContentSigner = new CustomContentSigner(signatureAlgorithm.getJCEId(), signatureValue.getValue());
    generator = padesCMSSignedDataBuilder.createCMSSignedDataGenerator(signatureParameters, customContentSigner, signerInfoGeneratorBuilder, null);

    CMSSignedData cmsSignedData = CMSUtils.generateDetachedCMSSignedData(generator, content);
    return DSSASN1Utils.getDEREncoded(cmsSignedData);
}

public static CertificateVerifier getOfflineCertificateVerifier() {
    CertificateVerifier cv = new CommonCertificateVerifier();
    cv.setDataLoader(new IgnoreDataLoader());
    return cv;
}

public static List<CertificateToken> getCertificateChain() throws Exception {
    List<CertificateToken> list = new ArrayList<>();
    CertificateToken[] l = getKey("certificate.p12","123456").getCertificateChain();
    for (int i = 0; i < l.length; i++) {
        list.add(l[i]);
    }
    return list;
}

public static CertificateToken getSigningCert() throws Exception {
    return getKey("certificate.p12","123456").getCertificate();
}

public static DSSPrivateKeyEntry getKey(String certificate, String pin) throws Exception {
    try (Pkcs12SignatureToken signatureToken = new Pkcs12SignatureToken("certificate.p12",
            new KeyStore.PasswordProtection("123456".toCharArray()))) {
        List<DSSPrivateKeyEntry> keys = signatureToken.getKeys();
        KSPrivateKeyEntry dssPrivateKeyEntry = (KSPrivateKeyEntry) keys.get(0);
        DSSPrivateKeyEntry entry = signatureToken.getKey(dssPrivateKeyEntry.getAlias(),
                new KeyStore.PasswordProtection("123456".toCharArray()));
        return entry;
    }
}
private static class ExternalCMSPAdESService extends PAdESService {

    private static final long serialVersionUID = -2003453716888412577L;

    private byte[] cmsSignedData;

    public ExternalCMSPAdESService(CertificateVerifier certificateVerifier) {
        super(certificateVerifier);
    }

    @Override
    protected byte[] generateCMSSignedData(final DSSDocument toSignDocument, final PAdESSignatureParameters parameters,
                                           final SignatureValue signatureValue) {
        if (this.cmsSignedData == null) {
            throw new NullPointerException("A CMS signed data must be provided");
        }
        return this.cmsSignedData;
    }

    public void setCmsSignedData(final byte[] cmsSignedData) {
        this.cmsSignedData = cmsSignedData;
    }

}
}
马淇
2023-03-14

这是对你问题的最初修改的回应。

你的密码提到了帕德斯。因此,当你说你试图用DSS签署PDF文档时,我假设你指的是集成的PAdES(而不是分离的CAdES或XAdES)签名。

创建集成的PDF签名(如PAdES)首先需要准备PDF能够携带嵌入式签名,即向现有或新的签名字段添加签名字典。这个签名字典包含多个信息,签名时间,签名原因等。,还有一个用于稍后嵌入CMS签名容器的占位符。然后这个准备好的PDF(占位符除外)被散列。

此外,您的代码提到您选择签名的级别(-B、-T、-LT、-LTA)。

创建PAdES Baseline LT和PAdES Baseline LTA签名需要准备一份带有PAdES Baseline T签名的PDF,并根据T签名的性质添加一组其他对象。

eSig DSS可以为您做所有这些准备,如果它有PDF准备。

因此,如果您只想将哈希值从服务器a发送到服务器B,那么您必须在服务器a上使用eSig DSS来完成大部分工作,而服务器B只充当一个哑签名服务,返回一个已签名的哈希值,或者最多是一个可用于PADE的CMS容器。

您是否可以在服务器不知道证书的情况下执行此操作,取决于您是否希望新签名的签名小部件中显示证书详细信息。创建小部件外观是PDF准备步骤的一部分,因此,如果您想要这样一个带有证书信息的小部件,服务器a需要知道证书,通常甚至在请求签名之前!

那么你在服务器A和服务器B之间运行什么样的协议取决于你。你只需要相应地实现SignatureTokenConnection,就可以在eSig DSS中的服务器A上使用它来与服务器B通信。

现在展示了来自两个服务器的代码后,可以讨论您的具体方法。

在服务器A上,您使用eSig DSS准备PAdES签名,并用SignatureValue您的SignHashDocument嵌入CMS签名容器。signHash调用返回:

ToBeSigned dataToSign = service.getDataToSign(toSignDocument, parameters);

SignatureValue signatureValue = SignHashDocument.signHash(dataToSign);

DSSDocument signedDocument = service.signDocument(toSignDocument, parameters, signatureValue);

也就是说,服务器A创建CMS签名容器,而服务器B只提供签名的散列。

除非您知道用于签名的证书,并在服务之前的参数中设置它,否则这无法工作。getDataToSign呼叫。

原因是CMS容器在容器的无符号字节和(对于PAdES)有符号字节中包含对该证书的引用。对于无符号字节中的引用,理论上只要检索证书和签名字节就足够了,但是对于有符号字节中的引用,必须事先知道。

或者,您可以尝试在服务器B上实现CMS容器的完整生成。

不过,这需要进行相当大的更改,您必须深入了解PAdESService源代码。除了服务器A上面引用的三行代码外,您还必须:

>

IPdfObjFactory pdfObjFactory = new ServiceLoaderPdfObjFactory();
PDFSignatureService pdfSignatureService = pdfObjFactory.newPAdESSignatureService();

第一次准备PDF进行签名并计算文件摘要,

byte[] hash = pdfSignatureService.digest(toSignDocument, parameters);

将此文档摘要发送到后端(服务器B),后端必须创建并返回一个特殊的CAdES签名容器,而不仅仅是裸签名字节,

第二次准备PDF进行签名,并注入此签名容器:

DSSDocument signature = pdfSignatureService.sign(toSignDocument, encodedData, parameters);

以下是使用eSig DSS 5.8的概念证明:

在服务器A上,我们基本上可以使用您现有的代码:

DSSDocument toSignDocument = PDF_DOCUMENT_TO_SIGN;
DSSDocument image = IMAGE_DOCUMENT;


PAdESSignatureParameters parameters = new PAdESSignatureParameters();
parameters.setDigestAlgorithm(DigestAlgorithm.SHA512);
parameters.setReason("Preuve de signature");
parameters.setLocation("MAROC");
parameters.setGenerateTBSWithoutCertificate(true);

SignatureImageParameters imageParameters = new SignatureImageParameters();
imageParameters.setPage(1);
imageParameters.setImage(image);
imageParameters.setxAxis(350);
imageParameters.setyAxis(400);
imageParameters.setWidth(200);
imageParameters.setHeight(100);
parameters.setImageParameters(imageParameters);

SignatureImageTextParameters textParameters = new SignatureImageTextParameters();
DSSFont font = new DSSJavaFont(Font.SERIF);
font.setSize(16);
textParameters.setFont(font);
textParameters.setTextColor(Color.BLUE);
textParameters.setSignerTextPosition(SignerTextPosition.RIGHT);
textParameters.setSignerTextHorizontalAlignment(SignerTextHorizontalAlignment.LEFT);
textParameters.setSignerTextVerticalAlignment(SignerTextVerticalAlignment.TOP);
textParameters.setText("TESTING");
imageParameters.setTextParameters(textParameters);


IPdfObjFactory pdfObjFactory = new ServiceLoaderPdfObjFactory();
PDFSignatureService pdfSignatureService = pdfObjFactory.newPAdESSignatureService();

byte[] hash = pdfSignatureService.digest(toSignDocument, parameters);

byte[] signatureValue = signHash(hash);

DSSDocument signedDocument = pdfSignatureService.sign(toSignDocument, signatureValue, parameters);


signedDocument.save(PATH_TO_SAVE_THE_SIGNED_DOCUMENT_TO);

(SplitPAdESSigning测试testSplitPAdESGenerationForMehdi

现在,signHash方法应为给定的文档散列独立创建一个CMS签名容器,该容器应符合PAdES要求。eSig DSS包含提供此功能的方法和类,但它们受保护,甚至不太可见。因此,对于我们的POC,我们只需将它们复制到我们的代码中。

为了简单起见,我使用带有RSA的硬编码SHA512作为签名算法。

因此:

byte[] signHash(byte[] hash) throws IOException {
    Pkcs12SignatureToken signingToken = new Pkcs12SignatureToken(YOUR_P12_DATA);
    DSSPrivateKeyEntry privateKey = signingToken.getKey(YOUR_ALIAS);

    CommonCertificateVerifier commonCertificateVerifier = new CommonCertificateVerifier();
    padesCMSSignedDataBuilder = new PadesCMSSignedDataBuilder(commonCertificateVerifier);

    PAdESSignatureParameters parameters = new PAdESSignatureParameters();
    parameters.setDigestAlgorithm(DigestAlgorithm.SHA512);
    parameters.setEncryptionAlgorithm(EncryptionAlgorithm.RSA);
    parameters.setSignatureLevel(SignatureLevel.PAdES_BASELINE_B);
    parameters.setSigningCertificate(privateKey.getCertificate());

    ToBeSigned dataToSign = getDataToSign(hash, parameters);
    SignatureValue signatureValue = signingToken.sign(dataToSign, DigestAlgorithm.SHA512, privateKey);
    return generateCMSSignedData(hash, parameters, signatureValue);
}

PadesCMSSignedDataBuilder padesCMSSignedDataBuilder;

(劈裂法)

帮助器方法getDataToSign和GenerateCMSSignedData基本上是从PAdESService复制的;它们使用signHash提供的padesCMSSignedDataBuilder(您也可以使其成为这两个方法的另一个参数,而不是成员变量):

/** @see eu.europa.esig.dss.pades.signature.PAdESService#getDataToSign(DSSDocument, PAdESSignatureParameters) */
public ToBeSigned getDataToSign(byte[] messageDigest, final PAdESSignatureParameters parameters) throws DSSException {
    final SignatureAlgorithm signatureAlgorithm = parameters.getSignatureAlgorithm();
    final CustomContentSigner customContentSigner = new CustomContentSigner(signatureAlgorithm.getJCEId());

    SignerInfoGeneratorBuilder signerInfoGeneratorBuilder = padesCMSSignedDataBuilder.getSignerInfoGeneratorBuilder(parameters, messageDigest);

    final CMSSignedDataGenerator generator = padesCMSSignedDataBuilder.createCMSSignedDataGenerator(parameters, customContentSigner,
            signerInfoGeneratorBuilder, null);

    final CMSProcessableByteArray content = new CMSProcessableByteArray(messageDigest);

    CMSUtils.generateDetachedCMSSignedData(generator, content);

    final byte[] dataToSign = customContentSigner.getOutputStream().toByteArray();
    return new ToBeSigned(dataToSign);
}

/** @see eu.europa.esig.dss.pades.signature.PAdESService#generateCMSSignedData(DSSDocument, PAdESSignatureParameters, SignatureValue) */
protected byte[] generateCMSSignedData(byte[] messageDigest, final PAdESSignatureParameters parameters,
        final SignatureValue signatureValue) {
    final SignatureAlgorithm signatureAlgorithm = parameters.getSignatureAlgorithm();
    final SignatureLevel signatureLevel = parameters.getSignatureLevel();
    Objects.requireNonNull(signatureAlgorithm, "SignatureAlgorithm cannot be null!");
    Objects.requireNonNull(signatureLevel, "SignatureLevel must be defined!");
    
    final CustomContentSigner customContentSigner = new CustomContentSigner(signatureAlgorithm.getJCEId(), signatureValue.getValue());
    
    final SignerInfoGeneratorBuilder signerInfoGeneratorBuilder = padesCMSSignedDataBuilder.getSignerInfoGeneratorBuilder(parameters, messageDigest);
    
    final CMSSignedDataGenerator generator = padesCMSSignedDataBuilder.createCMSSignedDataGenerator(parameters, customContentSigner,
    signerInfoGeneratorBuilder, null);
    
    final CMSProcessableByteArray content = new CMSProcessableByteArray(messageDigest);
    CMSSignedData data = CMSUtils.generateDetachedCMSSignedData(generator, content);

    return DSSASN1Utils.getDEREncoded(data);
}

(拆分识别方法)

由于可见性受限,将类PadesCMSignedDataBuilderPAdESLevelBaselineB复制到:

/** @see eu.europa.esig.dss.cades.signature.CMSSignedDataBuilder */
class PadesCMSSignedDataBuilder extends CMSSignedDataBuilder {
    public PadesCMSSignedDataBuilder(CertificateVerifier certificateVerifier) {
        super(certificateVerifier);
    }

    @Override
    protected CMSSignedDataGenerator createCMSSignedDataGenerator(CAdESSignatureParameters parameters, ContentSigner contentSigner, SignerInfoGeneratorBuilder signerInfoGeneratorBuilder,
            CMSSignedData originalSignedData) throws DSSException {

        return super.createCMSSignedDataGenerator(parameters, contentSigner, signerInfoGeneratorBuilder, originalSignedData);
    }

    protected SignerInfoGeneratorBuilder getSignerInfoGeneratorBuilder(final PAdESSignatureParameters parameters, final byte[] messageDigest) {
        final CAdESLevelBaselineB cadesLevelBaselineB = new CAdESLevelBaselineB(true);
        final PAdESLevelBaselineB padesProfileB = new PAdESLevelBaselineB();

        final DigestCalculatorProvider digestCalculatorProvider = new BcDigestCalculatorProvider();

        SignerInfoGeneratorBuilder signerInfoGeneratorBuilder = new SignerInfoGeneratorBuilder(digestCalculatorProvider);

        signerInfoGeneratorBuilder = signerInfoGeneratorBuilder.setSignedAttributeGenerator(new CMSAttributeTableGenerator() {
            @Override
            public AttributeTable getAttributes(@SuppressWarnings("rawtypes") Map params) throws CMSAttributeTableGenerationException {
                return padesProfileB.getSignedAttributes(params, cadesLevelBaselineB, parameters, messageDigest);
            }
        });

        signerInfoGeneratorBuilder = signerInfoGeneratorBuilder.setUnsignedAttributeGenerator(new CMSAttributeTableGenerator() {
            @Override
            public AttributeTable getAttributes(@SuppressWarnings("rawtypes") Map params) throws CMSAttributeTableGenerationException {
                return padesProfileB.getUnsignedAttributes();
            }
        });

        return signerInfoGeneratorBuilder;
    }
}

/** @see eu.europa.esig.dss.pades.signature.PAdESLevelBaselineB */
class PAdESLevelBaselineB {
    AttributeTable getSignedAttributes(@SuppressWarnings("rawtypes") Map params, 
            CAdESLevelBaselineB cadesProfile, PAdESSignatureParameters parameters, byte[] messageDigest) {
        AttributeTable signedAttributes = cadesProfile.getSignedAttributes(parameters);

        if (signedAttributes.get(CMSAttributes.contentType) == null) {
            ASN1ObjectIdentifier contentType = (ASN1ObjectIdentifier) params.get(CMSAttributeTableGenerator.CONTENT_TYPE);
            if (contentType != null) {
                signedAttributes = signedAttributes.add(CMSAttributes.contentType, contentType);
            }
        }

        if (signedAttributes.get(CMSAttributes.messageDigest) == null) {
            signedAttributes = signedAttributes.add(CMSAttributes.messageDigest, new DEROctetString(messageDigest));
        }

        return signedAttributes;
    }

    AttributeTable getUnsignedAttributes() {
        return null;
    }
}

(拆分助手类)

signHash及其助手不依赖于服务器A代码,因此也可以位于服务器B上。

 类似资料:
  • 我使用OpenSSL创建了一个自签名证书,如下所示: 然后,我在C#.NET4.0中编写了以下代码: 使用一些文章和答案中的解决方案,我有类,我试图在其中实现和注册签名描述: 我已经验证了hash的长度为字节,它返回一个。但是如果我使用var(20字节长),尽管中指定的算法是,但它可以工作,并使用算法对哈希进行签名。 另外,如果我打印,它的值是http://www.w3.org/2000/09/x

  • 我正在使用iText7执行PDF和签名操作。我的场景是,我在本地机器上计算哈希,并将这个哈希发送到签名服务器,作为响应,得到签名的PKCS1(原始签名),然后我将这个签名嵌入到PDF中。我的代码片段如下: 1:从智能卡设备读取公共证书。 3:初始化PdfSigner并设置签名外观: 4:我已经实现了IExternalSignatureContainer接口来获取文档哈希: 5:获取文档哈希: 7:

  • 问题开始于,输出是不同的。以下变量和的内容错误。 有人设法做到了吗?任何帮助都将不胜感激。

  • Im使用OpenSSL的< code>dgst命令执行ECDSA签名,如下所示: 然而,我在这个SO答案中读到,它首先对data_file进行SHA256哈希处理,ASN.1在签名之前对哈希进行编码。 我想创建数据的SHA256哈希,并让ECDSA只对该哈希的原始字节进行签名。(由于这是ECDSA签名,我不能使用如上述SO答案中所述。) 如何使用OpenSSL实现这一点?

  • 我正在尝试通过签名服务签署一个pdf文件。这个服务需要发送一个十六进制编码的SHA256摘要,作为回报,我会收到一个十六进制编码的SignatureValue。此外,我还收到了签名证书、中间证书、OCSP响应和TimeStampToken。但是,我在尝试使用SignatureValue对pdf进行签名时已经陷入了困境。 我读过布鲁诺的白皮书,过度浏览互联网,尝试了很多不同的方式,但签名不断出现无效

  • 您好,我可以使用iText 5对PDF文档进行数字签名。我需要再次签署PDF,而在验证PDF时,它表明初始签名无效。您可以在此处查看再次签名的文件。 请参见下面用于标记的代码, 请让我知道出了什么问题。