Retrieving CMSSignedData from ASN.1 encoding in Bouncy Castle - java

In the following piece of code I sign a message using Bouncy Castle:
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.cms.CMSTypedData;
import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.bouncycastle.util.encoders.Base64;
import java.io.FileInputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
public class Sign {
public static void main(String[] args) throws Exception {
Security.addProvider(new BouncyCastleProvider());
String certPath = "certPath";
FileInputStream inPublic = new FileInputStream(certPath);
CertificateFactory factory = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) factory.generateCertificate(inPublic);
String keyPrivatePath = "keyPath";
Path path = Paths.get(keyPrivatePath);
Files.readAllBytes(Paths.get(keyPrivatePath));
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(Files.readAllBytes(Paths.get(keyPrivatePath)));
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey privateKey = kf.generatePrivate(spec);
CMSProcessableByteArray msg = new CMSProcessableByteArray("My message".getBytes());
CMSSignedDataGenerator sGen = new CMSSignedDataGenerator();
ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").build(privateKey);
sGen.addSignerInfoGenerator(
new JcaSignerInfoGeneratorBuilder(
new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()
).build(sha1Signer, cert)
);
CMSSignedData sd = sGen.generate(msg);
CMSTypedData cmsBytes = new CMSProcessableByteArray(sd.getEncoded());
// How to reconstruct a CMSSignedData from cmsBytes again?
byte[] bytes = (byte[]) cmsBytes.getContent();
CMSSignedData retrieved = new CMSSignedData(bytes);
System.out.println(retrieved.getSignedContent()); // Doesn't work, is null
}
}
My question is how to retrieve the original CMSSignedData (wanting to read the original message, and verify it), using only the byte array of the ASN.1 encoding of this object.
The reason I am asking this, is that I want to decrypt a certain encrypted and signed message. I am able to decrypt this message, but it results in an ASN.1 encoded byte array (which does correspond to my original message), but I am not able to process this decrypted message any further.

You can use the classes org.bouncycastle.asn1.cms.ContentInfo and org.bouncycastle.asn1.ASN1Sequence:
CMSTypedData cmsBytes = new CMSProcessableByteArray(sd.getEncoded());
byte[] bytes = (byte[]) cmsBytes.getContent();
// reconstruct CMSSignedData from the byte array
ContentInfo ci = ContentInfo.getInstance(ASN1Sequence.fromByteArray(bytes));
CMSSignedData sig = new CMSSignedData(ci);
Also note that you must create a CMSSignedData with the content encapsulated in the signature, so you must change this:
CMSSignedData sd = sGen.generate(msg);
To this:
CMSSignedData sd = sGen.generate(msg, true);

Related

How to validate a signature in Java if the public key's algorithm is EC?

Given an X509 certificate object of a person. (The object's type is sun.security.x509.X509CertImpl). This person signed a String with his private key. Given the signature that was made by this person, when he signed the above mentioned String object.
My task is to verify this signature, but have difficulties with it.
When I try to verify the signature with the below code:
...
X509Certificate x509Certificate = getCertificate(certificate);
Signature signature = Signature.getInstance("SHA256withECDSA");
signature.initVerify(x509Certificate.getPublicKey());
signature.update(unsignedData);
boolean bool = signature.verify(signatureToVerify);
System.out.println("The signature is " + (bool ? "" : "NOT") + " valid");
I get java.security.SignatureException: Could not verify signature
Do you have an idea, how can I make it working?
Edited:
At the end, I managed to make it working, but do not understand the reason yet:
Before passing the signature to the verify method, i needed to do the following modification on it:
byte[] rBytes = Arrays.copyOfRange(signatureHash, 0, 32);
byte[] sBytes = Arrays.copyOfRange(signatureHash, 32, 64);
BigInteger r = new BigInteger(1, rBytes);
BigInteger s = new BigInteger(1, sBytes);
ASN1Integer asn1R = new ASN1Integer(r);
ASN1Integer asn1S = new ASN1Integer(s);
DERSequence seq = new DERSequence(new ASN1Integer[]{asn1R, asn1S});
byte[] signatureToVerify2 = seq.getEncoded();
// verifying the signatureToVerify2 instead of the original brings success
boolean bool = signature.verify(signatureToVerify2);
Here is a (semi)working app for further reference that verifies a signature, when ECDSA is involved in the story:
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.DERSequence;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Arrays;
public class SignatureTest {
public static void main(String[] args) throws CertificateException, InvalidKeyException, SignatureException, NoSuchAlgorithmException, IOException {
byte[] certificateAsByteArray = ...;
byte[] dataToVerifyAsByteArray = ...;
byte[] signatureHashAsByteArray = ...;
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
InputStream in = new ByteArrayInputStream(certificateBytes);
X509Certificate x509Certificate = (X509Certificate) certFactory.generateCertificate(in);
Signature signature = Signature.getInstance("SHA256withECDSA");
signature.initVerify(x509Certificate.getPublicKey());
signature.update(dataToVerifyAsHexaString);
byte[] rBytes = Arrays.copyOfRange(signatureHash, 0, 32);
byte[] sBytes = Arrays.copyOfRange(signatureHash, 32, 64);
ASN1Integer asn1R = new ASN1Integer(rBytes);
ASN1Integer asn1S = new ASN1Integer(sBytes);
DERSequence seq = new DERSequence(new ASN1Integer[] {asn1R, asn1S});
boolean isSignatureOK = signature.verify(seq.getEncoded());
System.out.println("The signature is " + (isSignatureOK ? "" : "NOT ") + "VALID");
}
}

Got "data isn't an object ID (tag = 49)" while generating X509 cert

I'm trying to generate my own CSR for my keystore, but it didn't go well and that error is confusing me. Here is my code:
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.openssl.PEMWriter;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder;
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
public class CreateKeyTest {
public static void main(String[] args) throws OperatorCreationException, IOException, GeneralSecurityException {
KeyPairGenerator kpg;
KeyPair kp;
RSAPublicKey pubKey;
RSAPrivateKey privKey;
FileOutputStream out;
KeyStore ks;
FileInputStream in;
FileInputStream bFis;
try {
ks = KeyStore.getInstance("JKS");
kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
kp = kpg.generateKeyPair();
pubKey = (RSAPublicKey) kp.getPublic();
privKey = (RSAPrivateKey) kp.getPrivate();
// generate CSR
ContentSigner sign = new JcaContentSignerBuilder("SHA1withRSA").build(privKey);
X500NameBuilder nBuilder = new X500NameBuilder();
nBuilder.addRDN(BCStyle.CN, "TestCSR");
nBuilder.addRDN(BCStyle.C, "ER");
nBuilder.addRDN(BCStyle.E, "test#test.com");
X500Name name = nBuilder.build();
PKCS10CertificationRequestBuilder cerReq = new JcaPKCS10CertificationRequestBuilder(name, pubKey);
PKCS10CertificationRequest request = cerReq.build(sign);
PEMWriter pWr = new PEMWriter(new FileWriter(new File("D:\\test.csr")));
pWr.writeObject(request);
pWr.flush();
pWr.close();
bFis = new FileInputStream("D:\\test.csr");
BufferedInputStream ksbufin = new BufferedInputStream(bFis);
X509Certificate certificate = (X509Certificate) CertificateFactory.getInstance("X.509")
.generateCertificate(ksbufin);
ks.setKeyEntry("RSA_key", kp.getPrivate(), "changeit".toCharArray(),
new java.security.cert.Certificate[] { certificate });
out = new FileOutputStream("key.store");
ks.store(out, "changeit".toCharArray());
System.out.println("New Keystore Generated");
out.close();
} catch (KeyStoreException | IOException | CertificateException | NoSuchAlgorithmException
| OperatorCreationException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
When I execute it, it showed me the exception:X509.ObjectIdentifier() -- data isn't an object ID (tag = 49), and it could be back-traced to generateCertificate(ksbufin). But I checked test.cer and it do have certificate data in there, and that exception message confused me, don't even know what does that mean(object ID? tag = 49? I didn't see I generated an ID in my code.).
Can anyone help me out this mud?
The error message is correct, test.csr does not contain a certificate. You have built it using a PKCS10CertificationRequest, so it consenquently contains a Certificate Signing Request (CSR).
You have generated a key pair, private and public, and a CSR. The CSR is a request of a certificate to a Certification Authority (CA). It contains the public key and some expected attributes for the certificate (CN, C, OU, etc). CSR is signed with the private key and has to be sent to CA. The CA will extract the public key, generates a certificate and signs it. See Certificate enrollment process
If you want a Certificate, you need to get signed the certificate by the CA

Flexiprovider - How to encrypt/de with formatted keypair

Im using flexiprovider to encrypt/de with asymmetric algorithm based on Elliptic Curve following this tutorial. With a little modification, i'm gonna convert the public and the private key into Base64 for personal purpose (like storing into the database or text file). I'm also looking at this question and the answer is refer to this thread. But my code are running for dekstop not in android device, android and dekstop version in java i think is a really big difference (just for clean up my question information). Ok, in my code when im going to create the formatted public key from a generated public key i got an error (i think the same problem will happen when i try to do that for the private key).
Now, here's my code:
Keypair generator class.
import org.jivesoftware.smack.util.Base64; //or whatever to convert into Base64
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.KeyFactory;
import javax.crypto.Cipher;
import de.flexiprovider.common.ies.IESParameterSpec;
import de.flexiprovider.core.FlexiCoreProvider;
import de.flexiprovider.ec.FlexiECProvider;
import de.flexiprovider.ec.parameters.CurveParams;
import de.flexiprovider.ec.parameters.CurveRegistry.BrainpoolP160r1;
import de.flexiprovider.pki.PKCS8EncodedKeySpec;
import de.flexiprovider.pki.X509EncodedKeySpec;
...
Security.addProvider(new FlexiCoreProvider());
Security.addProvider(new FlexiECProvider());
KeyPairGenerator kpg = KeyPairGenerator.getInstance("ECIES","FlexiEC");
CurveParams ecParams = new BrainpoolP160r1();
kpg.initialize(ecParams, new SecureRandom());
KeyPair keyPair = kpg.generateKeyPair();
PublicKey pubKey = keyPair.getPublic();
byte[] encod_pubK = pubKey.getEncoded();
String publicKey = Base64.encodeBytes(encod_pubK);
System.out.println("Public Key :" +publikKey);
PrivateKey privKey = keyPair.getPrivate();
byte[] encod_privK = privKey.getEncoded();
String privateKey = Base64.encodeBytes(encod_privK);
System.out.println("Private Key :" +privateKey);
From that code above im going to store the string "privateKey" and "publicKey". Now im going to encrypt the message.
Sender Side
import (same as code above)
...
Security.addProvider(new FlexiCoreProvider());
Security.addProvider(new FlexiECProvider());
Cipher cipher = Cipher.getInstance("ECIES","FlexiEC");
IESParameterSpec iesParams = new IESParameterSpec ("AES128_CBC","HmacSHA1", null, null);
byte[] decodedPubKey = Base64.decode(publicKey);
X509EncodedKeySpec formatted_public = new X509EncodedKeySpec(decodedPubKey);
KeyFactory kf = KeyFactory.getInstance("ECIES","FlexiEC");
PublicKey publicKey = kf.generatePublic(formatted_public); // <--- I got error when hit this row
cipher.init(Cipher.ENCRYPT_MODE, publicKey, iesParams);
byte[] block = "this my message".getBytes();
System.out.println("Plaintext: "+ new String(block));
byte [] Ciphered = cipher.doFinal(block);
System.out.println("Ciphertext : "+ Base64.encodeBytes(Ciphered));
The error from that sender code above is:
Exception in thread "main" de.flexiprovider.api.exceptions.InvalidKeySpecException: java.lang.RuntimeException: java.security.InvalidAlgorithmParameterException: Caught IOException("Unknown named curve: 1.3.36.3.3.2.8.1.1.1")
at de.flexiprovider.ec.keys.ECKeyFactory.generatePublic(ECKeyFactory.java:205)
at de.flexiprovider.api.keys.KeyFactory.engineGeneratePublic(KeyFactory.java:39)
at java.security.KeyFactory.generatePublic(KeyFactory.java:328)
How can i generate that public key with that named curve: 1.3.36.3.3.2.8.1.1.1 ?
Recipient Side (just for another information)
If the sender has been succesfully encrypt the message, now im going to decrypt the message, here's my code (but not sure if this running without an error like the sender code above):
byte[] decodedPrivateKey = Base64.decode(privateKey);
PKCS8EncodedKeySpec formatted_private = new PKCS8EncodedKeySpec(decodedPrivateKey);
cipher.init(Cipher.DECRYPT_MODE, privKey, iesParams);
byte[] decryptedCipher = cipher.doFinal(Ciphered);
System.out.println("Decrypted message : "+ new String (decryptedCipher));
Due to unsolved error with my code above because i think this flexiprovider aren't compatible with jdk-8 where the bug is in "KeyFactory kf = KeyFactory.getInstance("ECIES","FlexiEC")" line which can't find that named curve, i change and decide to use BouncyCastle provider for doing the EC encryption (ECIES) and it works. But there's a question again come in to my mind, as i can see in the Flexiprovider which is use ("AES128_CBC","HmacSHA1", null, null); as the IESParameterSpec.
But for bouncycastle provider i can't find where is the IESParameterSpec which using AES128_CBC as the iesparameterspec, how can i do that if want to change the iesparam into AES128_CBC when i'm using this bouncy provider ?
Somebody please explain about this iesparam spec in bouncy provider i'm new about this.
Here's my code for information:
Key Pair Generator Class
import codec.Base64; // or whatever which can use to base64 encoding
import static java.lang.System.out;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
...
Security.addProvider(new BouncyCastleProvider());
KeyPairGenerator kpg = KeyPairGenerator.getInstance("ECIES", "BC");
ECGenParameterSpec brainpoolP160R1 = new ECGenParameterSpec("brainpoolP160R1");
// I'm Still using this 160 bit GF(*p*) to keep the algorithm running fast rather than 256 or above
kpg.initialize(brainpoolP160R1);
KeyPair kp = kpg.generateKeyPair();
PublicKey publicKey = kp.getPublic();
PrivateKey privateKey = kp.getPrivate();
byte[] PublicKey = publicKey.getEncoded();
byte[] PrivateKey = privateKey.getEncoded();
out.println("Encoded Public : "+Base64.encode(PublicKey));
out.println("\nEncoded Private : "+Base64.encode(PrivateKey));
...
The Encryption class (sender side)
import codec.Base64;
import codec.CorruptedCodeException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PublicKey;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
...
Security.addProvider(new BouncyCastleProvider());
// Assume that we know the encoded public key then return it by decode the public key
byte[] decodedPublic = Base64.decode("MEIwFAYHKoZIzj0CAQYJKyQDAwIIAQEBAyoABNXclcmtUt8/rlGN47pc8ZpxkWgNgtKeeHdsVD0kIWLUMEULnchGZPA=".getBytes());
X509EncodedKeySpec formatted_public = new X509EncodedKeySpec(decodedPublic);
KeyFactory kf = KeyFactory.getInstance("EC","BC");
PublicKey pubKey = kf.generatePublic(formatted_public);
Cipher c = Cipher.getInstance("ECIES", "BC");
c.init(Cipher.ENCRYPT_MODE, pubKey); // How can i put the AES128_CBC for ies parameter ? is that possible
byte[] cipher = c.doFinal("This is the message".getBytes());
System.out.println("Ciphertext : "+ Base64.encode(cipher));
...
The decryption class (recipient side)
import codec.Base64;
import codec.CorruptedCodeException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
...
Security.addProvider(new BouncyCastleProvider());
// Assume that we know the encoded private key
byte[] decodedPrivate = Base64.decode("MHECAQAwFAYHKoZIzj0CAQYJKyQDAwIIAQEBBFYwVAIBAQQUQmA9ifs472gNHBc5NSGYq56TlOKgCwYJKyQDAwIIAQEBoSwDKgAE1dyVya1S3z+uUY3julzxmnGRaA2C0p54d2xUPSQhYtQwRQudyEZk8A==".getBytes());
PKCS8EncodedKeySpec formatted_private = new PKCS8EncodedKeySpec(decodedPrivate);
KeyFactory kf = KeyFactory.getInstance("EC", "BC");
PrivateKey privKey = kf.generatePrivate(formatted_private);
Cipher c = Cipher.getInstance("ECIES");
c.init(Cipher.DECRYPT_MODE, privKey); //How can i adding the **AES128_CBC** ies param ?
// Assume that we know the encoded cipher text
byte[] plaintext = c.doFinal(Base64.decode("BKbCsKY7gDPld+F4jauQXvKSayYCt6vOjIGbsyXo5fHWo4Ax+Nt5BQ5FlkAGksFNRQ46agzfxjfuoxWkVfnt4gReDmpPYueUbiRiHp1Gwp0="));
System.out.println("\nPlaintext : "+ new String (plaintext));
...
Any help would be appriciate !

Decrypting a Base64 string encoded using RSA using Base64 encoded CRT components

so I've found myself having to decrypt a string given to me via an API. I know it's been Base64 encoded, and then encrypted with an RSA key (although I'm not sure in what order). I've been given the Modulus, public and private exponents, and the primes. The following code was my (truncated) attempt, and it's throwing me an "javax.crypto.BadPaddingException: Decryption error" on the final line. No idea where to go from here, any help would be appreciated :)
import java.math.BigInteger;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.Base64;
import javax.crypto.Cipher;
public static final String RSAKeyFactory = "RSA";
public static final String RSAKeyAlgorithm = "RSA/ECB/PKCS1Padding";
public static final String UTF_8 = "UTF-8";
byte[] mod = Base64.getDecoder().decode("3dlF3Frvwmuet+gM/LX8EQBI...");
BigInteger modulus = new BigInteger(1,mod);
byte[] prive64 = Base64.getDecoder().decode("YwTJhmqOS58PJzhhvuREI...");
BigInteger privExp = new BigInteger(1,prive64);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(new RSAPrivateKeySpec(modulus, privExp));
byte[] cipherBytes = Base64.getDecoder().decode("VdznCyJeYukJahmHsbge...");
Cipher cipher = Cipher.getInstance(RSAKeyAlgorithm);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] plainData = cipher.doFinal(cipherBytes);
Cheers

Java BouncyCastle ECC Keys and Self Signed Certificates

I've been scouring the internet for hours looking for a Java example for creating Elliptic Curve (EC) keys and self signed certificates. So far I've only found snippets and examples, many of which do not work.
UPDATE:
I've made some progress here, here's my code for anybody that might find it useful! Just need to work out how to self sign it now!
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.ContentVerifierProvider;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder;
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
import java.security.*;
/**
* A simple example showing generation and verification of a PKCS#10 request.
*/
public class genECKeyExample {
private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
public static void main(String[] args)
throws Exception {
Security.addProvider(new BouncyCastleProvider());
// Create an eliptic curve key
ECParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec("prime192v1");
KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA", "BC");
g.initialize(ecSpec, new SecureRandom());
KeyPair pair = g.generateKeyPair();
System.out.println(pemUtils.toPem(pair.getPrivate()));
System.out.println(pemUtils.toPem(pair.getPublic()));
ContentSigner signer = new JcaContentSignerBuilder("SHA1withECDSA").setProvider(BC).build(pair.getPrivate());
PKCS10CertificationRequestBuilder reqBuilder = new JcaPKCS10CertificationRequestBuilder(new X500Name("CN=XXX"), pair.getPublic());
PKCS10CertificationRequest req = reqBuilder.build(signer);
ContentVerifierProvider verifier = new JcaContentVerifierProviderBuilder().setProvider(BC).build(pair.getPublic());
// System.out.println(verifier);
req = new PKCS10CertificationRequest(req.getEncoded());
System.out.println(pemUtils.toPem(req));
pemUtils.toFile("csr.pem", pemUtils.toPem(req));
pemUtils.toFile("pkey.pem", pemUtils.toPem(pair.getPrivate()));
}
}
This is the closest I've got but does not create the CSR or certificate. Also, it doesn't appear to allow different key sizes (I think they are curves) to be selected. Does anybody have some woking examples they can share?
import org.bouncycastle.openssl.PEMWriter;
import java.io.StringWriter;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.ECFieldFp;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.EllipticCurve;
import javax.crypto.KeyAgreement;
public class X509CertificateGenerator {
public static void main(String[] args) throws Exception {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ECDH", "BC");
EllipticCurve curve = new EllipticCurve(new ECFieldFp(new BigInteger(
"fffffffffffffffffffffffffffffffeffffffffffffffff", 16)), new BigInteger(
"fffffffffffffffffffffffffffffffefffffffffffffffc", 16), new BigInteger(
"fffffffffffffffffffffffffffffffefffffffffffffffc", 16));
ECParameterSpec ecSpec = new ECParameterSpec(curve, new ECPoint(new BigInteger(
"fffffffffffffffffffffffffffffffefffffffffffffffc", 16), new BigInteger(
"fffffffffffffffffffffffffffffffefffffffffffffffc", 16)), new BigInteger(
"fffffffffffffffffffffffffffffffefffffffffffffffc", 16), 1);
keyGen.initialize(ecSpec, new SecureRandom());
KeyAgreement aKeyAgree = KeyAgreement.getInstance("ECDH", "BC");
KeyPair aPair = keyGen.generateKeyPair();
KeyAgreement bKeyAgree = KeyAgreement.getInstance("ECDH", "BC");
KeyPair bPair = keyGen.generateKeyPair();
aKeyAgree.init(aPair.getPrivate());
bKeyAgree.init(bPair.getPrivate());
aKeyAgree.doPhase(bPair.getPublic(), true);
bKeyAgree.doPhase(aPair.getPublic(), true);
MessageDigest hash = MessageDigest.getInstance("SHA1", "BC");
System.out.println(new String(hash.digest(aKeyAgree.generateSecret())));
System.out.println(new String(hash.digest(bKeyAgree.generateSecret())));
System.out.println(aPair.getPrivate());
StringWriter pemWrtPublic = new StringWriter();
PEMWriter pubkey = new PEMWriter(pemWrtPublic);
pubkey.writeObject(aPair.getPublic());
pubkey.flush();
String pemPublicKey = pemWrtPublic.toString();
System.out.println(pemPublicKey);
StringWriter pemWrtPrivate = new StringWriter();
PEMWriter privkey = new PEMWriter(pemWrtPrivate);
privkey.writeObject(aPair.getPrivate());
privkey.flush();
String pemPrivateKey = pemWrtPrivate.toString();
System.out.println(pemPrivateKey);
}
}
Ive managed to create a CSR programatically following these steps (assuming you have a X509 Certificate stored in a keystore):
X509Certificate generatedCertificate = (X509Certificate)getKeystore().getCertificate(r.keystoreAlias);
PrivateKey privateRequestKey = (PrivateKey)getKeystore().getKey("alias", "password".toCharArray());
Signature signature = Signature.getInstance("MD5WithRSA");
signature.initSign(privateRequestKey);
X500NameBuilder x500NameBld = new X500NameBuilder(BCStyle.INSTANCE);
//possibly less or more of these, depending on your needs
x500NameBld.addRDN(BCStyle.C, "country");
x500NameBld.addRDN(BCStyle.O, "ORG");
x500NameBld.addRDN(BCStyle.E, "email");
x500NameBld.addRDN(BCStyle.CN, "SubjectName");
x500NameBld.addRDN(BCStyle.SN, "12345678");
X500Name subject = x500NameBld.build();
PKCS10CertificationRequest req = new PKCS10CertificationRequest("MD5WithRSA",X509Name.getInstance(subject),generatedCertificate.getPublicKey(),new DERSet(),privateRequestKey);
Please note that this code works for "regular" keypairs but should work for all public/private keypairs.

Categories