为什么Key.getAlgorithm在保存并重新加载KeyStore后返回不同的结果

时间:2015-11-18 19:09:05

标签: java cryptography bouncycastle keystore digital-certificate

我正在使用椭圆曲线算法生成用于签名的KeyPair。生成私钥后,我将其存储在KeyStore中并将其写入文件。当我调用Key.getAlgorithm时,它返回“ECDSA”。但是在从文件重新加载KeyStore之后,Key.getAlgorithm返回“EC”。我想知道这是从哪里来的,以及为什么我在保存后会得到不同的结果。

这是我的代码(请注意,为此需要在jre中安装JCE无限强度策略文件):

public static void main(String [] args) throws Exception
{
    String PROVIDER = "BC";
    String KEY_ALGORITHM = "ECDSA";
    String SIGNATURE_ALGORITHM = "SHA1WITHECDSA";
    String ALIAS = "TestAlias";
    char [] PASSWORD = "password".toCharArray();
    String KEYSTORE = "c:/test/bugs/keystore.p12";

    Security.addProvider(new BouncyCastleProvider());

    // Generate the key
    Calendar calNow = Calendar.getInstance();
    Calendar calLater = Calendar.getInstance();
    calLater.set(Calendar.YEAR, calLater.get(Calendar.YEAR) + 25);
    Date startDate = new Date(calNow.getTimeInMillis());
    Date expiryDate = new Date(calLater.getTimeInMillis());

    ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp192r1");
    KeyPairGenerator g = KeyPairGenerator.getInstance(KEY_ALGORITHM, PROVIDER);
    g.initialize(ecSpec, new SecureRandom());
    KeyPair keyPair = g.generateKeyPair();

    X509V1CertificateGenerator certGen = new X509V1CertificateGenerator();
    X500Principal dnName = new X500Principal("CN=Test");
    certGen.setSerialNumber(new BigInteger(8, new SecureRandom()));
    certGen.setIssuerDN(dnName);
    certGen.setNotBefore(startDate);
    certGen.setNotAfter(expiryDate);
    certGen.setSubjectDN(dnName); // note: same as issuer
    certGen.setPublicKey(keyPair.getPublic());
    certGen.setSignatureAlgorithm(SIGNATURE_ALGORITHM);
    X509Certificate cert = certGen.generate(keyPair.getPrivate(), PROVIDER);

    // Save the keystore
    KeyStore exportStore = KeyStore.getInstance("PKCS12", PROVIDER);
    exportStore.load(null, null);
    exportStore.setKeyEntry(ALIAS, keyPair.getPrivate(), PASSWORD, new Certificate[] { cert });
    FileOutputStream out = new FileOutputStream(KEYSTORE);
    exportStore.store(out, PASSWORD);
    out.flush();
    out.close();

    // print the info from the keystore 
    System.out.println(exportStore.getKey(ALIAS, PASSWORD).getAlgorithm());

    // Reload the keystore
    FileInputStream in = new FileInputStream(KEYSTORE);
    exportStore.load(in, PASSWORD);
    in.close();

    // print the info from the reloaded keystore 
    System.out.println(exportStore.getKey(ALIAS, PASSWORD).getAlgorithm());
}

基于this example from Bouncy Castle,在生成KeyPair时使用“ECDSA”似乎是正确的。

1 个答案:

答案 0 :(得分:1)

Oracle Java加密体系结构Oracle平台标准版Oracle提供程序文档(Java 7 / Java 8)要求:

  

使用椭圆曲线密码术(ECDSA,ECDH,ECDHE,ECDH_anon)的密码套件需要符合以下要求的JCE加密提供程序:

     
      
  • 提供程序必须实现由java.security.spec和java.security.interfaces包中的类和接口定义的ECC。 椭圆曲线键对象的getAlgorithm()方法必须返回字符串" EC"。

  •   
  • 提供者必须支持签名算法SHA1withECDSA和NONEwithECDSA,KeyAgreement算法ECDH,以及KeyPairGenerator和算法EC的KeyFactory。如果缺少其中一种算法,SunJSSE将不允许使用EC密码套件。

  •   
  • 提供者必须支持RFC 4492规范第5.1.1节中引用的所有SECG曲线(另请参见附录A)。在证书中,应使用未压缩的形式对点进行编码,并且应使用namedCurve选项对曲线进行编码,即使用对象标识符。

  •   
     

如果不满足这些要求,可能无法正确协商EC密码套件。

据推测,因为您的代码明确使用了" ECDSA" KeyPairGenerator ,原始密钥将" ECDSA" 作为算法公开,但在加载序列化表示时,BouncyCastle使用" EC& Oracle要求#34;

顺便说一句,如果您设置KEY_ALGORITHM = "EC",则会在两个输出中获得" EC"