java.security.UnrecoverableKeyException: Cannot recover key when executing KeyManagerFactory.init() - java

I have the following code that tries to initialize KeyManagerFactory using SHA-256 hash as password.
public static KeyManager[] getKeystoreManagers()
throws UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException, NoSuchProviderException {
KeyStore keystore = getKeyStore();
if (keystore == null) {
return null;
}
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keystore, getMachinePassword(SHA_256).toCharArray());
return kmf.getKeyManagers();
}
getKeyStore() returns my application keystore. getMachinePassword() returns a password using SHA-256, 64 digits password length. The problem is that I get the exception when init() is called:
java.security.UnrecoverableKeyException: Cannot recover key
If I am passing smaller password length lets say, 50 digits the init succeeded. What seems to be the problem here?

I've solved my problem. The keystore was created using setEntry with specific alias. Therefore, in my conversion function I had to get the entry using the old password and set the same entry with the same alias again with the new password. Now, with this updated keystore the KeyManagerFactory.init() runs successfully. See the following code below:
static void convertPasswordAlgorithm(String keystorePath, String fromAlgorithm, String toAlgorithm) throws Exceptionc {
FileInputStream fileInStream = null;
String keystoreFullPath = keystorePath + ISiteConstants.c_FILE_SEPERATOR + KEYSTORE_FILE_NAME;
KeyStore keyStore;
try {
String alias = getCertificateAlias();
keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
fileInStream = new FileInputStream(keystoreFullPath);
// Try to load the keystore with fromAlgorithm password hash.
char[] machineOldAlgPassword = getMachinePassword(fromAlgorithm).toCharArray();
keyStore.load(fileInStream, machineOldAlgPassword);
// Save the entry to update
KeyStore.Entry entry = keyStore.getEntry(alias, new KeyStore.PasswordProtection(machineOldAlgPassword));
HandleFiles.close(fileInStream);
// If succeeded, recalculate password using toAlgorithm hash and save.
String machineNewAlgPassword = getMachinePassword(toAlgorithm);
keyStore.setEntry(alias, entry, new KeyStore.PasswordProtection(machineNewAlgPassword.toCharArray()));
FileOutputStream fileOutputStream = new FileOutputStream(keystoreFullPath);
keyStore.store(fileOutputStream, machineNewAlgPassword.toCharArray());
HandleFiles.close(fileOutputStream);
} finally {
HandleFiles.close(fileInStream);
}
}

Related

Not able to store multiple alias in same Keystore using private key and Certificate in java

void createKeyStore(String alias) throws Exception {
if(keyStoreType == null || keyStoreType.isEmpty()){
keyStoreType = KeyStore.getDefaultType();
}
keyStore = KeyStore.getInstance(keyStoreType);
KeyPair kp = generateRSAKeyPair();
Certificate[] certChain = new Certificate[1];
certChain[0] = generateCertificate(kp);
//load
char[] pwdArray = keyStorePassword.toCharArray();
keyStore.load(null, pwdArray);
keyStore.setKeyEntry(alias, kp.getPrivate(), keyStorePassword.toCharArray(), certChain);
// Save the keyStore
FileOutputStream fos = new FileOutputStream(keyStoreName,true);
keyStore.store(fos, pwdArray);
fos.close();
}
Using this function for create and write multiple alias in keystore
In the first request it create keystore file and store the alias with private key and certificate but in the second request with alias it not storing any data in same keystore file.
I am working on a Java project. I have created certificate using my function but now I have only one certificate . I am expecting to store multiple alias in the same file but it happen only with first request but not with second request.

Java Key Store always ends up with null aliases

I've been trying on this for a couple of days and I'm hopelessly stuck.
To fully understand how java key store works, i've been trying to create my own keystore, put some stuff inside it, then retrieve them from another program.
Here's my keystore generator :
{
//generate a X509 certificate
Security.addProvider(new BouncyCastleProvider());
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509", "BC");
X509Certificate certificate = (X509Certificate) certificateFactory.generateCertificate(new FileInputStream("certificate.cer"));
LOGGER.debug("BouncyCastle provider & X509 certificate added.");
//generate a private & a public key
KeyPair keyPair = generateRSAKeyPair();
RSAPrivateKey priv = (RSAPrivateKey) keyPair.getPrivate();
RSAPublicKey pub = (RSAPublicKey) keyPair.getPublic();
//generate a keystore
KeyStore ks = KeyStore.getInstance("PKCS12");
char[] keyStorePassword = "keystore_password".toCharArray();
ks.load(null, keyStorePassword);
try (FileOutputStream fos = new FileOutputStream("TestKeyStore.jks")) {
ks.store(fos, keyStorePassword);
}
ks.load(new FileInputStream("TestKeyStore.jks"), keyStorePassword);
//Symmetric key
SecretKey secretKey = KeyGenerator.getInstance("AES").generateKey();
KeyStore.SecretKeyEntry secretKeyEntry = new KeyStore.SecretKeyEntry((secretKey));
KeyStore.ProtectionParameter protectionParameter = new KeyStore.PasswordProtection(keyStorePassword);
ks.setEntry("symmetric_key", secretKeyEntry, protectionParameter);
//Asymmetric key
X509Certificate[] x509Certificates = new X509Certificate[1];
x509Certificates[0] = certificate;
ks.setKeyEntry("asymmetric key", priv, keyStorePassword, x509Certificates);
//certificate
ks.setCertificateEntry("test_certif", certificate);
Key key = ks.getKey("symmetric_key", keyStorePassword);
System.out.println("I have this symmetric key : " + key);
X509Certificate certificate1 = (X509Certificate) ks.getCertificate("test_certif");
System.out.println("I have this certificate : " + certificate1);
System.out.println(ks.aliases().nextElement());
LOGGER.debug("all went well");
}
As you probably noticed, it's not all polished: my goal for now is only to put some stuff inside the keystore. But the point here, from the last System.out.println(ks.aliases().nextElement());, is just to see there is indeed something inside the keystore. And this is working just fine, it gives back symmetric_key.
Now, from the same folder is another class that is supposed to read from that keystore.
Note: there is no issue regarding the file (I've tested by moving its localization) so it can't be that.
KeyStore ks = KeyStore.getInstance("PKCS12");
char[] keyStorePassword = "keystore_password".toCharArray();
ks.load(new FileInputStream("TestKeyStore.jks"), keyStorePassword);
System.out.println(ks.containsAlias("symmetric_key"));
This always gets me: false
If I try this: System.out.println(ks.aliases());, it's always null
If I try this:
if (!keystore.aliases().hasMoreElements()) {
System.out.println("nothing inside the keystore");
}
it gives me back nothing inside the keystore.
Even though it's not the case in the generator.
Any clue?
Thank you
The problem is that you are setting the entries after writing the keystore.
If you move:
try (FileOutputStream fos = new FileOutputStream("TestKeyStore.jks")) {
ks.store(fos, keyStorePassword);
}
Till after this line:
ks.setCertificateEntry("test_certif", certificate);
Everything should work fine.
Bellow you have an working example with some code removed for clarity:
public static void main(String[] args) throws Exception{
final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
final KeyPair keyPair = keyGen.genKeyPair();
RSAPrivateKey priv = (RSAPrivateKey) keyPair.getPrivate();
//generate a keystore
KeyStore ks = KeyStore.getInstance("PKCS12");
char[] keyStorePassword = PASSWORD;
ks.load(null, keyStorePassword);
X509Certificate[] chain = {generateCertificate("cn=Unknown", keyPair, 365, "SHA256withRSA")};
// saving one keypair in keystore object
ks.setKeyEntry("asymmetric key", keyPair.getPrivate(), keyStorePassword, chain);
//Symmetric key
SecretKey secretKey = KeyGenerator.getInstance("AES").generateKey();
KeyStore.SecretKeyEntry secretKeyEntry = new KeyStore.SecretKeyEntry((secretKey));
KeyStore.ProtectionParameter protectionParameter = new KeyStore.PasswordProtection(keyStorePassword);
// saving symmetric key in keystore object
ks.setEntry("symmetric_key", secretKeyEntry, protectionParameter);
// Saving our keystore object into the filesystem
try (FileOutputStream fos = new FileOutputStream("TestKeyStore.p12")) {
ks.store(fos, keyStorePassword);
}
// The rest of the code
}
The reason why it works in the method that saves the keystore is because the changed keystore is still in memory, but not on the filesystem. Also, since you are creating a PKCS12 keystore, I would avoid the .jks extension and go for something like .pkcs12.

Creating a .p12 file with a KeyStore

I have an external service that creates certificate for me, out of which I recieve a buffer (String). I attempt to load this buffer into a KeyStore in Java and then use the "store" function in order to create a .p12 file. However, the store function throws an exception - "Given final block not properly padded".
No matter what I try, I cannot get this to work or find the cause of the issue.
My code is :
public void createP12Certificate(String userName, String comment) throws KeyStoreException, AdminCertificateException, CertificateException, NoSuchAlgorithmException, IOException
{
KeyStore store = KeyStore.getInstance("PKCS12");
/* Some Code that gets 'buff' etc. */
byte[] byteBuff = hexStringToByteArray(buff);
Arrays.reverse(byteBuff);
InputStream inputStream = new ByteArrayInputStream(byteBuff);
store.load(inputStream, password.toCharArray());
OutputStream outputStream = new FileOutputStream(userName+".p12");
store.store(outputStream,anotherPassword); //Throws Exception
}
Thank you very much!
The issue is at those lines
/* Some Code that gets 'buff' etc. */
byte[] byteBuff = hexStringToByteArray(buff);
Because the other posted code would work without an exception.
char[] passwordChars = "password".toCharArray();
String fileOne = "/tmp/output_1.p12";
String fileTwo = "/tmp/output_2.p12";
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(null, null);
keyStore.store(new FileOutputStream(fileOne), passwordChars);
keyStore = KeyStore.getInstance("PKCS12");
byte[] byteBuff = Files.readAllBytes(Paths.get(fileOne));
InputStream inputStream = new ByteArrayInputStream(byteBuff);
keyStore.load(inputStream, passwordChars);
keyStore.store(new FileOutputStream(fileTwo), passwordChars);

How to add, delete or display keys from a keystore without using keytool for AES encryption?

How can I manage keystore in java without using keytool command ?
I know how to load the Key Store from the java code, but this is not what I just want, I want to create a Keystore, Display keys from a keystore or delete a Key entry from a keystore.
Is it possible to do with the java code ?
This is how i am loading the keystore,
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
// get user password and file input stream
char[] password = getPassword();
java.io.FileInputStream fis = null;
try {
fis = new java.io.FileInputStream("keyStoreName");
ks.load(fis, password);
} finally {
if (fis != null) {
fis.close();
}
}
The instructions are given here to generate a new keystore,
https://docs.oracle.com/javase/6/docs/api/java/security/KeyStore.html
but it just generate an empty keystore, not a keystore with the key inside it.
First of all, you have to create an empty keystore before adding a key inside it, and your code wouldn't work because,
To create an empty keystore using the above load method, pass null as the InputStream argument.
See the following example to see how to pass null as argument.
Creating a Keystore,
public static void createStore(String path, String keyStoreName,
String storePassword) throws KeyStoreException,
NoSuchAlgorithmException, CertificateException, IOException {
KeyStore store = KeyStore.getInstance("BKS");
char[] password = storePassword.toCharArray();
store.load(null, password);
FileOutputStream fos = new FileOutputStream(path + keyStoreName);
store.store(fos, password);
System.out.println("New Store Created !");
fos.close();
}
The above code is copied from my repo, aes-256-java-bks
According to its description, it has all the features which you need,
This simple code allows you to encrypt/decrypt any kind of file using
AES-256 standard. It uses Bouncy Castle Keystore for Key Management.
Beside Encryption, the code allows you to manage your keystore, like
Creating a new Keystore, Loading an existing keystore, adding key to
an existing keystore, generating new Key with user Password, deleting
key from a keystore or displaying keys from given keystore, all these
features could be accessed at runtime, all you need to do is execute
the program.
The following codes are from the same repository as mentioned above,
Loading store,
static KeyStore loadStore() throws KeyStoreException,
FileNotFoundException, IOException, NoSuchAlgorithmException,
CertificateException {
KeyStore store = KeyStore.getInstance("BKS");
InputStream keystoreStream = new FileInputStream(keyStoreLocation);
store.load(keystoreStream, storePassword.toCharArray());
System.out.println("Key Store loaded!\n");
return store;
}
For security reasons, you cannot display actual keys from the keystore, but you sure could get the list of all the aliases of keys from the keystore,
Check this code,
private static void getAliases() throws KeyStoreException,
FileNotFoundException, NoSuchAlgorithmException,
CertificateException, IOException {
if (store.size() == 0)
System.out.println("Store is Empty!");
Enumeration<String> enumeration = store.aliases();
while (enumeration.hasMoreElements()) {
String alias = (String) enumeration.nextElement();
System.out.println("Key Alias: " + alias);
}
}
Deleting a Key from keystore,
public static void deleteAlias(String alias) throws KeyStoreException {
store.deleteEntry(alias);
}
Your FileInputStreamis not reading "keystorename" cause it does not exists or it does, but in another location.
According to documentation:
To create an empty keystore using the above load method, pass null as the InputStream argument.

How to get validity date the digital certificate in java?

I want to read information the certificate with .pfx extension, but when load the certificate occurs this error:
failed to decrypt safe contents entry:
javax.crypto.BadPaddingException: Given final block not properly
padded
Stack trace:
(java.lang.StackTraceElement[]) [
sun.security.pkcs12.PKCS12KeyStore.engineLoad(PKCS12KeyStore.java:1304),
java.security.KeyStore.load(KeyStore.java:1214),
br.com.certificateutils.CertificatesTest.testLoadCertificateIdeal(CertificatesTest.java:48),
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method),
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57),
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43),
java.lang.reflect.Method.invoke(Method.java:606),
org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47),
org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12),
org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44),
org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17),
org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271),
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70),
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50),
org.junit.runners.ParentRunner$3.run(ParentRunner.java:238),
org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63),
org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236),
org.junit.runners.ParentRunner.access$000(ParentRunner.java:53),
org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229),
org.junit.runners.ParentRunner.run(ParentRunner.java:309),
org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50),
org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38),
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467),
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683),
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390),
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)]
My code is:
try{
KeyStore ks = KeyStore.getInstance("pkcs12", "SunJSSE");
InputStream is = new FileInputStream("C:\\certificado.pfx");
ks.load(is, "password".toCharArray()); //line ocorrus error
String alias = ks.aliases().nextElement();
Key key = ks.getKey(alias, "password".toCharArray());
Certificate[] cc = ks.getCertificateChain(alias);
X509Certificate certificate1 = (X509Certificate) cc[0];
ret += certificate1.getNotAfter();
ret += certificate1.getNotBefore();
} catch (Exception e) {
System.out.print(e.getMessage());
}
My objective is read a certificate and get validity and an unique identifier.
Here is the code
KeyStore keyStore = KeyStore.getInstance("pkcs12");
keyStore.load(newByteArrayInputStream(signature),password.toCharArray());
Enumeration<String> enums = keyStore.aliases();
while (enums.hasMoreElements()) {
String alias = enums.nextElement();
X509Certificate c = (X509Certificate)keyStore.getCertificate(alias);
LocalDateTime expiryDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(c.getNotAfter().getTime()), ZoneId.systemDefault());
}

Categories