从KeyStore检索SecretKey后,Bouncy Castle PQC XMSS签名:NullPointerException [英] Bouncy Castle PQC XMSS signing: NullPointerException after retrieving SecretKey from KeyStore

查看:127
本文介绍了从KeyStore检索SecretKey后,Bouncy Castle PQC XMSS签名:NullPointerException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在重建 JarSigner ,以便与PQC签名方案配合使用,例如 XMSS JCA / JCE提供程序 BouncyCastle 我遇到了一个问题:XMSS专用密钥在存储并从磁盘检索后似乎无法再用于对内容进行签名。但是,XMSSMT和SPHINCS私钥可以。为什么?

While rebuilding JarSigner in order to work with PQC Signature Schemes such as XMSS provided by the JCA/JCE Provider BouncyCastle I came across a problem: It seems that XMSS PrivateKeys cannot be used to sign stuff anymore after being stored and retrieved from disk. However XMSSMT and SPHINCS PrivateKeys can. Why ?

供您自己测试的源代码位于底部。
您将需要2个外部库才能工作:

The Source Code for you to test it yourself is at the bottom. You will need 2 external libraries for it to work:


  1. 充气城堡提供商

  2. 充气城堡实用程序库可生成X.509证书

  1. the Bouncy Castle Provider
  2. a Bouncy Castle utility library to generate X.509 Certificates

注意:源代码是关于保存和检索 KeyStore 。但是我也尝试将其简单保存到文件中

N.B.: The Source Code is about saving and retrieving the Key in/from a KeyStore. But I also tried saving it simply to a file which does not work either.

我得到的错误:

java.security.SignatureException: java.lang.NullPointerException
at org.bouncycastle.pqc.jcajce.provider.xmss.XMSSSignatureSpi.engineSign(Unknown Source)
at java.base/java.security.Signature.sign(Signature.java:598)
at Main.sign(Main.java:91)
at Main.run(Main.java:71)
at Main.main(Main.java:22)

[Main]

public class Main {
    public static String keyStorePath = "myKeyStore.keystore";

    public static void main(String[] args) throws InterruptedException {
        String[] algs = {"XMSS", "XMSS", "XMSSMT", "XMSSMT", "SPHINCS256"},
                 digests = {"SHA256", "SHA512", "SHA256", "SHA512", "SHA512"};
        for (int i = 0; i < algs.length; i++){
            try {
                run(algs[i], digests[i]);
            }catch (Exception ignore){
                ignore.printStackTrace();
                Thread.sleep(60); // Wait for print
            }
        }
    }

    public static void run(String alg, String digest) throws Exception{
        String sigAlg = digest + "with" + alg,
                provider = "BCPQC",
                keyStoreProvider = "BC",
                keyStoreAlias = sigAlg,  // for readability
                keyStorePassword = "password";
        System.out.println("Running " + sigAlg + ".");

        // Add providers
        addProvider(new String[] {provider, keyStoreProvider});

        // Generate KeyPairs
        KeyPairGenerator kpg = KeyPairGenerator.getInstance(alg, provider);
        initialize(kpg, alg, digest);
        KeyPair myKp = kpg.generateKeyPair();

        // Sign
        sign(myKp.getPrivate(), sigAlg, provider, "Hello World!");

        // Generate a self-signed certificate
        X509Certificate cert = BCCertGen.generate(myKp.getPrivate(), myKp.getPublic(), 365, sigAlg, true);

        // Load a KeyStore
        KeyStore keyStore = KeyStore.getInstance("PKCS12", keyStoreProvider);
        try {
            keyStore.load(new FileInputStream(keyStorePath), keyStorePassword.toCharArray());
        }catch (Exception ingore){
            // If there is no KeyStore at @keyStorePath
            // create an empty one
            keyStore.load(null, keyStorePassword.toCharArray());
        }

        // Store the generated KeyPair with the Certificate in the KeyStore
        keyStore.setKeyEntry(keyStoreAlias, myKp.getPrivate(), keyStorePassword.toCharArray(), new X509Certificate[] {cert});
        keyStore.store(new FileOutputStream(keyStorePath), keyStorePassword.toCharArray());

        // Load the stored PrivateKey from the KeyStore
        keyStore.load(new FileInputStream(keyStorePath), keyStorePassword.toCharArray());
        PrivateKey privateKey = (PrivateKey) keyStore.getKey(keyStoreAlias, keyStorePassword.toCharArray());

        // Sign again
        sign(privateKey, sigAlg, provider, "Hello World!");
    }

    public static void addProvider(String[] providers){
        for (String provider : providers) {
            switch (provider) {
                case "BCPQC":
                    Security.addProvider(new BouncyCastlePQCProvider());
                    break;
                case "BC":
                    Security.addProvider(new BouncyCastleProvider());
                    break;
            }
        }
    }

    public static void sign(PrivateKey pk, String sigAlg, String provider , String payload) throws Exception{
        Signature signer = Signature.getInstance(sigAlg, provider);
        signer.initSign(pk);
        signer.update(payload.getBytes());
        signer.sign();
        System.out.println("Successfully signed");
    }

    public static void initialize(KeyPairGenerator kpg, String alg, String digest) throws Exception {
        switch (alg) {
            case "XMSS":
                kpg.initialize(new XMSSParameterSpec(4, digest));
                break;
            case "XMSSMT":
                kpg.initialize(new XMSSMTParameterSpec(4, 2, digest));
                break;
            case "SPHINCS256":
                kpg.initialize(new SPHINCS256KeyGenParameterSpec());
                break;
            case "RSA":
                kpg.initialize(new RSAKeyGenParameterSpec(2048, new BigInteger("5")));
                break;
        }
    }
}

[BCCertGen]

[BCCertGen]

public class BCCertGen {
    public static String _country = "Westeros",
                         _organisation = "Targaryen",
                         _location = "Valyria",
                         _state = "Essos",
                         _issuer = "Some Trusted CA";

    public BCCertGen(String country, String organisation, String location, String state, String issuer){
        _country = country;
        _organisation = organisation;
        _location = location;
        _state = state;
        _issuer = issuer;
    }
    public static X509Certificate generate(PrivateKey privKey, PublicKey pubKey, int duration, String signAlg, boolean isSelfSigned) throws Exception{
        Provider BC = new BouncyCastleProvider();

        // distinguished name table.
        X500NameBuilder builder = createStdBuilder();

        // create the certificate
        ContentSigner sigGen = new JcaContentSignerBuilder(signAlg).build(privKey);
        X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(
                new X500Name("cn="+_issuer),    //Issuer
                BigInteger.valueOf(1),      //Serial
                new Date(System.currentTimeMillis() - 50000),   //Valid from
                new Date((long)(System.currentTimeMillis() + duration*8.65*Math.pow(10,7))),    //Valid to
                builder.build(),    //Subject
                pubKey              //Publickey to be associated with the certificate
        );

        X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));

        cert.checkValidity(new Date());

        if (isSelfSigned) {
            // check verifies in general
            cert.verify(pubKey);
            // check verifies with contained key
            cert.verify(cert.getPublicKey());
        }

        ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded());
        CertificateFactory fact = CertificateFactory.getInstance("X.509", BC);

        return (X509Certificate) fact.generateCertificate(bIn);
    }

    private static X500NameBuilder createStdBuilder() {
        X500NameBuilder builder = new X500NameBuilder(RFC4519Style.INSTANCE);

        builder.addRDN(RFC4519Style.c, _country);
        builder.addRDN(RFC4519Style.o, _organisation);
        builder.addRDN(RFC4519Style.l, _location);
        builder.addRDN(RFC4519Style.st, _state);

        return builder;
    }
}


推荐答案

此是一个已知问题: https://github.com/bcgit/bc-java/issues / 380
请按照建议使用高于161b01的beta版本。

This is a known issue: https://github.com/bcgit/bc-java/issues/380 Just use a beta version higher than 161b01 as suggested.

这篇关于从KeyStore检索SecretKey后,Bouncy Castle PQC XMSS签名:NullPointerException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆