KeyStore not saving to file - java

I am trying to store multiple private keys in a JKS file using the Java KeyStore library. I created a method which writes and reads to the JKS file but the private key isn't being saved in the file.
When I store something into the KeyStore I can get all the aliases in the keystore and the new key is there. Once the method is closed and the same key is attempted to be pulled it does not find the key.
Main.java
public static void main(String[] args) throws Exception {
//Create keys
main m = new main();
m.getOrSetPrivateKey("123", "123", privateKey, false);
PrivateKey p = m.getOrSetPrivateKey("123", "123", null, true);
if (p.equals(c.getPriv_key()))
System.err.println("Equal");
else
System.err.println("Not equal !!!!!!!!");
}
private synchronized PrivateKey getOrSetPrivateKey(String alias, String id, PrivateKey c, boolean read ) throws InterruptedException, IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException, InvalidKeySpecException, NotSupportedException, UnrecoverableKeyException {
PrivateKey key = null;
InputStream inpusStream = new FileInputStream(getFile2(Constants.JKS_PRIVATE_FILE_NAME));
KeyStore keyStore = null;
try {
keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(inpusStream, Constants.JKS_PRIVATE_FILE_PASSWORD);
} finally {
if (inpusStream != null)
inpusStream.close();
}
Enumeration<String> s = keyStore.aliases();
while (s.hasMoreElements())
System.err.println("[ " + s.nextElement() + " ]");
//Generate password for this private key
char [] pass = getKeyPassword(c, alias, id);
if (read == true) { //If reading/getting private key from file store
boolean isKeyEntry = keyStore.isKeyEntry(alias);//Check if there is a key with the alias deviceSerialnumber
if (!isKeyEntry) {//No key with this alias exists
throw new KeyStoreException("No key with alias " + alias + " exists!");
}
key = (PrivateKey) keyStore.getKey(alias, pass);
} else { //Writing/ saving key to the file store
keyStore.setKeyEntry(alias, c , pass, new Certificate[] { createCertificate() });
FileOutputStream out = new FileOutputStream(new File(Constants.JKS_PRIVATE_FILE_NAME), true);
try {
keyStore.store(out, pass);
System.out.println("Alias exists = " + keyStore.containsAlias(alias));
} finally {
if (out != null)
out.close();
}
}
s = keyStore.aliases();
while (s.hasMoreElements())
System.err.println("( " + s.nextElement() + " )");
return key;
}
Output:
[ mykey ]
( 123 )
( mykey )
Alias exists = true
[ mykey ]
Exception in thread "main" java.security.KeyStoreException: No key with alias 123 exists!
Why is the key not being saved to the JKS file file?

You are appending to the existing keystore instead of replacing it because you are passing "true" to the FileOutputStream constructor.
FileOutputStream out = new FileOutputStream(new File(Constants.JKS_PRIVATE_FILE_NAME), true);
Replace the line above with the following:
FileOutputStream out = new FileOutputStream(new File(Constants.JKS_PRIVATE_FILE_NAME));

The problem was in the FileOutputStream was pointing to the wrong file.
FileOutputStream out = new FileOutputStream(new File(Constants.JKS_PRIVATE_FILE_NAME), true);
Should be using the getFile2 method like this:
FileOutputStream out = new FileOutputStream(getFile2(Constants.JKS_PRIVATE_FILE_NAME));
As Palamino pointed out, don't need to include true in the FileOutputStream constructor.
Also the key store should have been using the JKS file password, not the password that is generated by getKeyPassword().
Changed this:
keyStore.store(out, pass);
To use the JKS file password, like this:
keyStore.store(out, Constants.JKS_PRIVATE_FILE_PASSWORD);

Related

Working with Java.io.file, when ever I try to read a cert from it it always points to wrong path

I am trying to read a cert with file IO , every time I try accessing my cert under
testApp/src/main/resources -> cert
it always reads
X:\workspace1\testApp\target\classes\cert\test.p12
And here is my code that I am using, It always exceptions out with null pointer.
// String fileName = "config/sample.txt";
ClassLoader classLoader = App2.class.getClassLoader();
File file = new File(classLoader.getResource("cert/test.p12").getFile());
FileInputStream fm = new FileInputStream(file);
KeyStore ks = KeyStore.getInstance("PKCS12");
try {
ks.load(fm, "test".toCharArray());
}
catch(Exception e) {
e.printStackTrace();
}
Key key = ks.getKey("test", "test".toCharArray());
Certificate cert = ks.getCertificate("test");
PublicKey publicKey = cert.getPublicKey();
System.out.println("Public key");
System.out.println(Base64.getEncoder().encodeToString(publicKey.getEncoded()));
fm.close();
I want to read this cert to extract public or private key.
this worked for me
File file = new File(classLoader.getResource("./cert/test.p12").getFile());

Adobe - Signature is timestamped but the timestamp could not be verified

I'm fighting with creating signature with timestamp on my pdf file. After many attempts we succeeded and signed PDF file. Adobe verified this file but there is one mistake with timestamp. There is information about:
Signature is timestamped but the timestamp could not be verified
Is this signature was created inproperly?
There is a code
public String signByPfxCert(String filePath) {
String postfix = "-signed";
try {
PdfReader reader = new PdfReader(filePath);
OutputStream os = new FileOutputStream(filePath + postfix);
PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0');
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setReason("REASON");
appearance.setLocation("LOCATION");
Security.addProvider(new BouncyCastleProvider());
FileInputStream fis = new FileInputStream(getClass().getClassLoader().
getResource("clientcert.pfx").getFile());
String password = "pwd12345";
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(fis, password.toCharArray());
String alias = ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, password.toCharArray());
X509Certificate cert = (X509Certificate) ks.getCertificate(alias);
com.itextpdf.text.pdf.security.TSAClient tsc = new TSAClientBouncyCastle(tsaUrl);
ExternalDigest digest = new BouncyCastleDigest();
ExternalSignature signature = new PrivateKeySignature(pk, "SHA-1", "BC");
MakeSignature.signDetached(appearance, digest, signature, new Certificate[]{cert}, null, null, tsc, 0,
MakeSignature.CryptoStandard.CMS);
if (fis.available() != 0) {
fis.close();
}
File originalFile = new File(filePath);
File signedFile = new File(filePath + postfix);
boolean deleteOriginal = originalFile.delete();
File destination = new File(filePath);
boolean rename = signedFile.renameTo(destination);
if(deleteOriginal && rename){
return destination.getName();
}else {
return "";
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}

Is it possible to store secret keys on SoftHSM?

I've found this thread: Connecting to SoftHSM java and it works when storing private keys, just like the example.
But I need to store secret keys, such as AES.
Here's my code:
import java.security.*;
import sun.security.pkcs11.*;
import javax.crypto.spec.SecretKeySpec;
public class Main {
public static void main(String[] args) throws Exception {
// Set up the Sun PKCS 11 provider
String configName = "softhsm.cfg";
Provider p = new SunPKCS11(configName);
if (-1 == Security.addProvider(p)) {
throw new RuntimeException("could not add security provider");
}
// Load the key store
char[] pin = "mypin".toCharArray();
KeyStore keyStore = KeyStore.getInstance("PKCS11", p);
keyStore.load(null, pin);
// AES key
SecretKeySpec secretKeySpec = new SecretKeySpec("0123456789ABCDEF".getBytes(), "AES");
Key key = new SecretKeySpec(secretKeySpec.getEncoded(), "AES");
keyStore.setKeyEntry("AA", key, "1234".toCharArray(), null);
keyStore.store(null); //this gives me the exception.
}
}
And this is the softhsm.cfg file:
name = SoftHSM
library = /usr/local/lib/softhsm/libsofthsm.so
slot = 0
attributes(generate, *, *) = {
CKA_TOKEN = true
}
attributes(generate, CKO_CERTIFICATE, *) = {
CKA_PRIVATE = false
}
attributes(generate, CKO_PUBLIC_KEY, *) = {
CKA_PRIVATE = false
}
When executing keyStore.store(null) I'm getting java.security.KeyStoreException Cannot convert to PKCS11 keys
Turns out the Exception occurs with SoftHSMv1. I installed SoftHSMv2, wich you can get using git to download it from GitHub, and use it to store secret keys. Don't download SoftHSMv2 from the OpenDNSsec website because it won't work!!.
Finally I had to change the softhsm.cfg file to point the new library and for some reason I ignore, SoftHSM2 changes the number of the initializated slot, you can verify it using sudo softhsm2-util --show-slots
softhsm.cfg:
name = SoftHSM
library = /usr/local/lib/softhsm/libsofthsm2.so
slot = 498488451
attributes(generate, *, *) = {
CKA_TOKEN = true
}
attributes(generate, CKO_CERTIFICATE, *) = {
CKA_PRIVATE = false
}
attributes(generate, CKO_PUBLIC_KEY, *) = {
CKA_PRIVATE = false
}
My code:
import java.security.*;
import sun.security.pkcs11.*;
import javax.crypto.spec.SecretKeySpec;
public class Main {
public static void main(String[] args) throws Exception {
// Set up the Sun PKCS 11 provider
String configName = "softhsm.cfg";
Provider p = new SunPKCS11(configName);
if (-1 == Security.addProvider(p)) {
throw new RuntimeException("could not add security provider");
}
// Load the key store
char[] pin = "mypin".toCharArray();
KeyStore keyStore = KeyStore.getInstance("PKCS11", p);
keyStore.load(null, pin);
// AES key
SecretKeySpec secretKeySpec = new SecretKeySpec("0123456789ABCDEF".getBytes(), "AES");
Key key = new SecretKeySpec(secretKeySpec.getEncoded(), "AES");
keyStore.setKeyEntry("AA", key, "1234".toCharArray(), null);
keyStore.store(null); //this no longer gives me the exception.
Enumeration<String> aliases = keyStore.aliases();
while(aliases.hasMoreElements()){
String alias = aliases.nextElement();
System.out.println(alias + ": " + keyStore.getKey(alias,"1234".toCharArray()));
}
}
}
Which gives me the output:
AA: SunPKCS11-SoftHSM AES secret key, 16 bits (id 2, token object, not sensitive, unextractable)
If you try to get the key using something like keyStore.getKey("AA", "1234".toCharArray()); you'll get an objet with some attributes of the key but you wont be able to use .getEncoded() to actually get the key itself since it is unextractable.

RSA - bouncycastle PEMReader returning PEMKeyPair instead of AsymmetricCipherKeyPair for reading private key

I have a function that successfully reads a openssl formatted private key:
static AsymmetricKeyParameter readPrivateKey(string privateKeyFileName)
{
AsymmetricCipherKeyPair keyPair;
using (var reader = File.OpenText(privateKeyFileName))
keyPair = (AsymmetricCipherKeyPair)new PemReader(reader).ReadObject();
return keyPair.Private;
}
and returns an AsymmetricKeyParameter which is then used to decrypt an encrypted text.
Below is the decrypt code:
public static byte[] Decrypt3(byte[] data, string pemFilename)
{
string result = "";
try {
AsymmetricKeyParameter key = readPrivateKey(pemFilename);
RsaEngine e = new RsaEngine();
e.Init(false, key);
//byte[] cipheredBytes = GetBytes(encryptedMsg);
//Debug.Log (encryptedMsg);
byte[] cipheredBytes = e.ProcessBlock(data, 0, data.Length);
//result = Encoding.UTF8.GetString(cipheredBytes);
//return result;
return cipheredBytes;
} catch (Exception e) {
Debug.Log ("Exception in Decrypt3: " + e.Message);
return GetBytes(e.Message);
}
}
These work in C# using bouncy castle library and I get the correct decrypted text. However, when I added this to Java, the PEMParser.readObject() returns an object of type PEMKeyPair instead of AsymmetricCipherKeyPair and java throws an exception trying to cast it. I checked in C# and it is actually returning AsymmetricCipherKeyPair.
I don't know why Java behaves differently but I hope someone here can help how to cast this object or read the privatekey file and decrypt successfully. I used the same public and privatekey files in both C# and Java code so I don't think the error is from them.
Here for reference the Java version of how I'm reading the privatekey:
public static String readPrivateKey3(String pemFilename) throws FileNotFoundException, IOException
{
AsymmetricCipherKeyPair keyParam = null;
AsymmetricKeyParameter keyPair = null;
PEMKeyPair kp = null;
//PrivateKeyInfo pi = null;
try {
//var fileStream = System.IO.File.OpenText(pemFilename);
String absolutePath = "";
absolutePath = Encryption.class.getProtectionDomain().getCodeSource().getLocation().getPath();
absolutePath = absolutePath.substring(0, (absolutePath.lastIndexOf("/")+1));
String filePath = "";
filePath = absolutePath + pemFilename;
File f = new File(filePath);
//return filePath;
FileReader fileReader = new FileReader(f);
PEMParser r = new PEMParser(fileReader);
keyParam = (AsymmetricCipherKeyPair) r.readObject();
return keyParam.toString();
}
catch (Exception e) {
return "hello: " + e.getMessage() + e.getLocalizedMessage() + e.toString();
//return e.toString();
//return pi;
}
}
The Java code has been updated to a new API, which is yet to be ported across to C#. You could try the equivalent (but now deprecated) Java PEMReader class. It will return a JCE KeyPair though (part of the reason for the change was because the original version worked only with JCE types, not BC lightweight classes).
If using PEMParser, and you get back a PEMKeyPair, you can use org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter.getKeyPair to get a JCE KeyPair from it. Ideally there would be a BCPEMKeyConverter, but it doesn't appear to have been written yet. In any case, it should be easy to make an AsymmetricCipherKeyPair:
PEMKeyPair kp = ...;
AsymmetricKeyParameter privKey = PrivateKeyFactory.createKey(kp.getPrivateKeyInfo());
AsymmetricKeyParameter pubKey = PublicKeyFactory.createKey(kp.getPublicKeyInfo());
new AsymmetricCipherKeyPair(pubKey, privKey);
Those factory classes are in the org.bouncycastle.crypto.util package.

Importing PEM encrypted key pair in java using bouncycastle

I'm writing a program that uses RSA for various tasks.
I know how to generate and write the key pair to file, but I cannot load the encrypted (AES-256-CFB) key pair to a KeyPair object.
So the question is: how do I load/decrypt an encrypted PEM key pair as a java.security.KeyPair object using the BouncyCastle library?
Thanks.
Generation/export code:
public void generateKeyPair(int keysize, File publicKeyFile, File privateKeyFile, String passphrase) throws FileNotFoundException, IOException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException {
SecureRandom random = new SecureRandom();
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "BC");
generator.initialize(keysize, random);
KeyPair pair = generator.generateKeyPair();
Key pubKey = pair.getPublic();
PEMWriter pubWriter = new PEMWriter(new FileWriter(publicKeyFile));
pubWriter.writeObject(pubKey);
pubWriter.close();
PEMWriter privWriter = new PEMWriter(new FileWriter(privateKeyFile));
if (passphrase == null) {
privWriter.writeObject(pair);
} else {
PEMEncryptor penc = (new JcePEMEncryptorBuilder("AES-256-CFB"))
.build(passphrase.toCharArray());
privWriter.writeObject(pair, penc);
}
privWriter.close();
}
I am assuming that you have set BouncyCastle as the security provider, for example with:
Security.addProvider(new BouncyCastleProvider());
The code you provided creates two key files, one for the private key and one for the public key. However, the public key is implicitly contained in the private key, so we only have to read the private key file to reconstruct the key pair.
The main steps then are:
Creating a PEMParser to read from the key file.
Create a JcePEMDecryptorProvider with the passphrase required to decrypt the key.
Create a JcaPEMKeyConverter to convert the decrypted key to a KeyPair.
KeyPair loadEncryptedKeyPair(File privateKeyFile, String passphrase)
throws FileNotFoundException, IOException {
FileReader reader = new FileReader(privateKeyFile);
PEMParser parser = new PEMParser(reader);
Object o = parser.readObject();
if (o == null) {
throw new IllegalArgumentException(
"Failed to read PEM object from file!");
}
JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
if (o instanceof PEMKeyPair) {
PEMKeyPair keyPair = (PEMKeyPair)o;
return converter.getKeyPair(keyPair);
}
if (o instanceof PEMEncryptedKeyPair) {
PEMEncryptedKeyPair encryptedKeyPair = (PEMEncryptedKeyPair)o;
PEMDecryptorProvider decryptor =
new JcePEMDecryptorProviderBuilder().build(passphrase.toCharArray());
return converter.getKeyPair(encryptedKeyPair.decryptKeyPair(decryptor));
}
throw new IllegalArgumentException("Invalid object type: " + o.getClass());
}
Example usage:
File privKeyFile = new File("priv.pem");
String passphrase = "abc";
try {
KeyPair keyPair = loadEncryptedKeyPair(privKeyFile, passphrase);
} catch (IOException ex) {
System.err.println(ex);
}
Reference: BouncyCastle unit test for key parsing (link).

Categories

Resources