16

I have used KeyPairGenerator to generate a RSA key pair. If I'm not wrong, the KeyStore is only used to store certificates and not keys. How can I properly store the private key on the computer?

segfault
  • 5,759
  • 9
  • 45
  • 66

4 Answers4

11

NOTE: This code is for demonstration purposes only. Private keys must be encrypted when you store them on disk. Do not use it as is.

You can do something like this:

 KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
 kpg.initialize(2048);

 KeyPair kp = kpg.genKeyPair();

 KeyFactory fact = KeyFactory.getInstance("RSA");

 RSAPublicKeySpec pub = fact.getKeySpec(kp.getPublic(),
        RSAPublicKeySpec.class);
 saveToFile(PUBLIC_KEY_FILE, 
        pub.getModulus(), pub.getPublicExponent());

 RSAPrivateKeySpec priv = fact.getKeySpec(kp.getPrivate(),
        RSAPrivateKeySpec.class);
 saveToFile(PRIVATE_KEY_FILE, 
         priv.getModulus(), priv.getPrivateExponent());

The save function:

private static void saveToFile(String fileName,
                               BigInteger mod, BigInteger exp) 
    throws SomeException {
    ObjectOutputStream oout = new ObjectOutputStream(
            new BufferedOutputStream(new FileOutputStream(fileName)));
    try {
        oout.writeObject(mod);
        oout.writeObject(exp);
    } catch (Exception e) {
        throw new SomeException(e);
    } finally {
        oout.close();
    }
}

And read the same way back:

private static PublicKey readPublicKey() throws SomeException {
    InputStream in = new FileInputStream(PUBLIC_KEY_FILE);
    ObjectInputStream oin =
            new ObjectInputStream(new BufferedInputStream(in));
    try {
        BigInteger m = (BigInteger) oin.readObject();
        BigInteger e = (BigInteger) oin.readObject();
        RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
        KeyFactory fact = KeyFactory.getInstance("RSA");
        PublicKey pubKey = fact.generatePublic(keySpec);
        return pubKey;
    } catch (Exception e) {
        throw new SomeException(e);
    } finally {
        oin.close();
    }
}

Reading private key is similar.

Eugene Retunsky
  • 13,009
  • 4
  • 52
  • 55
  • 2
    @segfault, Also keep in mind that you need `` to add this in `AndroidManifest.xml` – Israel Jan 10 '13 at 22:42
  • 7
    Is it safe to store the private key in storage that's accessible via other apps? (Correct me if I'm wrong, but that's what's done here.) – cph2117 Nov 03 '14 at 19:01
  • It's up to you to set up permissions to the file on the OS level (e.g. a dedicated user for the app etc.). Ovbiously, it's outside of the scope of this answer. – Eugene Retunsky Nov 07 '14 at 21:42
  • 21
    So you dont use `keystore` this mean you did not answer the question – meda Oct 12 '15 at 19:45
  • 1
    This is one of the most dangerous security/code hacks I've ever seen. You didn't even recommend to secure the private key. – TheRealChx101 Jan 12 '19 at 08:30
7

This block of code will generate and store a KeyPair on the AndroidKeyStore. (NOTE: Exception catches omitted)

KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);

String alias = "my_key"; // replace as required or get it as a function argument

int nBefore = keyStore.size(); // debugging variable to help convince yourself this works

// Create the keys if necessary
if (!keyStore.containsAlias(alias)) {

    Calendar notBefore = Calendar.getInstance();
    Calendar notAfter = Calendar.getInstance();
    notAfter.add(Calendar.YEAR, 1);
    KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(this)
                    .setAlias(alias)
                    .setKeyType("RSA")
                    .setKeySize(2048)
                    .setSubject(new X500Principal("CN=test"))
                    .setSerialNumber(BigInteger.ONE)
                    .setStartDate(notBefore.getTime())
                    .setEndDate(notAfter.getTime())
                    .build();
    KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
    generator.initialize(spec);

    KeyPair keyPair = generator.generateKeyPair();
}
int nAfter = keyStore.size();
Log.v(TAG, "Before = " + nBefore + " After = " + nAfter);

// Retrieve the keys
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(alias, null);
RSAPrivateKey privateKey = (RSAPrivateKey) privateKeyEntry.getPrivateKey();
RSAPublicKey publicKey = (RSAPublicKey) privateKeyEntry.getCertificate().getPublicKey();

Log.v(TAG, "private key = " + privateKey.toString());
Log.v(TAG, "public key = " + publicKey.toString());
Patrick Brennan
  • 2,688
  • 3
  • 20
  • 30
0

http://snipplr.com/view/18368/

OR

http://docs.oracle.com/javase/1.5.0/docs/api/java/security/KeyStore.html

OR

http://java.sun.com/docs/books/tutorial/security/apisign/vstep2.html This is most Promising

OR

It's impossible to secure a key in an untrusted environment. You can obfuscate your code, you can create a key from arbitrary variables, whatever. Ultimately, assuming that you use the standard javax.crypto library, you have to call Mac.getInstance(), and sometime later you'll call init() on that instance. Someone who wants your key will get it.

However, I think the solution is that you tie the key to the environment, not the program. A signature is meant to say that the data originated from a known source, and has not been tampered with since that source provided it. Currently, you're trying to say "guarantee that my program produced the data." Instead, change your requirement to "guarantee that a particular user of my program produced the data." The onus is then shifted to that user to take care of his/her key.

Hemang
  • 26,840
  • 19
  • 119
  • 186
Anand
  • 1,129
  • 7
  • 29
0

Depending on the format of your private key you might need to convert it to a format the java keytool can use.

But if it is in a keytool supported format you should be able yo just import it using keytool. more info at:

http://docs.oracle.com/javase/tutorial/security/toolfilex/rstep1.html

http://docs.oracle.com/javase/1.5.0/docs/tooldocs/windows/keytool.html

Community
  • 1
  • 1
Sibster
  • 3,081
  • 21
  • 18