Как мне создать SignerInfoGenerator в Bouncy Castle, используя pqc-алгоритмы (XMSS, XMSSMT, ...)? - PullRequest
0 голосов
/ 12 апреля 2019

Я хочу создать SignerInfoGenerator (пакет org.bouncycastle.cms) с использованием постквантовых сертификатов / алгоритмов.

У меня есть работающий код для RSA, но я не могу заставить его работать, например, с XMSSMT. Программа генерирует исключение java.lang.NullPointerException (полный пример см. Ниже).

Я проверил исходный код Bouncy Castle и обнаружил проблему в строке 64 SignerInfoGenerator.java.

this.digester = digesterProvider.get(digAlgFinder.find(signer.getAlgorithmIdentifier()));

digAlgFinder.find (...) не может использовать AlgorithmIdentifier pqc-алгоритма.

(пожалуйста, поправьте меня, если я ошибаюсь)

Здесь пример выполнения (для RSA) / не работает (для XMSSMT):

public static void main(String[] args) throws OperatorCreationException, CertificateException, IOException,
        NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {

    // RSA
    //String algorithmName = "RSA";
    //String signatureAlgorithmName = "SHA256withRSA";
    //String provider = "BC";

    // XMSSMT
    String algorithmName = "XMSSMT";
    String signatureAlgorithmName = "SHA256withXMSSMT";
    String provider = "BCPQC";

    // code used by both RSA and XMSSMT
    if (Security.getProvider("BC") == null) {
        Security.addProvider(new BouncyCastleProvider());
    }
    if (Security.getProvider("BCPQC") == null) {
        Security.addProvider(new BouncyCastlePQCProvider());
    }

    KeyPair keyPair = createKeyPair(algorithmName);
    PrivateKey privateKey = (PrivateKey) keyPair.getPrivate();
    X509Certificate cert = createCertificate(keyPair, signatureAlgorithmName); // OperatorCreationException,
                                                                                // CertificateException, IOException

    JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder(signatureAlgorithmName);
    contentSignerBuilder.setProvider(provider);
    ContentSigner contentSigner = contentSignerBuilder.build(privateKey); // OperatorCreationException

    JcaDigestCalculatorProviderBuilder calculatorProviderBuilder = new JcaDigestCalculatorProviderBuilder();
    calculatorProviderBuilder.setProvider(provider);

    DigestCalculatorProvider digestCalculatorProvider = calculatorProviderBuilder.build(); // OperatorCreationException

    JcaSignerInfoGeneratorBuilder builder = new JcaSignerInfoGeneratorBuilder(digestCalculatorProvider);

    SignerInfoGenerator signerInfoGenerator = builder.build(contentSigner, cert); // CertificateEncodingException |
                                                                                    // OperatorCreationException
}

Последняя строка не работает с XMSSMT и приводит к

Exception in thread "main" java.lang.NullPointerException
    at org.bouncycastle.jcajce.util.MessageDigestUtils.getDigestName(MessageDigestUtils.java:59)
    at org.bouncycastle.operator.jcajce.OperatorHelper.createDigest(OperatorHelper.java:344)
    at org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder$1.get(JcaDigestCalculatorProviderBuilder.java:51)
    at org.bouncycastle.cms.SignerInfoGenerator.<init>(SignerInfoGenerator.java:82)
    at org.bouncycastle.cms.SignerInfoGenerator.<init>(SignerInfoGenerator.java:48)
    at org.bouncycastle.cms.SignerInfoGeneratorBuilder.createGenerator(SignerInfoGeneratorBuilder.java:138)
    at org.bouncycastle.cms.SignerInfoGeneratorBuilder.build(SignerInfoGeneratorBuilder.java:96)
    at org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder.build(JcaSignerInfoGeneratorBuilder.java:72)
    at org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder.build(JcaSignerInfoGeneratorBuilder.java:84)
    at xx.Test.main(Test.java:81)

Добавление этих двух кодов дает вам работающий пример, но они не важны:

public static KeyPair createKeyPair(String algorithmName)
        throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {
    String provider;
    if (algorithmName == "XMSSMT") {
        if (Security.getProvider("BCPQC") == null) {
            Security.addProvider(new BouncyCastlePQCProvider());
        }
        provider = "BCPQC";
    } else {
        if (Security.getProvider("BC") == null) {
            Security.addProvider(new BouncyCastleProvider());
        }
        provider = "BC";
    }
    KeyPairGenerator keygen = KeyPairGenerator.getInstance(algorithmName, provider); // NoSuchAlgorithmException |
                                                                                        // NoSuchProviderException
    if (algorithmName == "XMSSMT") {
        XMSSMTParameterSpec bcSpec = new XMSSMTParameterSpec(10, 5, XMSSMTParameterSpec.SHA256);
        keygen.initialize(bcSpec, new SecureRandom()); // InvalidAlgorithmParameterException
    } else if (algorithmName == "RSA") {
        keygen.initialize(1028, new SecureRandom());
    }
    return keygen.generateKeyPair();
}

(в основном из Самоподписанный сертификат X509 с Bouncy Castle на Java )

public static X509Certificate createCertificate(KeyPair keypair, String signatureAlgorithmName)
        throws IOException, OperatorCreationException, CertificateException {
    SecureRandom random = new SecureRandom();
    X500Name subject = new X500NameBuilder(BCStyle.INSTANCE).addRDN(BCStyle.CN, "xxx.com").build();
    byte[] id = new byte[20];
    random.nextBytes(id);
    BigInteger serial = new BigInteger(160, random);
    X509v3CertificateBuilder certificate = new JcaX509v3CertificateBuilder(subject, serial,
            Date.from(LocalDate.of(2000, 1, 1).atStartOfDay(ZoneOffset.UTC).toInstant()),
            Date.from(LocalDate.of(2035, 1, 1).atStartOfDay(ZoneOffset.UTC).toInstant()), subject,
            keypair.getPublic());
    certificate.addExtension(Extension.subjectKeyIdentifier, false, id);
    certificate.addExtension(Extension.authorityKeyIdentifier, false, id);
    BasicConstraints constraints = new BasicConstraints(true);
    certificate.addExtension(Extension.basicConstraints, true, constraints.getEncoded());
    KeyUsage usage = new KeyUsage(KeyUsage.keyCertSign | KeyUsage.digitalSignature);
    certificate.addExtension(Extension.keyUsage, false, usage.getEncoded());
    ExtendedKeyUsage usageEx = new ExtendedKeyUsage(
            new KeyPurposeId[] { KeyPurposeId.id_kp_serverAuth, KeyPurposeId.id_kp_clientAuth });
    certificate.addExtension(Extension.extendedKeyUsage, false, usageEx.getEncoded());
    ContentSigner signer = new JcaContentSignerBuilder(signatureAlgorithmName).build(keypair.getPrivate());
    X509CertificateHolder holder = certificate.build(signer);
    JcaX509CertificateConverter converter = new JcaX509CertificateConverter();
    converter.setProvider(new BouncyCastleProvider());
    return converter.getCertificate(holder);
}

Как мне создать SignerInfoGenerator с помощью pqc-алгоритмов?

Спасибо за помощь: -)

...