尽管重建的jarsigner为了与PQC签名方案,如工作XMSS提供由JCA / JCE提供 BouncyCastle的我碰到一个问题就来了:看来XMSS PrivateKeys不能再被存储并从磁盘检索后可以用来标志的东西。但是,XMSSMT和SPHINCS私钥可以。为什么呢
供您自己测试的源代码位于底部。您需要2个外部库才能运行:
注意:源代码是关于在KeyStore中保存和检索Key的。但是我也尝试将其简单地保存到一个也不起作用的文件中。
我得到的错误:
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)
[主要]
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]
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版本。