How to decrypt a pkcs8 encrypted private key using bouncy castle? - java

i am trying to decrypt a pkcs8 encrypted private key using bouncy castle library. I parsed the file containing the private key using PEMParser provided by bouncy castle. I got PKCS8EncryptedPrivateKeyInfo object. I am unable to get the PrivateKeyInfo object from this.
I am getting the following exception while trying to decrypt.
org.bouncycastle.pkcs.PKCSException: unable to read encrypted data: 1.2.840.113549.1.5.13 not available: No such provider: 1.2.840.113549.1.5.13
here is the code which I used
PEMParser parser = new PEMParser(br);
PKCS8EncryptedPrivateKeyInfo pair = (PKCS8EncryptedPrivateKeyInfo)parser.readObject();
JceOpenSSLPKCS8DecryptorProviderBuilder jce = new JceOpenSSLPKCS8DecryptorProviderBuilder();
jce.setProvider("1.2.840.113549.1.5.13");
InputDecryptorProvider decProv = jce.build(password.toCharArray());
PrivateKeyInfo info = pair.decryptPrivateKeyInfo(decProv);

Have you tried with jce.setProvider("BC"); instead of jce.setProvider("1.2.840.113549.1.5.13");
Edit to add solution provided by #PeterDettman :
In addition to use jce.setProvider("BC"); also install the BC provider bouncycastle.org/wiki/display/JA1/Provider+Installation

Security.addProvider(new BouncyCastleProvider());
thats whats missing

Related

OpenSSL always fails verifying signature generated from Bouncy Castle in Java

I'am trying to generate signatures from files, in order to verify them by clients using OpenSSL, so to implement the corresponding openSSL command in Java using Bouncy Castle :
openssl.exe dgst -sha256 -sign privateKey.pem -out \data.txt.sig \data.txt
using bouncy castle 1.57 and java, we get bytes array signature from file, which i could verify it in the code. Private, public and certificate are generated from openSSL.
so to generate certificates :
read the private key from the pem private key file:
PEMParser pemParser = new PEMParser(new FileReader(PRIVATE_FILE_PATH));
PKCS8EncryptedPrivateKeyInfo encryptedPrivateKeyInfo = (PKCS8EncryptedPrivateKeyInfo) pemParser.readObject();
JceOpenSSLPKCS8DecryptorProviderBuilder jce = new JceOpenSSLPKCS8DecryptorProviderBuilder();
jce.setProvider("BC");
InputDecryptorProvider decProv = jce.build(password.toCharArray());
PrivateKeyInfo info = encryptedPrivateKeyInfo.decryptPrivateKeyInfo(decProv);
JcaPEMKeyConverter pemKeyConverter = new JcaPEMKeyConverter();
PrivateKey pk = pemKeyConverter.getPrivateKey(info);
and generate the RSA SHA 256 signature and write the result in the signature file:
byte[] data = Files.readAllBytes(Paths.get(txtFileToSignPath));
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initSign(pk);
sig.update(data);
byte[] signature = sig.sign();
FileOutputStream dfis = new FileOutputStream(SignaturefilePath);
dfis.write(bytesToWrite);
dfis.close();
programmatically i could verify signatures generated from the code above as well as from open SSL:
Signature verifySignature = Signature.getInstance("SHA256withRSA");
byte[] signatureBytes =
Files.readAllBytes(Paths.get(SignaturefilePath);
verifySignature.initVerify(getPublicKeyFromCertFile(CERT_PEM));
verifySignature.update(data);
verifySignature.verify(signatureBytes);
on the other hand openSSL is getting always "verification failure" by verifiying signatures generated from code.
is OpenSSL able to verify array of bytes signatures directly, or am I missing anything ?
code above works fine, was verifying the signature against another file. Question maitained for learning purpose.

RSA decryption using Public Key - No such Provider

I have known public key and encrypted data. I want to decrypt it with public key. My code is look like:-
String s = "176byteofhexstring";
BigInteger Modulus = new BigInteger(s, 16);
String y = "03";
BigInteger Exponent = new BigInteger(y, 16);
RSAPublicKeySpec receiverPublicKeySpec = new RSAPublicKeySpec(Modulus, Exponent);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKey receiverPublicKey = (RSAPublicKey)
keyFactory.generatePublic(receiverPublicKeySpec);
Cipher rsaCipher = Cipher.getInstance("RSA/NONE/NoPadding","BC");
rsaCipher.init(Cipher.ENCRYPT_MODE, receiverPublicKey);
byte[] z = { 176 byte of cipher data };
byte[] m = rsaCipher.doFinal(z);
When I am run this code, getting error like:java.security.NoSuchProviderException: No such provider: BC.
Could anybody tell me how to avoid this error.
Add somewhere in the beginning of your code:
Security.addProvider(new BouncyCastleProvider());
This will register BouncyCastle provider to the JCA.
Another option is to use provider directly:
private static final Provider BC_PROVIDER = new BouncyCastleProvider();
...
Cipher rsaCipher = Cipher.getInstance("RSA/NONE/NoPadding", BC_PROVIDER);
Just use Cipher rsaCipher = Cipher.getInstance("RSA/ECB/NoPadding");. You don't need the Bouncy Castle provider to do textbook RSA. ECB here is a bit of a misnomer that is required for the provider of the standard JRE from Oracle; it's functionality the same as specifying NONE.
Note that using textbook RSA is completely insecure.
Completely missed it initially, but decryption with a public key is not the same thing as signature verification. Use the Signature class instead.
Here Want to share My doings for others.
Step1 - I was missing .Jar related to BouncyCastle (BC) , here the site help me to download the .jar file - http://www.itcsolutions.eu/2011/08/22/how-to-use-bouncy-castle-cryptographic-api-in-netbeans-or-eclipse-for-java-jse-projects/
step 2 - I download the jar from http://www.bouncycastle.org/latest_releases.html with name - bcprov-jdk15on-152.jar
step 3 - Add this jar to project, Properties -> Library -> Add Jar/folder
step 4 - add
import org.bouncycastle.jce.provider.BouncyCastleProvider;
step 5 - add line to your code
Security.addProvider(new BouncyCastleProvider());
and it solve my purpose...
Cipher.getInstance also accepts just the transformation - the provider is optional. When you don't specify the provider, it will use the default provider as specified in your java.security file.
I came across this while experiencing the same problem (only with the Signature.getInstance), and the answers already provided were very helpful in helping me realize this.

programatically reading java keystore file jceks using openssl

I am trying to do the AES encryption/decryption in java
I generated the secretkey using KeyGenerator. I stored the key using java keystore.
Key myKey = KeyGenerator.getInstance("AES").generateKey();
KeyStore.ProtectionParameter protParam =
new KeyStore.PasswordProtection("secretpass".toCharArray());
//For writing the secret Key
KeyStore.SecretKeyEntry skEntry =
new KeyStore.SecretKeyEntry((SecretKey)myKey);
FileOutputStream fout = new FileOutputStream("test.ks");
KeyStore ksout = KeyStore.getInstance("JCEKS");
ksout.load(null,"changeit".toCharArray());
ksout.setEntry("secretalias", skEntry, protParam);
I wanted to get this secretkey from this file using openssl programatically. Is it possible? If so, please give me some suggestions on how do I proceed.
Thank you in advance.
This is not possible as the default keystore (jks) is a proprietary format used by Java.
To exchange the key you would need something portable like PKCS#11 (which is a supported KeyStore format at least in Java 8).

JAVA: How to save a private key in a pem file with password protection

I am trying to save a private key in a pem file, protected with a password. The problem is, the pem file is created and I
can even open it with openssl but, no password is asked!
Here is the code:
KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA");
keygen.initialize(2048);
KeyPair keypair = keygen.generateKeyPair();
PrivateKey privKey = keypair.getPrivate();
PKCS8Generator encryptorBuilder = new PKCS8Generator(privKey);
encryptorBuilder.setPassword("testing".toCharArray());
PEMWriter writer = new PEMWriter(new FileWriter(new File("pk.pem")));
PemObject obj = encryptorBuilder.generate();
writer.writeObject(obj);
writer.flush();
writer.close();
After it executes, I try to open the pk.pem file
openssl rsa -in pk.pem -check
and it gives:
RSA key ok
writing RSA key
-----BEGIN RSA PRIVATE KEY-----
(... some key appears here ...)
-----END RSA PRIVATE KEY-----
It was suppose to ask for the password before giving access to the private key!
Can some one please help me?
Well you should read the BouncyCastle documentation carefully. It states for the constructor you use:
// Constructor for an unencrypted private key PEM object.
PKCS8Generator(java.security.PrivateKey key)
// Constructor for an encrypted private key PEM object.
PKCS8Generator(java.security.PrivateKey key, java.lang.String algorithm, java.lang.String provider)
Hence you are using the constructor for creating an creates an unencrypted PKCS8Generator instance. The password you set as no effect.
Use one of the other constructors instead that create an encrypting instance according to the documentation.
Note: The code in the question requires an outdated version of BouncyCastle (1.4x?), because the current version (1.5x) has different constructors, incompatible with those presented in this answer.
For newer versions use:
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
JcaPEMWriter writer = new JcaPEMWriter(new PrintWriter(System.out));
writer.writeObject(sk);
writer.close();
possibly replacing the PrintWriter with any other Writer of course.

How can I create a Java KeyStore from an existing set of certificates and keys without using command line tools?

I obtain a randomly generated RSA certificate and private key as strings from another service, and I would like to use those strings to create a Java KeyStore. All of the examples I see involve saving these strings to files, using the openssl and keytool command line tools to create the keystore on disk, and then loading the resulting KeyStore into memory (like here). However, it makes more sense for my purposes to create the KeyStore entirely in memory.
To that end, I am trying to use the Java Security API. I am able to convert the certificate string into an instance of the java.security.cert.Certificate class, but I am unable to convert the private key into an instance of java.security.PrivateKey. Here's method I am trying to create:
private PrivateKey generatePrivateKey (String newKey)
throws NoSuchAlgorithmException,
InvalidKeySpecException, IOException {
//Configuring the KeyFactory to use RSA
KeyFactory kf = KeyFactory.getInstance("RSA");
//Convert the key string to a byte array
byte[] keyBytes = newKey.getBytes();
KeySpec ks = new PKCS8EncodedKeySpec(keyBytes);
PrivateKey key = kf.generatePrivate(ks);
return key;
}
Where the value of newKey is something like "-----BEGIN RSA PRIVATE KEY-----\nMIIEow...gNK3x\n-----END RSA PRIVATE KEY-----".
When I run the code, I receive the following exception:
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format
at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:217)
at java.security.KeyFactory.generatePrivate(KeyFactory.java:372)
... 30 more
Caused by: java.security.InvalidKeyException: invalid key format
at sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:341)
at sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:367)
at sun.security.rsa.RSAPrivateCrtKeyImpl.<init>(RSAPrivateCrtKeyImpl.java:91)
at sun.security.rsa.RSAPrivateCrtKeyImpl.newKey(RSAPrivateCrtKeyImpl.java:75)
at sun.security.rsa.RSAKeyFactory.generatePrivate(RSAKeyFactory.java:316)
at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:213)
... 32 more
This particular error is very similar to this stackoverflow question, and I would be grateful if that question were resolved, but I also want to know if my higher level goal (creating a JKS programmatically and solely in memory using Java) is feasible, and if so, whether I am on the right path.
you need to decode base64 if your key is in the base64 representation:
KeySpec ks = new PKCS8EncodedKeySpec(Base64.decodeBase64(newKey));
you can use org.apache.commons.codec.binary.Base64 to do this.
if you want to generate keyPair you can you this code:
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.genKeyPair();
// extract the encoded private key, this is an unencrypted PKCS#8 private key
byte[] encodedprivkey = keyPair.getPrivate().getEncoded();
System.out.println(Base64.encodeBase64String(encodedprivkey));

Categories

Resources