21

Hi I want to extract public key from KeyStore using Java code

I am creating a keystore

keytool -genkey -alias mykeystore -keyalg RSA -keystore mykeystore.jks -keysize 2048

And exporting the public into another file

keytool -export -alias mykeystore -keystore mykeystore.jks -rfc -file publickey.cert

How can I get the Public Key String from keystore or the publickey.cert file using the Java code?

Thanks.

UPDATE

public static void main(String[] args) {

    try {

        FileInputStream is = new FileInputStream("/home/myuser/my-keystore/mykeystore.jks");
        KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
        String password = "myuserpass";
        char[] passwd = password.toCharArray();
        keystore.load(is, passwd);
        String alias = "mykeystore";
        Key key = keystore.getKey(alias, passwd);
        if (key instanceof PrivateKey) {
          // Get certificate of public key
          Certificate cert = keystore.getCertificate(alias);
          // Get public key
          PublicKey publicKey = cert.getPublicKey();

          String publicKeyString = Base64.encodeBase64String(publicKey
                    .getEncoded());
          System.out.println(publicKeyString);

        }

    } catch (Exception e) {
        e.printStackTrace();
    }
}

Then it is giving like

MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiG2FjSuXrraYuh0TyRNiUvVCyaFlb7VY9AFIMSDdcY0JgNF0c4YVQxYxUCbYzmkLZD/rrYMe/8nxkWV0TMz2Y7GnvichjtWHL1ui58uC0+RtFMkYJ+ftwt9qBy9hvb/rVFTsvT5/b6CQXD8a6bFveMUluQZISLCV7i11XYzp81+w6M7+2fJAwezIJnIrgwv1K9YDjWaToaNXe7hnzzy0s8AdkjTk197+hg8dRfbvkr8XAddNsEMPeUA5iY+5VEpRNI925ZT/dxnaABA0z6i4JbVjeLl8r7ySG9R/2w/j2G+/YSRQc9BmRHPa0tBgH7wvQM+WRwD9WmST+5qeBIfH3QIDAQAB

When I do cat publickey.cert, it shows this

-----BEGIN CERTIFICATE-----
MIIDgTCCAmmgAwIBAgIEf7XoMDANBgkqhkiG9w0BAQsFADBxMQswCQYDVQQGEwJJTjESMBAGA1UE
CBMJS2FybmF0YWthMRIwEAYDVQQHEwlCYW5nYWxvcmUxEjAQBgNVBAoTCU5ldHNjaXR1czESMBAG
A1UECxMJTmV0c2NpdHVzMRIwEAYDVQQDEwlOZXRzY2l0dXMwHhcNMTQxMTAzMDkyNTM3WhcNMTUw
MjAxMDkyNTM3WjBxMQswCQYDVQQGEwJJTjESMBAGA1UECBMJS2FybmF0YWthMRIwEAYDVQQHEwlC
YW5nYWxvcmUxEjAQBgNVBAoTCU5ldHNjaXR1czESMBAGA1UECxMJTmV0c2NpdHVzMRIwEAYDVQQD
EwlOZXRzY2l0dXMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCIbYWNK5eutpi6HRPJ
E2JS9ULJoWVvtVj0AUgxIN1xjQmA0XRzhhVDFjFQJtjOaQtkP+utgx7/yfGRZXRMzPZjsae+JyGO
1YcvW6Lny4LT5G0UyRgn5+3C32oHL2G9v+tUVOy9Pn9voJBcPxrpsW94xSW5BkhIsJXuLXVdjOnz
X7Dozv7Z8kDB7MgmciuDC/Ur1gONZpOho1d7uGfPPLSzwB2SNOTX3v6GDx1F9u+SvxcB102wQw95
QDmJj7lUSlE0j3bllP93GdoAEDTPqLgltWN4uXyvvJIb1H/bD+PYb79hJFBz0GZEc9rS0GAfvC9A
z5ZHAP1aZJP7mp4Eh8fdAgMBAAGjITAfMB0GA1UdDgQWBBSvgDYtI/NGP8Y0EvsCHASjmr/PmzAN
BgkqhkiG9w0BAQsFAAOCAQEACefje/dhmzEkBoA6OV934WtGXcBQNcb+9/qBGevUBG1cNJIyJddi
dea2gFUB1rx/WffTrJyiOCApV8wXG+zmGm6YJenKnGG9sIQtOTibhs3ll7UN4S0n9xsD+1y7YD1c
DNm9lI/3aFn1WUwPc3T4+RXE6XqkDB3geIvLUXaFUi+Y59XiLPHvk61kcopCGeoweX5yWVZ2Njp/
UUJIxQ6Ni3GvfPlxCxWtRe1MDAkhfT6/aAUr37lxtupHibzm9EAJdUEmAFHMhxkNCJiRDsasAiQ8
7V5uBI3ucdSwh+gPaW8KoWlJpv5SGlAkwzq0lSrxyq2ukkC6ciPeKhUvWtHaPg==
-----END CERTIFICATE-----

They keys are different, even in length. Why?

iCode
  • 7,556
  • 20
  • 50
  • 89

7 Answers7

24

You can find a solution by just googleling for your question.

Example from java2s.com:

import java.io.FileInputStream;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;

public class Main {
  public static void main(String[] argv) throws Exception {
    FileInputStream is = new FileInputStream("your.keystore");

    KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
    keystore.load(is, "my-keystore-password".toCharArray());

    String alias = "myalias";

    Key key = keystore.getKey(alias, "password".toCharArray());
    if (key instanceof PrivateKey) {
      // Get certificate of public key
      Certificate cert = keystore.getCertificate(alias);

      // Get public key
      PublicKey publicKey = cert.getPublicKey();

      // Return a key pair
      new KeyPair(publicKey, (PrivateKey) key);
    }
  }
}

See also:

UPDATE:

See comments for additional information to the problem.

Community
  • 1
  • 1
L.Butz
  • 1,977
  • 16
  • 41
  • 1
    @iProgrammer Hi, to answer the question at the end of your question: The difference is, that the publickey.cert is a whole certificate and not only the key itself. It also contains a lot of additional information. See http://en.wikipedia.org/wiki/Public_key_certificate#Contents_of_a_typical_digital_certificate – L.Butz Nov 03 '14 at 10:26
  • I got that. But see the public Key I got from java code and the public key in the public.cert file. Just check first few characters, you can understand both are different. – iCode Nov 03 '14 at 10:29
  • Please check the Java code also. Thanks. Anything wrong there? – iCode Nov 03 '14 at 10:31
  • It is exactly like I already told you. A Certificate contains a lot of additional information which are also encoded in base64. Take that output you provided (the ----BEGIN CERT----- one), paste it into a text file. Save that file and rename the file to something.cert. You get the WHOLE certificate including all additional fields and not only the public key. This is why you can't compare those two strings. They are just different - even in a logical way. – L.Butz Nov 03 '14 at 10:41
8

Try this:

import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Enumeration;
import java.security.PublicKey;
import java.util.Base64;

//=====================

try {
    File file = new File("C:\\Program Files (x86)\\keyStoreFilehere.kstr");
    FileInputStream is = new FileInputStream(file);
    KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
    String password = "password";
    keystore.load(is, password.toCharArray());
    Enumeration enumeration = keystore.aliases();
    while(enumeration.hasMoreElements()) {
         String alias = (String)enumeration.nextElement();
         Certificate certificate = keystore.getCertificate(alias);
         PublicKey publicKey = keystore.getCertificate(alias).getPublicKey();
         byte[] encodedCertKey = certificate.getEncoded();
         byte[] encodedPublicKey = publicKey.getEncoded();
         String b64PublicKey = Base64.getMimeEncoder().encodeToString(encodedPublicKey);
         String b64CertKey = Base64.getMimeEncoder().encodeToString(encodedCertKey);
         String publicKeyString = "-----BEGIN CERTIFICATE-----\n"
                            + b64PublicKey
                            + "\n-----END CERTIFICATE-----";

         String certKeyString = "-----BEGIN CERTIFICATE-----\n"
                            + b64CertKey
                            + "\n-----END CERTIFICATE-----";
         System.out.println(publicKeyString);
         System.out.println(certKeyString);
    }

 } catch (CertificateException | NoSuchAlgorithmException  | KeyStoreException | IOException e) {
            e.printStackTrace();
 }
vsantari
  • 81
  • 1
  • 2
  • 1
    While this code may answer the question, it would be better to include some context, explaining how it works and when to use it. Code-only answers are not useful in the long run. – glennsl Sep 27 '17 at 02:11
4

If it's just the public key string that you want, it's easier to get the publickey.cert file, as it is a plain text file. Assuming that you have the full path of the file (like "/home/users/iprogrammer/publickey.cert" or "D:\MyDocuments\publickey.cert" ) you do something like:

public String getPublicKeyString( Path path ) throws IOException {
    byte[] fileBytes = Files.readAllBytes(Paths.get(path));
    return new String( fileBytes, "US-ASCII" );
}

This will give you the whole file, including the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE-----.

Once you have the whole file, you can use the BouncyCastle library to open it:

    PEMParser pemParser = new PEMParser(new StringReader(certPEMData));
    Object parsedObj = pemParser.readObject();
    System.out.println("PemParser returned: " + parsedObj);
    if (parsedObj instanceof X509CertificateHolder)
    {
        X509CertificateHolder x509CertificateHolder = (X509CertificateHolder) parsedObj;
        return x509CertificateHolder.getSubjectPublicKeyInfo().getPublicKeyData().getString();
    }
    else
    {
        throw new RuntimeException("The parsed object was not an X509CertificateHolder.");
    }
EpicPandaForce
  • 71,034
  • 25
  • 221
  • 371
RealSkeptic
  • 32,074
  • 7
  • 48
  • 75
  • Then I can read the whole file. There are Java security functions to read public key from keystore – iCode Nov 03 '14 at 10:20
  • You asked for the public key string. Of course there are ways to read from the key store. But since you already exported it, I gave you the way to read it. – RealSkeptic Nov 03 '14 at 10:22
  • Actually, if he can read the Certificate in as a String like that, then he could use the `PEMParser` class from Bouncycastle. – EpicPandaForce Nov 03 '14 at 11:58
  • @Zhuinden, yes, but then he'll get the public key as an `SubjectPublicKeyInfo` object. Frankly, I would not have given the answer I've given if he didn't specifically ask for the public key **String**. – RealSkeptic Nov 03 '14 at 12:12
4

The first base 64 contains only the key

Base64.encodeBase64String(publicKey.getEncoded())

The second base 64 contains the whole public certificate

Base64.encodeBase64String(cert.getEncoded())
FkJ
  • 1,499
  • 1
  • 15
  • 29
1

Once you have the KeyStore loaded, it's one simple line to get the PublicKey.

    KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
    ks.load(null);          
    PublicKey publicKey = ks.getCertificate("aliasYouChose").getPublicKey();

The PublicKey is located 'inside' the Certificate, the Certficate is not just the PublicKey.

Also, it's important to note that a properly formatted PEM key expects a "\n" after every 64 characters. So, simply putting "\n-----END PUBLIC KEY-----" at the end (and respective beginning) might not work if you're trying to then use it with openSSL in PHP, for example.

Adam Winter
  • 973
  • 7
  • 19
0

Once you have successfully exported , you can get it from the key store,

through KeyPair(publicKey, (PrivateKey) key)

An example ,

   FileInputStream is = new FileInputStream("publickey.cert");
    KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
    keystore.load(is, "my-keystore-password".toCharArray());
    String alias = "myalias";
    Key key = keystore.getKey(alias, "password".toCharArray());
    if (key instanceof PrivateKey) {
      // Get certificate of public key
      Certificate cert = keystore.getCertificate(alias);
      // Get public key
      PublicKey publicKey = cert.getPublicKey();

      // Return a key pair
      new KeyPair(publicKey, (PrivateKey) key);
    }
  } 

will return the new key,value pair.

Also read the similar thread here Get Private Key from Keystore

Community
  • 1
  • 1
Santhosh
  • 8,045
  • 2
  • 26
  • 54
  • sorry i cant the second part in your update can you be more clear – Santhosh Nov 03 '14 at 10:27
  • Please see the public Key I got from Java code and the public key in the public.cert file. Just check first few characters, you can understand both are different. – iCode Nov 03 '14 at 10:30
0

If you would like the string version of the PublicKey:

String publicKeyString value = "-----BEGIN PUBLIC KEY-----\n" + new String(Base64.encode(publicKey.getEncoded())) + "\n-----END PUBLIC KEY-----";

Thomas Stubbe
  • 1,537
  • 4
  • 19
  • 32