To convert a pem file containing a x509 certificate + private key into a pkcs12 (.p12) file, the following command is being used:
openssl pkcs12 -export -inkey cert_pkey.pem -in cert_pkey.pem -out cert.p12
I am trying to accomplish the same programatically using Java with BouncyCastle library. I am able to extract the X509Cert from the PEMObject but the Private key has been confusing.
Any help in piecing together the steps is appreciated:
Open cert_pkey.pem file stream using PEMParser
Get the X509 Certificate from PemObject (done)
Get the private key from the PemObject (how?)
Create KeyStore of instance type PKCS12 with password
Finally got around how to get the cert and key separately - not sure why it worked out the way it worked out:
PEMParser pemParser = new PEMParser(new BufferedReader(new InputStreamReader(certStream)));
Object pemCertObj = pemParser.readObject();
PemObject pemKeyObj = pemParser.readPemObject();
PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(pemKeyObj.getContent());
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey privKey = kf.generatePrivate(privKeySpec);
Security.addProvider(new BouncyCastleProvider());
X509CertificateHolder certHolder = (X509CertificateHolder)pemCertObj;
X509Certificate x509cert = (new JcaX509CertificateConverter()).setProvider("BC").getCertificate(certHolder);
I got the hint when I looked up the .getType() on permCertObj and permKeyObj and got RSA CERT and RSA PRIVATE KEY respectively returned.
Couldn't figure out the difference between readObject() and readPemObject()
The PEMParser class will parse just about anything from PEM format. You can read the object from the file using that parser - if you'll print the class of that object you'l;l see it's a PEMKeyPair. That can be converted to a regular KeyPair using JcaPEMKeyConverter.
public KeyPair importKeyFromPemFile(String filePath)
{
try (FileReader reader = new FileReader(filePath))
{
PEMParser pemParser = new PEMParser(reader);
PEMKeyPair pemKeyPair = (PEMKeyPair)pemParser.readObject()
return new JcaPEMKeyConverter().getKeyPair(pemKeyPair);
}
catch (IOException | PEMException e)
{
throw new RuntimeException(e)
}
}
Related
I have created a PEMParser object to which I pass a PEM string containing chain certificate, encrypted private key etc. Which is the way to retrieve the decrypted private key and the certificate X509? I have tried with :
pemParser.readObject()
I am able to get a x509CertificateHolder (how to get the certificate from it?) and at the second call an encrypted privatekey info.
Thanks in advance.
assuming that your pem file has two entries first is cert and second is key.
another assumption is that key is of type pkcs8 and it is password protected.
first call to pemParser.readObject() is done with assumption that first entry in pem file is of x509 certificate
second call to pemParser.readObject() is done with assumption that second entry in pem file is of pkcs8 password protected key
variable certificate will contain the x509 certificate and variable finalKey will contain the private key
private void getCertAndKeyFromPemFile(String fileName, String keyPassword) throws Exception {
Security.addProvider(new BouncyCastleProvider());
PEMParser pemParser = new PEMParser(new FileReader(fileName));
JcaX509CertificateConverter x509Converter = new JcaX509CertificateConverter().setProvider(new BouncyCastleProvider());
X509Certificate certificate =x509Converter.getCertificate((X509CertificateHolder) pemParser.readObject());
PKCS8EncryptedPrivateKeyInfo privateKeyInfo = (PKCS8EncryptedPrivateKeyInfo) pemParser.readObject();
InputDecryptorProvider decryptorProvider = new JceOpenSSLPKCS8DecryptorProviderBuilder().build(keyPassword.toCharArray());
PrivateKey finalKey = new JcaPEMKeyConverter().getPrivateKey(privateKeyInfo.decryptPrivateKeyInfo(decryptorProvider));
}
Generate some keys with OpenSSL, then encode them in Base64 and obtain them and try to generate them to validate the authentication with JWT. Here is the code and description of what happens to me
Generate with the following commands:
openssl req -x509 -newkey rsa:4096 -keyout private_key.pem -out public_key.der
openssl pkcs12 -export -out keyStore.p12 -inkey private_key.pem -in public_key.der
base64 –w 0 private_key.pem > private_key_base64_enc.txt
base64 –w 0 public_key.der > public_key_base64_enc.txt
I saved in my vault.keystore from wildfly: private_key_base64_enc.txt and public_key_base64_enc.txt
Then in my java class I write the following:
private void jwtSignedAuthentication(String token, PropName vaultBlockName) throws Exception
{
String rsa512Alias = vaultBlockName.getDefaultValue();
String rsa512pvt = VaultReader.getValue(rsa512Alias, "privateKey");
String rsa512pbc = VaultReader.getValue(rsa512Alias, "publicKey");
KeyFactory keyfatc = null;
PrivateKey privateKey = null;
PublicKey publicKey = null;
try {
keyfatc = KeyFactory.getInstance("RSA");
} catch (NoSuchAlgorithmException e) {
logger.error(e);
}
StringBuilder pkcs8Lines = new StringBuilder();
BufferedReader rdr = new BufferedReader(new StringReader(new String(Base64.getDecoder().decode(rsa512pvt.getBytes()))));
String line;
while ((line = rdr.readLine()) != null) {
pkcs8Lines.append(line);
}
// Remove the "BEGIN" and "END" lines, as well as any whitespace
String pkcs8Pem = pkcs8Lines.toString();
pkcs8Pem = pkcs8Pem.replace("-----BEGIN ENCRYPTED PRIVATE KEY-----", "");
pkcs8Pem = pkcs8Pem.replace("-----END ENCRYPTED PRIVATE KEY-----", "");
pkcs8Pem = pkcs8Pem.replaceAll("\\s+","");
byte[] dataPvt = Base64.getDecoder().decode(pkcs8Pem.getBytes());
PKCS8EncodedKeySpec specPvt = new PKCS8EncodedKeySpec(dataPvt);
byte[] dataPbc = Base64.getDecoder().decode(rsa512pbc.getBytes());
StringBuilder publicLinesBuilder = new StringBuilder();
BufferedReader readerPlubKey = new BufferedReader(new StringReader(new String(dataPbc)));
String lineP;
while ((lineP = readerPlubKey.readLine()) != null) {
publicLinesBuilder.append(lineP);
}
String pubK = publicLinesBuilder.toString();
pubK = pubK.replace("-----BEGIN CERTIFICATE-----", "");
pubK = pubK.replace("-----END CERTIFICATE-----", "");
pubK = pubK.replaceAll("\\s+","");
X509EncodedKeySpec specPbc = new X509EncodedKeySpec(Base64.getDecoder().decode(pubK.getBytes()));
try {
privateKey = keyfatc.generatePrivate(specPvt);
publicKey = keyfatc.generatePublic(specPbc);
} catch (InvalidKeySpecException e) {
logger.error(e);
}
Algorithm algorithm = Algorithm.RSA512((RSAPublicKey) publicKey, (RSAPrivateKey) privateKey);
// Creación de un verificador JWT
JWTVerifier verifier = JWT.require(algorithm).withIssuer(JWT_CLAIM_ISSUER).acceptLeeway(2).build();
UserContext userContext = new UserContext();
userContext.setUserName(JWT_CLAIM_ISSUER);
try {
// Decode JWT, verificación del token.
#SuppressWarnings("unused")
DecodedJWT decodeJwt = verifier.verify(token);
} catch (JWTDecodeException e) {
logger.error(e);
}
}
When I try to generate the keys I return null:
privateKey = keyfatc.generatePrivate(specPvt);
publicKey = keyfatc.generatePublic(specPbc);
Anyone have any idea what happens with this. Thanks in advance
For generate my JWT:
public ResteasyWebTarget getClientWebAgent(String host, String blockName) throws KeyStoreException
{
ResteasyClient clientBuilder = new ResteasyClientBuilder().establishConnectionTimeout(10, TimeUnit.SECONDS).socketTimeout(5, TimeUnit.SECONDS).build();
ResteasyWebTarget target = clientBuilder.target(host);
KeyPair keys = null;
try {
keys = keyStore.getKeys();
/*logger.infov(new String(Base64.getEncoder().encode(keys.getPrivate().getEncoded())));
logger.infov("****PUBLIC KEY ******");
logger.infov(new String(keys.getPublic().getEncoded()));*/
} catch (IOException e) {
logger.error(e);
}
Algorithm algorithm = Algorithm.RSA512((RSAPublicKey) keys.getPublic(), (RSAPrivateKey) keys.getPrivate());
Map<String, Object> headerClaims = new HashMap<>();
headerClaims.put("alg", "RS512");
headerClaims.put("typ", "JWT");
JWTCreator.Builder jwtCreator = JWT.create();
jwtCreator.withHeader(headerClaims);
jwtCreator.withIssuer(JWT_CLAIM_ISSUER);
jwtCreator.withIssuedAt(LocalDate.now().toDate());
jwtCreator.withExpiresAt(LocalDate.now().toDateTimeAtCurrentTime().plusSeconds(30).toDate());
String jwtToken = jwtCreator.sign(algorithm);
target.register(new BearerAuthenticator(jwtToken));
target.register(new LanguageHeaderToken(Locale.getDefault()));
return target;
}
Your 'public key' is actually a certificate (specifically an X.509 v1 or v3 certificate, depending on your openssl config), which contains a publickey but is different from a publickey -- and is in PEM format even though you have misleadingly named it .der -- and your privatekey is encrypted.
In addition to the approach of using a PKCS12, as Roberto validly proposes and is usually the simplest because it's only one file to manage and is still encrypted and thus more secure:
Java can handle an X.509 certificate, but you use a CertificateFactory.getInstance("X.509") and give it an InputStream instead of a KeyFactory and an X509EncodedKeySpec. CertificateFactory can handle either PEM or DER, unlike KeyFactory which can handle only DER, so you don't need the de-PEM (strip BEGIN/END/EOL and decode base64) parts.
standard Java cannot handle encrypted PKCS8 keys directly. If you can add a thirdparty library, BouncyCastle's bcpkix can do so; search the dozen or so existing Qs that use PEMParser (not PEMReader, that's the older version) and JceOpenSSLPKCS8DecryptorBuilder. Otherwise, you can add -nodes to your req -newkey -x509 command to generate an unencrypted privatekey file, which after you de-PEM it does work in KeyFactory with PKCS8EncodedKeySpec. (It's still spelled -nodes even though the encryption used without it hasn't been plain aka single DES for decades.) Using an unencrypted privatekey file of course means that any intruder or malware on your system that can read that file can get your privatekey, which in many situations is a risk.
finally, if you really want only the keypair and not a certificate, don't bother with req -newkey -x509. Instead use openssl genpkey to generate the privatekey, or the older but simpler openssl genrsa -nodes followed by (or piped to) openssl pkcs8 -topk8 -nocrypt to convert it to PKCS8-unencrypted format. Then use openssl pkey -pubout or the older openssl rsa -pubout to make a separate file with the publickey. Those commands can write (and read back where applicable) DER format instead of PEM; if you do that, your code doesn't need the de-PEM steps, you can just pass the binary file contents to KeyFactory. The risks for an unencrypted file are the same as above.
Maybe you are generating the keystore without assigning a valid alias, looking at your command you are not using the -name option.
The command should be like this:
openssl pkcs12 -export -out keyStore.p12 -inkey private_key.pem -in public_key.der -name "alias"
A smarter way to use the keys in java is by creating a KeyPair:
KeyPair loadKeyPair() throws Exception {
// Read keystore from resource folder
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
URL resource = classLoader.getResource("keyStore.p12");
File file = new File(Objects.requireNonNull(resource).toURI());
char[] keyPass = "1234".toCharArray();
String alias = "alias";
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
try (FileInputStream is = new FileInputStream(file)) {
keystore.load(is, keyPass);
}
Key key = keystore.getKey(alias, keyPass);
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
return new KeyPair(publicKey, (PrivateKey) key);
}
return null;
}
Then extract RSAPublicKey and RSAPrivateKey keys from the KeyPair:
void loadKeys() throws Exception{
KeyPair keyPair = loadKeyPair();
if (null != keyPair) {
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
}
}
Hope it can be helpful and good luck with your Json Web Tokens! :-p
I have a key created with OpenSSL from a previous app with the commands:
openssl req -nodes -newkey rsa:2048 -keyout root.key \
-out root.csr -config ./openssl.cnf
I changed it to a PKCS8 key since I need to use that key in Java with:
openssl pkcs8 -topk8 -nocrypt -in pkcs1_key_file -out pkcs8_key.pem
As far as I can tell, this works since I'm able to create a SSLContext with it. I'm having trouble recreating a KeyPair object in order to perform other operations with it. I've tried:
Path privateKeyPath = Paths.get("root.key.pem");
File privateKeyFile = new File( System.getProperty("user.dir") + File.separator + "ue.key.pem");
byte[] bytes = Files.readAllBytes(privateKeyPath);
PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(bytes);
BufferedReader br = new BufferedReader(new FileReader(privateKeyPath.toFile()));
PEMParser pemParser = new PEMParser(new FileReader(privateKeyFile));
PrivateKeyInfo privateKeyInfo = (PrivateKeyInfo) pemParser.readObject(); // ?????
I've seen other code like Read an encrypted private key with bouncycastle/spongycastle, where they do pemParser.readObject, the object is of type PEMEncryptedKeyPair, or they use the converter to getKeyPair(), but when I call readObject, my object is of type PrivateKeyInfo so I cannot call getKeyPair either.
Is there a step somewhere I'm missing in either the changing to PKCS8 key with the OpenSSL command, or in trying to reconstruct the KeyPair?
I am Signing some text using "Windows-MY" KeyStore .
I want to sign using my private key and verify using Public Key.
KeyStore keyStore = KeyStore.getInstance("Windows-MY");
keyStore.load(null, null);
Enumeration en = keyStore.aliases();
while (en.hasMoreElements()) {
KeyStore keyStore = KeyStore.getInstance("Windows-MY");
keyStore.load(null, null);
String alias = en.nextElement().toString();
X509Certificate c = (X509Certificate) keyStore.getCertificate(alias);
String serialNumber = c.getSerialNumber().toString();
System.out.println("--" + aliasName);
PrivateKey privateKey = (PrivateKey) keyStore.getKey(aliasName, null);
PublicKey publicKey = (PublicKey) c.getPublicKey();
Certificate[] chain = keyStore.getCertificateChain(aliasName);
DataOutputStream fout = new DataOutputStream(outstream);
// -------------------------------------------------------
String data = "Monika";
byte[] content = data.getBytes();
Provider p = keyStore.getProvider();
// ----------------------signature---start---------------------------
Signature signature = Signature.getInstance("SHA256withRSA", p);
System.out.println(" signature.getProvider():"+ signature.getProvider());
signature.initSign(privateKey);
signature.update(content);
byte[] signatureBytes = signature.sign();
System.out.println("signatureBytes-------------"+ signatureBytes.toString());
// ----------------------signature----------end------------------
// ------------------------verification---------------
Signature signature1 = Signature.getInstance("SHA256withRSA", p);
System.out.println(" signature1.getProvider():"+ signature1.getProvider());
signature1.initVerify(publicKey);
signature1.update(content);
boolean verifies = signature1.verify(signatureBytes);
System.out.println("signature verifies: " + verifies);
// ------------------------------------------------
fout.close();
} // while
Output:
privateKey:RSAPrivateKey [size=2048 bits, type=Exchange, container=AC0BEBA9-A361-4611-96D9-B365B671FBC3]
signature.getProvider():SunMSCAPI version 1.6
signatureBytes-------------[B#1402d5a
signature1.getProvider():SunRsaSign version 1.5
signature verifies: false
Notice that:
My Private key is already RSAPrivateKey .
Provider for Signing is SunMSCAPI.
But I dont know about Provider for Verification with PrivateKey.
There are several issues with your code:
You are simply using the first certificate / public key from your windows keystore. This might actually be the right one here, but there might be more than one certificate in the keystore and then it is just coincidence which certificate you are using for verify.
String alias = en.nextElement().toString();
X509Certificate c = (X509Certificate) keyStore.getCertificate(alias);
PublicKey publicKey = c.getPublicKey();
PrivateKey privateKey = (PrivateKey) keyStore.getKey(DSCName, null);
You should write keyStore.getCertificate(DSCName) instead to make sure it matches the private key.
You are generating a key (resp. trying to convert the existing key) for no reason. You can remove this code completely. This will also solve your problem with the NullPointerException:
byte[] encodedPrivateKey = privateKey.getEncoded();
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
RSAPrivateKey privateKey1 = (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
There is a lot of unnecessary code in your question, like loading the certificate chain, but never using it. That makes it harder to fix. A minimal (working) example would look like this:
String alias = "myAlias";
String myData = "data to encrypt";
KeyStore keyStore = KeyStore.getInstance("Windows-MY");
keyStore.load(null, null);
X509Certificate cert = (X509Certificate) keyStore.getCertificate(alias);
PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, null);
PublicKey publicKey = cert.getPublicKey();
Signature instance = Signature.getInstance("SHA256withRSA");
instance.initSign(privateKey, new SecureRandom());
instance.update(myData.getBytes("UTF-8"));
byte[] signedBytes = instance.sign();
instance.initVerify(publicKey);
instance.update(myData.getBytes("UTF-8"));
System.out.println(instance.verify(signedBytes));
Signature signature = Signature.getInstance("SHA256withRSA",p);
System.out.println(" signature.getProvider():"+ signature.getProvider());
signature.initSign(privateKey, new SecureRandom());
signature.update(byteData);
byte[] signatureBytes = signature.sign();
// X509Certificate cert1 =signatureBytes.
System.out.println("signatureBytes-------------"+ signatureBytes.toString());
// ----------------------signature----------end------------------
// ------------------------verification---------------
Signature signature1 = Signature.getInstance("SHA256withRSA");
System.out.println(" signature1.getProvider():"+ signature1.getProvider());
signature1.initVerify(publicKey);
signature1.update(byteData);
boolean verifies = signature1.verify(signatureBytes);
System.out.println("signature verifies: " + verifies);
You are getting null here
byte[] encodedPrivateKey = privateKey.getEncoded(); // are you sure that this byte array is not null ?
To make things more safe check here:
PrivateKey privateKey = (PrivateKey) keyStore.getKey(
DSCName, null); // this maybe returning null
so before the line which gives error, make a check:
if(encodedPrivateKey==null){
System.out.println("private key is null");
}
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(
encodedPrivateKey);
Check this complete and working code to verify signature after signing some text/data using digest SHA256withRSA:
/* verifyRSAsha256.java */
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
import javax.xml.bind.DatatypeConverter;
/*
Compile:
clear && javac verifyRSAsha256.java && java verifyRSAsha256
Create private key:
openssl genrsa -des3 -out encrypted.pem 2048 && openssl rsa -in encrypted.pem -out private.pem -outform PEM && openssl rsa -in private.pem -pubout > public.pem
Create signature:
/bin/echo -n "some text that you want to be trusted" > data.txt
openssl dgst -sha256 -sign private.pem data.txt > signature.tmp
base64 signature.tmp
Verify signature:
openssl dgst -sha256 -verify public.pem -signature signature.tmp data.txt
*/
public class verifyRSAsha256 {
public static void main(String args[]){
String publicKey =
// "-----BEGIN PUBLIC KEY-----"+
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwns0JWYgEshlpLYsZQFc"+
"d5iVSqIHDO0zISLlO1aK4bbbosSvRE81+inKrG5mlnkIrv0+mJ/qTLY1RdBAVAe4"+
"GPLTpHmLJhEtq7stydm2cCTEPRwfJNjoHqATDHEm1KLVGA8k0hztfMr8fLChE3/K"+
"n2MHxzs7qhMLyBdPqbVC9RNja3i+Nl814xPTSXJ50zdJMLC56VtIU0xjqNjXN8iQ"+
"pLZ2EfcP55nZ/venD01yxfsUn4sQLFTAlXqygA10fdDv9y0eZvgaGGSb4MuPT7yD"+
"BfgNEU3tl4nRdSzPNkCkCmkuaa/pqZ5uw+G0HBwaQlHDwsnIcwE/xo6aHpt4xF4W"+
"/QIDAQAB";
// "-----END PUBLIC KEY-----";
byte[] signature, data;
// the signature is a binary data and I encoded it with base64, so the signature must be decoded from base64 to binary again
signature = DatatypeConverter.parseBase64Binary("Yy9CdQDfdYWwZkSu2SZgoFABHk5Bd3tzYvX73QR+GDCWpUsWrO5CXRF+j3dBz+bq1SRQ+1c1hdez5mMeE1587s4Mos8EsT1sqNemu4l4535P+jYicwG1m2MAesquAHhIIAyY9iGID576ehX0/34rCCeGuVZablpL+2ki6cEwxPVlH7xtWNIc1AdxivHjkWorkWC1LrbfcNdbZhUrNuz7DZsxHP2sr+2TQdD4L9CA2bgpj6HeQt+MTfCf2PKSdVoLFdwnM8638jHL6MVcEJxeIow/YUDZGEAyR743RdRk4CGU1bJ7er9M1Q4hFfYWGOBsLBok2XXUJcchLgWET1eKdA==");
// the signature length have to be 256 bytes
System.out.print("Signature length 256 = ");
System.out.println(signature.length);
// the data used the generate the signature
data = "some text that you want to be trusted".getBytes();
// verify if signature is ok
try {System.out.println(verify(data,signature,publicKey));}catch(GeneralSecurityException e){e.printStackTrace();}
// if any byte of data changes (ex: change last byte from d to D)
data = "some text that you want to be trusteD".getBytes();
// the signature doesn't math and method verify will fail
try {System.out.println(verify(data,signature,publicKey));}catch(GeneralSecurityException e){e.printStackTrace();}
}
private static boolean verify(byte[] data, byte[] signature, String publicKey) throws GeneralSecurityException{
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(DatatypeConverter.parseBase64Binary(publicKey));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initVerify(pubKey);
sig.update(data);
return sig.verify(signature);
}
}
You can create a private and public key using openssl command line tool:
openssl genrsa -des3 -out encrypted.pem 2048
openssl rsa -in encrypted.pem -out private.pem -outform PEM
openssl rsa -in private.pem -pubout > public.pem
You can create one signature with your private key using openssl command line tool:
/bin/echo -n "some text that you want to be trusted" > data.txt
openssl dgst -sha256 -sign private.pem data.txt > signature.tmp
You can verify if the signature is correct using openssl command line tool:
openssl dgst -sha256 -verify public.pem -signature signature.tmp data.txt
I have .p12 file, I am extracting the private key using openssl, I have a password for extracting it.
openssl pkcs12 -in my.p12 -nocerts -out privateKey.pem
And after I get my private key, I'm trying to use that key for encryption:
public static void main(String[] args) throws Exception {
Security.addProvider(new BouncyCastleProvider());
KeyPair keyPair = readKeyPair(privateKey, "testpassword".toCharArray());
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
byte[] textEncrypted = cipher.doFinal("hello world".getBytes());
System.out.println("encrypted: "+new String(textEncrypted));
cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
byte[] textDecrypted = cipher.doFinal(textEncrypted);
System.out.println("decrypted: "+new String(textDecrypted));
}
private static KeyPair readKeyPair(File privateKey, char[] keyPassword) throws IOException {
FileReader fileReader = new FileReader(privateKey);
PEMReader r = new PEMReader(fileReader, new DefaultPasswordFinder(keyPassword));
try {
return (KeyPair) r.readObject(); // this returns null
} catch (IOException ex) {
throw new IOException("The private key could not be decrypted", ex);
} finally {
r.close();
fileReader.close();
}
}
r.readObject(); returns null. But when I create a private key by myself by this command:
openssl genrsa -out privkey.pem 2048
The above code works fine.
How can I extract private key from p12 file properly?
Or is there any way to use p12 file for encrypt/decrypt the text
without extracting through command line?
I know it is just PKCS#12 is just archaive file which stores keys.
I don't know what is wrong with your code, but I have code that reads stuff from a key store. I read the file into a KeyStore instance and then access the key or entry as appropriate. Here are some of the relevant calls:
char[] password;
String alias;
java.security.KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC");
keyStore.load(inputStream, password);
java.security.PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, password);
java.security.keystore.PrivateKeyEntry privateKeyEntry = (PrivateKeyEntry) keyStore.getEntry(alias, new KeyStore.PasswordProtection(password));
To find the alias of the entry you are interested in, I suggest using keytool (comes with JDK):
keytool -list -v -keystore keystore.pkcs12 -storetype pkcs12
You will be prompted for the keystore password and then get information like this:
Keystore type: PKCS12
Keystore provider: SunJSSE
Your keystore contains 1 entry
Alias name: thealias
Creation date: Aug 30, 2013
Entry type: PrivateKeyEntry
Certificate chain length: 2
[... lots of info about the certificates deleted ...]