关于密钥管理:如何从我们创建的密钥库中检索公钥和私钥

How to retrieve my public and private key from the keystore we created

我的任务如下:

  • 从我创建的密钥库中检索我的公钥和私钥。
  • 使用这些密钥使用我的RSA 2048位公钥加密段落。
  • 使用dsa-sha-1签名算法对结果进行数字签名。
  • 将数字签名输出保存在名为output.dat的文件中。

下面的程序引发错误:"java.security.invalidkeyException:没有安装的提供程序支持此密钥:sun.security.provider.dsapublickeyimpl"。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import java.security.*;
import java.security.KeyStore.*;
import java.io.*;
import java.security.PublicKey;
import java.security.PrivateKey;
import javax.crypto.Cipher;
import java.nio.charset.*;
import sun.security.provider.*;
import javax.crypto.*;

public class Code {

/**
 * @param args the command line arguments
 */

    public static void main(String[] args) {

        try {

            /* getting data for keystore */

            File file = new File(System.getProperty("user.home") + File.separatorChar +".keystore");
            FileInputStream is = new FileInputStream(file);
            KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());

            /*Information for certificate to be generated */
            String password ="abcde";
            String alias ="mykeys";
            String alias1 ="skeys";

            String filepath ="C:\\email.txt";

            /* getting the key*/
            keystore.load(is, password.toCharArray());
            PrivateKey key = (PrivateKey)keystore.getKey(alias,"bemylife".toCharArray());
            //PrivateKey key = cert1.getPrivateKey();
            //PublicKey key1= (PrivateKey)key;

            /* Get certificate of public key */
            java.security.cert.Certificate cert = keystore.getCertificate(alias);

            /* Here it prints the public key*/
            System.out.println("Public Key:");
            System.out.println(cert.getPublicKey());

            /* Here it prints the private key*/
            System.out.println("
Private Key:"
);
            System.out.println(key);

            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE,cert.getPublicKey());

            String cleartextFile ="C:\\email.txt";
            String ciphertextFile ="D:\\ciphertextRSA.png";

            FileInputStream fis = new FileInputStream(cleartextFile);
            FileOutputStream fos = new FileOutputStream(ciphertextFile);
            CipherOutputStream cos = new CipherOutputStream(fos, cipher);

            byte[] block = new byte[32];
            int i;
            while ((i = fis.read(block)) != -1) {
                cos.write(block, 0, i);
            }
            cos.close();


            /* computing the signature*/
            Signature dsa = Signature.getInstance("SHA1withDSA","SUN");
            dsa.initSign(key);
            FileInputStream f = new FileInputStream(ciphertextFile);
            BufferedInputStream in = new BufferedInputStream(f);
            byte[] buffer = new byte[1024];
            int len;
            while ((len = in.read(buffer)) >= 0) {
               dsa.update(buffer, 0, len);
           };
           in.close();

           /* Here it prints the signature*/
           System.out.println("Digital Signature :");
           System.out.println( dsa.sign());

           /* Now Exporting Certificate */
           System.out.println("Exporting Certificate.");
           byte[] buffer_out = cert.getEncoded();
           FileOutputStream os = new FileOutputStream(new File("d:\\signedcetificate.cer"));
           os.write(buffer_out);
           os.close();

           /* writing signature to output.dat file */
           byte[] buffer_out1 = dsa.sign();
           FileOutputStream os1 = new FileOutputStream(new File("d:\\output.dat"));
           os1.write(buffer_out1);
           os1.close();

       } catch (Exception e) {System.out.println(e);}

   }
}


您必须将它从keystore文件(可能以.jks结尾)读取到java.security.keystore对象中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/**
 * Reads a Java keystore from a file.
 *
 * @param keystoreFile
 *          keystore file to read
 * @param password
 *          password for the keystore file
 * @param keyStoreType
 *          type of keystore, e.g., JKS or PKCS12
 * @return the keystore object
 * @throws KeyStoreException
 *           if the type of KeyStore could not be created
 * @throws IOException
 *           if the keystore could not be loaded
 * @throws NoSuchAlgorithmException
 *           if the algorithm used to check the integrity of the keystore
 *           cannot be found
 * @throws CertificateException
 *           if any of the certificates in the keystore could not be loaded
 */

public static KeyStore loadKeyStore(final File keystoreFile,
    final String password, final String keyStoreType)
    throws KeyStoreException, IOException, NoSuchAlgorithmException,
    CertificateException {
  if (null == keystoreFile) {
    throw new IllegalArgumentException("Keystore url may not be null");
  }
  LOG.debug("Initializing key store: {}", keystoreFile.getAbsolutePath());
  final URI keystoreUri = keystoreFile.toURI();
  final URL keystoreUrl = keystoreUri.toURL();
  final KeyStore keystore = KeyStore.getInstance(keyStoreType);
  InputStream is = null;
  try {
    is = keystoreUrl.openStream();
    keystore.load(is, null == password ? null : password.toCharArray());
    LOG.debug("Loaded key store");
  } finally {
    if (null != is) {
      is.close();
    }
  }
  return keystore;
}

一旦你拥有了KeyStore,你就可以使用Certificate和公钥和私钥。

但使用它来签署文本并将其保存到文件中更为复杂,而且很容易出错。使用给定的公钥查看符号字符串,并将getKeyPair方法替换为使用KeyStore的方法。有点像

1
2
3
4
5
6
7
8
9
public static KeyPair getKeyPair(final KeyStore keystore,
    final String alias, final String password) {
  final Key key = (PrivateKey) keystore.getKey(alias, password.toCharArray());

  final Certificate cert = keystore.getCertificate(alias);
  final PublicKey publicKey = cert.getPublicKey();

  return KeyPair(publicKey, (PrivateKey) key);
}

(显然有点粗糙,我手边没有样本)


问题是DSA密钥不适合RSA加密。您需要一个RSA密钥进行加密,也许您可以将签名算法切换到RSA/SHA1以避免需要两个密钥。


1
2
3
4
5
6
7
8
9
trusted.load(in, ((PBCApplication) context.getApplicationContext()).getBuildSettings().getCertificatePass());
Enumeration enumeration = trusted.aliases();

while (enumeration.hasMoreElements()) {
    String alias = (String) enumeration.nextElement();
    System.out.println("alias name:" + alias);
    Certificate certificate = trusted.getCertificate(alias);
    certificate.getPublicKey();
}

我没有存储在大脑顶部的Java代码,但是一些一般的检查是:

  • 要将公共证书存储在所需位置吗?特别是,我的记忆是,带有公钥和私钥的证书存储在一个别名下,所以您在其中的两个别名设置看起来很奇怪。尝试将两者存储在同一别名下,并在私钥调用和公钥调用中引用它。

  • 您可以从证书中获得其他内容吗?例如,主题DN或颁发者DN都是证书中必须包含的字段。这为您提供了一个很好的证据,证明证书正按预期阅读。

  • 在几乎任何加密事务中,都要非常小心如何读取文件和传输编码方法。如果您已经创建了文件IO并以一种奇怪的方式从中提取,那么您可能会破坏关键材料的编码。这是最后一件要检查的事情,通常Java和JKS并没有这么糟糕,但是它会发生。同样,要清楚文件的格式-例如,jks文件不同于pkcs 12文件。