I want to generate a key pair and insert the public and private keys into different keystores, to be used as KeyStore and TrustStore in an SSL Socket connection. I generate the KeyPair using a KeyPairGenerator, and I already have generated a signing certificate for the chain using java's keytool. Then I can insert the private key into a KeyStore like this:
PublicKey publicKey;
PrivateKey privateKey;
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(null, "storepass".toCharArray());
keyStore.setKeyEntry("privatekey", privateKey, "keypass".toCharArray(), chain);
Using this keystore I can create a KeyManager for the SSL connection. But to create a TrustManager, I need the public key stored into a KeyStore as well, so I tried storing the public key in a key store:
PublicKey publicKey;
KeyStore trustStore = KeyStore.getInstance("JKS");
keyStore.load(null, "storepass".toCharArray());
trustStore.setKeyEntry("publickey", publicKey, "public".toCharArray(), chain);
This returns an error: java.security.KeyStoreException: Cannot store non-PrivateKeys
So I tried using setCertificateEntry(), but this doesn't work since it's a PublicKey object and I need a Certificate. So my question is, how can I store the PublicKey in a KeyStore programatically? Using keytool is not an option.
Related
I want to store private key in android KeyStore, but I have problem with KeyStore.getInstance("JKS") is error like this:
java.security.KeyStoreException: JKS not found.
Please help me why it's not know for this instance?
I have file load my keystore: mykeystore.jks
My code as below:
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.genKeyPair();
X509Certificate certificate = generateCertificate(keyPair);
KeyStore ks = KeyStore.getInstance("JKS");
char[] password = "xxxxxx".toCharArray();
try (FileInputStream fis = new FileInputStream("path\\mykeystore.jks")) {
ks.load(fis, password);
}
Certificate[] certChain = new Certificate[1];
certChain[0] = certificate;
ks.setKeyEntry("key1", keyPair.getPrivate(), password, certChain);
} catch(Exception e) {
e.printStackTrace();
}
Result error:
java.security.KeyStoreException: JKS not found
A Java KeyStore (JKS) is not available on Android.
The recommended keystore on android is AndroidKeyStore. For your case, get keystore instance using AndroidKeyStore instead of JKS and set password as null because AndroidKeyStore does not accepts any password:
//...
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
//...
ks.setKeyEntry("key1", keyPair.getPrivate(), null, certChain);
In an AndroidKeyStore, you cannot set password for keys or keystore because keystore file(s) managed by Android system itself. Also, generating keys inside to the AndroidKeyStore instead of importing (eg. calling setKeyEntry) is more secure and recommended way.(In supported devices, Android generates keys in separated secure hardware. Which means, nobody, including app itself cannot export keys from that device)
So, generate keys using KeyGenParameterSpec.Builder instead of KeyPairGenerator.
You can check documentation here: https://developer.android.com/training/articles/keystore
But if you think AndroidKeyStore is still not suitable for you, you can list available keystore types in Android via:
// Iterate in security providers
for(Provider provider: Security.getProviders()) {
for(Object item: provider.keySet()) {
if(item.toString().startsWith("KeyStore.")) { // grep KeyStores
Log.d(TAG, "Keystore: " + item.toString() + " available in provider: " + provider.getName());
}
}
}
In an Android Emulator Pixel 2 API 28 this code outputs:
Keystore: KeyStore.BouncyCastle available in provider: BC
Keystore: KeyStore.PKCS12 available in provider: BC
Keystore: KeyStore.BKS available in provider: BC
Keystore: KeyStore.AndroidCAStore available in provider: HarmonyJSSE
Keystore: KeyStore.AndroidKeyStore available in provider: AndroidKeyStore
Which means, available KeyStore's are:
BouncyCastle
PKCS12
BKS
AndroidCAStore
AndroidKeyStore
I would like to know how can I rename an alias of a keystore, programmatically in java, not using keytool.
I have my java.security.KeyStore object, containing an certain alias. How can I rename it?
The KeyStore API does not provide a rename operation for aliases. But what you can do is:
Save the content (key pair, certificates) of the keystore entry that you want to rename.
Delete the entry.
Create a new entry with the saved content and the new alias.
As Java code:
Key privateKey = keyStore.getKey(alias, password.toCharArray());
Certificate[] certs = keyStore.getCertificateChain(alias);
keyStore.setKeyEntry(newAlias, privateKey, password.toCharArray(), certs);
keyStore.deleteEntry(alias);
Of course this does not work if the private key is stored on a hardware device (smartcard or HSM) and therefore is not readable.
If the keystore entry contains a trusted certificate, the code looks a bit different:
Certificate cert = keyStore.getCertificate(alias);
keyStore.setCertificateEntry(newAlias, cert);
keyStore.deleteEntry(alias);
I'm using bouncycastle for generating detached signature for XML's signing. For key initialize I use this code:
Security.addProvider(new BouncyCastleProvider());
KeyStore ks = KeyStore.getInstance(KEYSTORE_INSTANCE);
ks.load(new FileInputStream(KEYSTORE_FILE), KEYSTORE_PWD.toCharArray());
Key key = ks.getKey(CERT_ALIAS, KEYSTORE_PWD.toCharArray());
I have JKS keystore with certificate. But if I do this:
Key key = ks.getKey(CERT_ALIAS, KEYSTORE_PWD.toCharArray());
key stay always null and I have InvalidKeyException
Where's my mistake? I new in crypto
I can't comment due to too low reputation. So I'll answer/edit instead.
The above example works fine, the error is probably in one of the constants being used. What are they, and what is the exact error you're getting?
I mean something like: java.security.InvalidKeyException: Illegal key size
Here is the working example I tried while loading a KeyStore from a file:
'secret1' is the store password, 'secret2' is the key password and 'myKey' is the key alias.
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(new FileInputStream(keyStoreFile.getAbsolutePath()), "secret1".toCharArray());
Key key = keyStore.getKey("myKey", "secret2".toCharArray());
I need to create certificate pfx file with password in java. I search in google and can create certificate "cer" file in http://www.java2s.com/Tutorial/Java/0490__Security/CreatingaSelfSignedVersion3Certificate.htm
I add code in main
FileOutputStream fos = null;
fos = new FileOutputStream("public.cer");
fos.write(cert.getEncoded());
fos.close();
this only work without password.
Normally a .pfx or pkcs12 its a keystore to save a public, private key pairs. Besides if you use a RSA key pair with public certificate as in your link sample, normally this certificate must be issued by a certificate authority, anyway I suppose that you're making an attempt to save a selfsigned certificate, to do so you have to use java.security.KeyStore class not a FileOutputStream directly, I give you a sample:
import java.io.FileOutputStream;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
....
X509Certificate cert = // your certificate...
// generate a keystore instance
KeyStore ks = KeyStore.getInstance("PKCS12");
// save your cert inside the keystore
ks.setCertificateEntry("YourCertAlias", cert);
// create the outputstream to store the keystore
FileOutputStream fos = new FileOutputStream("/your_path/keystore.pfx");
// store the keystore protected with password
ks.store(fos, "yourPassword".toCharArray());
....
As I said normally in the keystore you store the key pairs, normally using: setKeyEntry(String alias, byte[] key, Certificate[] chain) or setKeyEntry(String alias, Key key, char[] password, Certificate[] chain) however with the code above you can store a certificate in keystore protecting it with a password. For more info take a look at: java keystore api.
Hope this helps,
Hy Guys! I'm trying to create x.509 certificate using bouncycastle, which should be signed by another certificate and store it PEM base 64 format.
I've already have self-signed certificate (public and private key). Now I want to create new one and sign it with existing self-signed certificate.
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", "BC");
keyPairGenerator.initialize(1024, new SecureRandom());
KeyPair keyPair = keyPairGenerator.generateKeyPair();
X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
X500Principal dnName = new X500Principal("CN=Sergey");
certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
certGen.setSubjectDN(dnName);
certGen.setIssuerDN(caCert.getSubjectX500Principal());
certGen.setNotBefore(validityBeginDate);
certGen.setNotAfter(validityEndDate);
certGen.setPublicKey(keyPair.getPublic());
certGen.setSignatureAlgorithm("SHA256WithRSAEncryption");
certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(caCert));
certGen.addExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifierStructure(keyPair.getPublic()));
X509Certificate cert = certGen.generate(caCertPrivateKey, "BC");
Verification passed without exceptions, which means from my point of view that it was successfully signed by caCert:
cert.verify(caCert.getPublicKey());
Then I decode it to the PEM base 64:
PEMWriter pemWriter = new PEMWriter(new PrintWriter(System.out));
pemWriter.writeObject(cert);
pemWriter.flush();
I get something like this in the output:
-----BEGIN CERTIFICATE-----
MIIDDjCCAnegAwIBAgIBFDAN........
-----END CERTIFICATE-----
When I open it, I see the next:
Why there is no certification chain if it was successfully signed by caCert?
What need to be changed in my code to see certification chain as I expected?
I was able to find solution. Actually code works as expected. I didn't see chain of certificates because my caRoot certificate wasn't added to the trusted store. After I add my sel-signed certificate to the trusted root certified centers I see the whole certification chain as I expected.