Extracting private key in java - java

I have certificate created using java class CertAndKeyGen and X500Name and I am able to generate the certificate which is in byte array. Now I want the private key I used in certificate and convert it into readable format. Below is the code I used to create the certificate,
CertAndKeyGen keypair = new CertAndKeyGen("RSA", "SHA1WithRSA", null);
X500Name x500Name = new X500Name(commonName, organizationalUnit, organization, city, state, country);
keypair.generate(keysize);
PrivateKey privKey = keypair.getPrivateKey();
PKCS10 certReq = keypair.getCertRequest(x500Name);
X509Certificate[] chain = new X509Certificate[1];
chain[0] = keypair.getSelfCertificate(x500Name, new Date(), (long) validity * 24 * 60 * 60);
keyStore.setKeyEntry(alias, privKey, keyStorePassword.toCharArray(), chain);
ByteArrayOutputStream bs = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(bs);
certReq.print(ps);
byte[] certReqPrintable = bs.toByteArray();
I have got no clues, please help me to go in right direction to get private key and convert it into readable format. Thanks in advance.

If you want to save the private key to a file use
byte[] privateKeyBytes = privKey.getEncoded();
This returns the key in DER encoded (binary) format.
In case you want just to display the contained values on the console just print it using toString():
System.out.println(privKey);

BouncyCastle has the useful PEMWriter class that you can use to write the private key to a file in PEM format (this is what tools like OpenSSH and curl expect).
PEMWriter privatepemWriter = new PEMWriter(new FileWriter(filename)));
privatepemWriter.writeObject(privKey);
privatepemWriter.close();
Otherwise you can just save the byte array from the private key which is the DER format also used by many tools.
Finally you can write it to a JKS keystore used by other java programs using this:
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(null);
keyStore.setKeyEntry("some alias", privKey, somePassword.toCharArray(), chain[0]));
FileOutputStream fos = new FileOutputStream(filename);
keyStore.store(fos, somePassword.toCharArray());
fos.close();

Related

Bouncy Castle's CMSSignedData PEM produced data causing parsing issues

I'm trying to wrap PKCS#10 request with PKCS#7/CMS signed object, as there almost no examples on how to do that I've started by wrapping a X.509 instead.
I've used Bouncy Castel's Example, produced the CMSSignedData object, decoded it to PEM, and stored it in the file system, and that works.
The issue is that my CA rejects it with "Error Parsing - ASN bad tag value met", also ASN.1 Editor failed to open the file.
private static void generateCMS(X509Certificate signCert, KeyPair signKP, X509Certificate signedCert) {
CMSTypedData msg = new CMSProcessableByteArray("Hello world!".getBytes());
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA256withRSA")
.setProvider("BC").build(signKP.getPrivate());
gen.addCertificate(new X509CertificateHolder(signedCert.getEncoded()));
gen.addSignerInfoGenerator(
new JcaSignerInfoGeneratorBuilder(
new JcaDigestCalculatorProviderBuilder().setProvider("BC").build())
.build(sha1Signer, signCert));
CMSSignedData sigData = gen.generate(msg, true);
ContentInfo cmsSignedDataAsASN1 = sigData.toASN1Structure();
JcaPEMWriter writer = new JcaPEMWriter(new FileWriter("test.p7b"));
writer.writeObject(cmsSignedDataAsASN1);
writer.close();
}
I've noticed something weird, I'm not sure it's related, but when using OpenSSL CMS module for signing certificates the PEM encoded Base 64 always starts with the letters "MII", while my code produced PEM consistently starts with the letters "MIA".
Can someone point me to what I'm missing here?
I figured it out, when org.bouncycastle.asn1.cms.ContentInfo ASN.1 is being written to an OutputStream it's using BER encoding, all I had to do is to get the ASN1Primitive and instruct the decoder to use DER instead.
Here's the code:
ASN1Primitive cmsSignedDataAsASN1 = cmsSignedDataAsASN1.toASN1Primitive()
sigData.toASN1Structure().toASN1Primitive()
PemObject pemObject = new PemObject("CMS",
cmsSignedDataAsASN1.getEncoded(ASN1Encoding.DER));
PemWriter pemWriter = new PemWriter(new FileWriter(fileName));
pemWriter.writeObject(pemObject);
pemWriter.close();

How to extract PKCS12 keystore(containing a keypair of pkcs#8 and a certificate)

when the user provides keystore, usually the keystore contains a keypair(an RSA encrypted private key, x.509 certificate) and CA certificates.
I want to extract the contents of keystore and write them in a different file.
I am able to read the contents of certificates without any issue but when trying to read the key and write to file, the contents are in unecrypted form.
How to write the contents of private key file in encrypted from itself?
I have fetched the key and cert as below:
key = (PrivateKey)keyStore.getKey(keyAlias, password.toCharArray());
cert = keyStore.getCertificate(keyAlias);
I also tried using bouncycastle.
Using java libs:
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(key.getEncoded());
byte[] privatekey = encoder.encode(pkcs8EncodedKeySpec.getEncoded());
Using bouncycastle:
JceOpenSSLPKCS8EncryptorBuilder encryptorBuilder = new JceOpenSSLPKCS8EncryptorBuilder(PKCS8Generator.PBE_SHA1_RC2_128);
encryptorBuilder.setRandom(new SecureRandom());
encryptorBuilder.setPasssword("abcde".toCharArray()); // password
OutputEncryptor encryptor = encryptorBuilder.build();
JcaPKCS8Generator gen2 = new JcaPKCS8Generator(key, encryptor);
PemObject obj2 = gen2.generate();
StringWriter sw2 = new StringWriter();
try (JcaPEMWriter pw = new JcaPEMWriter(sw2)) {
pw.writeObject(obj2);
}
String pkcs8Key2 = sw2.toString();
FileOutputStream fos2 = new FileOutputStream(privateKeyLocation);
fos2.write(pkcs8Key2.getBytes());
fos2.flush();
fos2.close();
when used plain java libs the content is decrypted and I may want to append the header and footer tags.
When used bouncy castle, I got some data with in -----BEGIN ENCRYPTED PRIVATE KEY----- and -----END ENCRYPTED PRIVATE KEY----- but the content is not same as the original file. I also tried using different PKCS8Gnerator.algorithms to no use.

Add Key Usage to CertificateSigningInfo in Java

I am trying to add Key Usage to certificateSigningInfo in Java without using BouncyCastle. I have the following method which will create certificateSigningInfo that can be further signed to create PKCS#10:
public static byte[] createCertificationRequestInfo(X500Name x500Name, PublicKey publicKey) throws IOException {
final DerOutputStream der1 = new DerOutputStream();
der1.putInteger(BigInteger.ZERO);
x500Name.encode(der1);
der1.write(publicKey.getEncoded());
// der encoded certificate request info
final DerOutputStream der2 = new DerOutputStream();
der2.write((byte) 48, der1);
byte[] toReturn = der2.toByteArray();
der2.close();
return toReturn;
}
I am trying to add Key Usage with adding the following:
KeyUsageExtension ku = new KeyUsageExtension();
ku.set(KeyUsageExtension.NON_REPUDIATION, true);
ku.set(KeyUsageExtension.KEY_ENCIPHERMENT, true);
ku.set(KeyUsageExtension.DIGITAL_SIGNATURE, true);
ku.encode(der1);
The certificateSigningInfo is created but it can't be validate as it has some missing values...
For example, the following CSR is created:
-----BEGIN NEW CERTIFICATE REQUEST-----
MIIErDCCApQCAQAwWjENMAsGA1UEBhMEVGVzdDENMAsGA1UECBMEVGVzdDENMAsGA1UEBxMEVGVz
dDENMAsGA1UEChMEVGVzdDENMAsGA1UECxMEVGVzdDENMAsGA1UEAxMEVGVzdDCCAiEwDQYJKoZI
hvcNAQEBBQADggIOADCCAgkCggIAr11wXkShGHeEVRxl1K4D/7Ow8uIgVro35h/WMBKl5UWOEqBc
ajTnU9AMN+u/rVa5uRt8HcHhWF8Y4RIMoNxlMuxBu36UbxKBnPza8Y1/Dbn0HGwzematfnFYS7B7
HdyVoj6yRcSo2tM/p8bmUGpxr1NSXsEtbxVINFhuyMZnwMpuVUsqTgB58Uo/+sjGtIxDVkLaMNs4
d/HCe2rwb5rYhkvAEgXtAtoWtDD9PPZTpxhKqO+cMYGZ0HqwFyQEu687ONUpVlA068DsgzwM6oh5
w3y2OJ8PiCXW+ojqxGr5mm7ig//mbgkk7QiwoZ3taYoqAdRfGlQsOZsVzHPzAIH84CHlF2LMRcIO
M8dA3eQSopjPDPOZixo8PGQ/cYtQPgyBVGmiQt/93JQ/BAypu9olO70y91nd+cEsEzoZdGkuFnTR
KVT67ye0GnxFik6Y/VJxpE36NPbofOXVRxy8jbazJGg/AzETAGmkKXoNAbzqvVCaV2zeAOZZmTFx
rgjwQxvgW2oxpv5SCBDxtsH+/JpuqEtg5y3jzLFuibSmGs6qNDATEDIG1F1Xl0+1I6ygIE+tcycI
m/9SmlIX9UsiSEvSJe0kZOwOIrByzYhezeXdbgSHiD2WiuMe1XvXJBkqpV0wuwhw74vRKAJtz3vC
n1DNVBmBWMPWfxlVczG+HwgLBSECAwEAATAOBgNVHQ8BAf8EBAMCBeAwDQYJKoZIhvcNAQENBQAD
ggIBAHCEHA47S0jO7AXvF7SDXtPPV2zlgUFtvCx0DfRerElYcmQFg5ylspfvkbQnlUFOcpKgoi1/
Kgq5vchLjKVEJPJK9066NsNTRy1Ayt4f3Ne7yQ46cnrL729x7TLUcWijDgmfJE/Cp4eC0qTF87mH
rYeOK0+1azki0r6/ToM9EliDU497Tsl2CWmAJlP+hkWQRa80uPFXkEV+UH0vQwOc8mf/aW+q3LHf
BXvPHcH3J9lPtDHMZgKav7Vi4sFU8tlCzm7QE6/jU49BN+Ptgp34k8Hw+VV+4lpZX2QpkDMvaPg5
Zd7LYNGhayP//EevCftiliWsNJSHa8aA6zqYvsTnBoEPFPL4sVfXsWp18AbK294WhF5vIe+8AFks
RHMLE+Nl13SXO3wHlNDT5jXKUGFmbCOASsUjyrpfQcwVMJ0/muAX43r6zo2YatZKgmCtVrBtKVuE
U7KMJW2aEDO7ML7+47VER8r1LYWSt96OY/9Pre+UehMuDloUC5B9nSf5TKyCShnzxXoNAE7izr2A
l3x9O071c9d/pRKjUBu9Q/IrSFT/blg94zGov+9FplcXc2Ygnblt5UNjAs5XcoC6ckhGPkrcZbw6
3Qk5R9TTJGX9wpzKTFPWJF735TaFqkJNwn1U5kTKWCTgbGUi3U98gTCCV4OkeT+Fo+pWuOqz5NV5
Q778
-----END NEW CERTIFICATE REQUEST-----
Any help is appreciated.
PKCS10 type CertificationRequestInfo can't directly contain an Extension, or even Extensions (which is SEQUENCE OF Extension). Instead it can contain Attributes which is SET OF Attribute each of which is SEQUENCE of OID and SET OF values constrained by a notional InfoSet, or in the old syntax ANY DEFINED BY --metaspec. One possible Attribute is PKCS9 5.4.2 extensionRequest which does contain Extensions which can include the one for KeyUsage.
Thus to add this to a PKCS10 you need something like the following. And as long as you are using the undocumented and possibly unreliable sun.security classes, there is one for PKCS10 that replaces most of the code you posted.
import sun.security.pkcs.*;
import sun.security.pkcs10.*; // separate in j8 (and later? not checked)
import sun.security.util.*;
import sun.security.x509.*;
// dummy setup; replace as appropriate
X500Name name = new X500Name("O=Widgets Inc, CN=testcert");
KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
gen.initialize(1024); KeyPair pair = gen.generateKeyPair();
KeyUsageExtension ku = new KeyUsageExtension();
ku.set(KeyUsageExtension.NON_REPUDIATION, true);
ku.set(KeyUsageExtension.KEY_ENCIPHERMENT, true);
ku.set(KeyUsageExtension.DIGITAL_SIGNATURE, true);
CertificateExtensions exts = new CertificateExtensions();
exts.set(KeyUsageExtension.IDENT,ku);
PKCS10Attribute extreq = new PKCS10Attribute (PKCS9Attribute.EXTENSION_REQUEST_OID, exts);
PKCS10 csr = new PKCS10 (pair.getPublic(), new PKCS10Attributes (new PKCS10Attribute[]{ extreq }));
Signature signer = Signature.getInstance("SHA256withRSA"); // or adapt to key
signer.initSign(pair.getPrivate());
csr.encodeAndSign(name, signer);
// dummy output; replace
FileOutputStream out = new FileOutputStream ("SO49985805.der");
out.write(csr.getEncoded()); out.close();

Convert message and signature to BouncyCastle CMSSignedData object

I have an X509CertificateObject, a matching RSAPublicKey and managed to create a byte array containing a valid digital certificate for some message object also as a byte array.
Unfortunately the system I'm building upon only accepts CMSSignedData objects as input.
How do I convert my basic building blocks into such a valid CMSSignedData object?
Background: I'm experimenting with Java Bouncy Castle RSA blind signatures according to this example (digest is SHA512) and need to feed the result into the standard signature processing.
First, you'll probably want to sign your data with a private key. The idea being that the signature should be something only you can create. One you get that the rest should be as follows:
X509Certificate signingCertificate = getSigningCertificate();
//The chain of certificates that issued your signing certificate and so on
Collection&ltX509Certificate&gt certificateChain = getCertificateChain();
PrivateKey pk = getPrivateKey();
byte[] message = "SomeMessage".getBytes();
CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
certificateChain.add(signingCertificate);
generator.addCertificates(new CollectionStore(certificateChain));
JcaDigestCalculatorProviderBuilder jcaDigestProvider = new JcaDigestCalculatorProviderBuilder();
jcaDigestProvider.setProvider(new BouncyCastleProvider());
JcaSignerInfoGeneratorBuilder singerInfoGenerator = new JcaSignerInfoGeneratorBuilder(jcaDigestProvider.build());
AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA1withRSA");
AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
AsymmetricKeyParameter privateKeyParam = PrivateKeyFactory.createKey(pk.getEncoded());
ContentSigner cs = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(privateKeyParam);
SignerInfoGenerator sig = singerInfoGenerator.build(cs, signingCertificate);
generator.addSignerInfoGenerator(sig);
CMSSignedData data = generator.generate(new CMSProcessableByteArray(message), true);

Having trouble converting a X509 Certificate to Base64

I have a X509 Certificate and I want to store it in a MySQL DB instead of saving the file. Therefore, I thought it is better to convert the certificate to base64 and store it. I have done the forward and reverse of this conversion however, I did not get true results.
I'm using javax.security.cert.X509Certificate and import org.apache.commons.codec.binary.Base64 as follows:
X509Certificate cert = X509Certificate.getInstance(new FileInputStream(certFile));
System.out.println("Vigencia: "+cert.getNotAfter());
System.out.println("Inicio: "+cert.getNotBefore());
String cert64 = bytes2String(Base64.encodeBase64(cert.toString().getBytes("UTF-8")));
System.out.println("Cert 64: "+ cert64);
String certRegreso = bytes2String(Base64.decodeBase64(cert64.getBytes()));
System.out.println("Cert Regreso: "+ certRegreso);
X509Certificate certNuevo = X509Certificate.getInstance(certRegreso.getBytes());
According to the javadocs X509Certificate implements Serializable so why not use the much simpler solution and store it as a byte array? Something like:
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutput out = new ObjectOutputStream(bos);
out.writeObject(certificate);
byte[] data = bos.toByteArray();
bos.close();
And now just store the byte array as a blob. To recreate it you can just use:
ByteArrayIntputSream bis = new ByteArrayInputStream(byteData);
ObjectInput in = new ObjectInputStream(bis);
X509Certificate cert = (X509Certificate) in.readObject();
bis.close();

Categories

Resources