PKCS7 и подпись "NONEwithRSA"

Мне нужно вычислить некоторую подпись данных, используя неинкапсулированный pkcs7 с sha256 и RSA. Нет проблем с необработанным контентом, используя:

public byte[] signRawContent(final byte[] content)
    throws CMSException, IOException, OperatorCreationException, CertificateEncodingException {

    // Create generator of pkcs7-signature message
    CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
    ContentSigner signer = new JcaContentSignerBuilder("SHA256WithRSA").setProvider("BC").build(privateKey);
    generator.addSignerInfoGenerator(
        new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()).build(signer, certificate));
    generator.addCertificate(new X509CertificateHolder(certificate.getEncoded()));

    CMSTypedData cmsTypedData = new CMSProcessableByteArray(content);
    CMSSignedData cmsSignedData = generator.generate(cmsTypedData, false);
    return cmsSignedData.getEncoded();
}

Но у меня есть другие пользовательские случаи, когда у меня нет необработанного контента, только его хеш (sha256) Bouncycastle не поддерживает "NONEwithRSA" или "RSA" для подписи pkcs7, поэтому я попытался использовать собственный ContentSigner, не получив тот же подпись с версией необработанного содержимого.

public byte[] signHash(final byte[] sha256) throws IOException,
    OperatorCreationException, CertificateEncodingException, CMSException {

    // Create generator of pkcs7-signature message
    CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
    // custom content signer to bypass hash
    ContentSigner signer = new ContentSigner() {
        @Override public AlgorithmIdentifier getAlgorithmIdentifier() {
            return new DefaultSignatureAlgorithmIdentifierFinder().find("SHA256WithRSA");
        }

        @Override public OutputStream getOutputStream() {
            return new ByteArrayOutputStream();
        }

        @Override public byte[] getSignature() {
            try {
                Signature signer = Signature.getInstance("NONEwithRSA");
                signer.initSign(privateKey);
                signer.update(sha256);
                return signer.sign();
            } catch (Exception e){
            throw new RuntimeOperatorException("exception obtaining signature: " + e.getMessage(), e);
            }
        }
    };

    generator.addSignerInfoGenerator(
        new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()).build(signer, certificate));
    generator.addCertificate(new X509CertificateHolder(certificate.getEncoded()));

    CMSTypedData cmsTypedData = new CMSProcessableByteArray(sha256);
    CMSSignedData cmsSignedData = generator.generate(cmsTypedData, false);
    return cmsSignedData.getEncoded();
}

Я даже пытался перестроить дайджест контента, не повезло

 // build digest
 MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
 messageDigest.update(sha256);
 byte[] outputDigest = messageDigest.digest();
 AlgorithmIdentifier sha256Aid = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE);
 DigestInfo di = new DigestInfo(sha256Aid, outputDigest);

 //sign SHA256 with RSA
 Signature rsaSignature = Signature.getInstance("RSA");
 rsaSignature.initSign(privateKey);
 byte[] encodedDigestInfo = di.toASN1Primitive().getEncoded();
 rsaSignature.update(encodedDigestInfo);
 return rsaSignature.sign();

Так есть ли способ получить pkcs7 от sha256? Спасибо

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
743
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Нашел рабочее решение:

private static final String SIGNATURE_ALGO = "SHA256WithRSA";

/**
 * Get the pkcs7-signature from a document hash (sha256Hex)
 *
 * @param contentSha256Hex
 *     the original document content hash (sha256Hex) to be signed
 * @return the pkcs7 signature
 *
 * note: see TestSha1WithRsaAndAttributeTable() in bouncycastle/test/src/cms/test/SignedDataTest.cs
 * */
public byte[] signSha256Hex(final String contentSha256Hex)
    throws CertificateEncodingException, IOException, OperatorCreationException, CMSException, DecoderException {

    byte[] hash = Hex.decodeHex(contentSha256Hex);

    /*
     * The trick is to manually set digest attribute with hash value,
     * then generate signature without content.
     */

    // CMS attributes
    ASN1EncodableVector v = new ASN1EncodableVector();
    v.add(new Attribute(CMSAttributes.messageDigest, new DERSet(new DEROctetString(hash)))); // set digest (sha256)

    return signCms_Sha256WithRsa(
        new CMSAbsentContent(),
        new DefaultSignedAttributeTableGenerator(new AttributeTable(v)));

}

private byte[] signCms_Sha256WithRsa(CMSTypedData content, CMSAttributeTableGenerator signedAttributes)
    throws CMSException, IOException, CertificateEncodingException, OperatorCreationException {

    CMSSignedDataGenerator generator = new CMSSignedDataGenerator();

    // content signer
    ContentSigner signer = new JcaContentSignerBuilder(SIGNATURE_ALGO).setProvider("BC").build(privateKey);
    generator.addSignerInfoGenerator(
        new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").build())
            .setSignedAttributeGenerator(signedAttributes)
            .build(signer, certificate));

    // add certificate
    generator.addCertificate(new X509CertificateHolder(certificate.getEncoded()));

    // sign
    CMSSignedData cmsSignedData = generator.generate(content, false);
    return cmsSignedData.getEncoded();
}

Другие вопросы по теме