How to generate Private key from string using BouncyCastle - java

I have a String stored in a variable:
-----BEGIN RSA PUBLIC KEY-----
MIGHAoGBANAahj75ZIz9nXqW2H83nGcUao4wNyYZ9Z1kiNTUYQl7ob/RBmDzs5rY
mUahXAg0qyS7+a55eU/csShf5ATGzAXv+DDPcz8HrSTcHMEFpuyYooX6PrIZ07Ma
XtsJ2J4mhlySI5uOZVRDoaFY53MPQx5gud2quDz759IN/0gnDEEVAgED
-----END RSA PUBLIC KEY-----
I generate public key as:
public static PublicKey getFromString(String keystr) throws Exception
{
//String S1= asciiToHex(keystr);
byte[] keyBytes = new sun.misc.BASE64Decoder().decodeBuffer(keystr);
ASN1InputStream in = new ASN1InputStream(keyBytes);
DERObject obj = in.readObject();
RSAPublicKeyStructure pStruct = RSAPublicKeyStructure.getInstance(obj);
RSAPublicKeySpec spec = new RSAPublicKeySpec(pStrcut.getModulus(), pStruct.getPublicExponent());
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePublic(spec);
}
How to generate the PrivateKey using bouncy castle in android
{Edit}
Without using bouncy castle i am generating private key like this:
public static PrivateKey getKey(String mKey){
try{
// Read in the key into a String
StringBuilder pkcs8Lines = new StringBuilder();
BufferedReader rdr = new BufferedReader(new StringReader(mKey));
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 RSA PRIVATE KEY-----", "");
pkcs8Pem = pkcs8Pem.replace("-----END RSA PRIVATE KEY-----", "");
pkcs8Pem = pkcs8Pem.replaceAll("\\s+","");
// Base64 decode the result
byte [] pkcs8EncodedBytes = Base64.decode(pkcs8Pem, Base64.DEFAULT);
// extract the private key
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pkcs8EncodedBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey privKey = kf.generatePrivate(keySpec);
System.out.println(privKey);
return privKey;
}catch (Exception ex){
ex.printStackTrace();
}
return null;
}
I want to achieve the same using Bouncy Castle

I'm a little confused on why you insist on using bouncycastle, but if you really want to use bouncycastle then the CMS/PKIX library has a nice helper class called PEMParser that will shorten the code needed, e.g:
public static PrivateKey getPemPrivateKey(String mKey) throws Exception {
PEMParser pemParser = new PEMParser(new StringReader(mKey));
final PEMKeyPair pemKeyPair = (PEMKeyPair) pemParser.readObject();
final byte[] encoded = pemKeyPair.getPrivateKeyInfo().getEncoded();
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(new PKCS8EncodedKeySpec(encoded));
}

Related

InvalidKeyException during getting privateKey from pem file java

public static RSAPrivateKey readPrivateKey(File file) throws Exception {
String key = new String(Files.readAllBytes(file.toPath()), Charset.defaultCharset());
String privateKeyPEM = key.replace("-----BEGIN PRIVATE KEY-----", "")
.replaceAll(System.lineSeparator(), "").replace("-----END PRIVATE KEY-----", "");
byte[] encoded = Base64.decodeBase64(privateKeyPEM);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
}
// to call above code
// private.key in PEM format
File file = new File("private.key");
PrivateKey key = readPrivateKey(file);
Above is my sample code, i am getting below error. I have a pem file and want to extract RsaKrivateKey from it in java.
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : DerInputStream.getLength(): lengthTag=40, too big

RSA signature Java to C#

I have a tool which creates a signature. I am looking for equivalent code in dot net core 2.1.
Java Code: sign(currentdate,'some text','SHA1WithRSA')
public String sign(String date, String subjectId, String algorithm){
Signature rsa = Signature.getInstance(algorithm);
rsa.initSign(this.getPrivate());
rsa.update(subjectId.getBytes());
rsa.update(date.getBytes());
String signature = new String(Base64.getEncoder().encode(rsa.sign()));
return signature;
}
public PrivateKey getPrivate() {
String privateKeyPEM = "<This is the private key string";
byte[] encoded = Base64.getDecoder().decode(privateKeyPEM);
KeyFactory kf = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(encoded);
return kf.generatePrivate(spec);
}
Suggest a way to generate dot net core 2.1 equivalent code for the above with or without 3rd party tool.
This is work for me using Portable.BouncyCastle library.
private string GetSign(string data)
{
using (var rsa = new RSACryptoServiceProvider())
{
var privateKey = new StringBuilder();
privateKey.AppendLine("-----BEGIN RSA PRIVATE KEY-----");
privateKey.AppendLine("private key as string");
privateKey.AppendLine("-----END RSA PRIVATE KEY-----");
var pem = new PemReader(new StringReader(privateKey.ToString()));
var keyPair = (AsymmetricCipherKeyPair)pem.ReadObject();
var privateKeyParameters = (RsaPrivateCrtKeyParameters)keyPair.Private;
var rsaParameters = DotNetUtilities.ToRSAParameters(privateKeyParameters);
rsa.ImportParameters(rsaParameters);
var sign = rsa.SignData(Encoding.UTF8.GetBytes(data), new HashAlgorithmName("SHA1") /*pass your algorithm*/,
RSASignaturePadding.Pkcs1);
return Convert.ToBase64String(sign);
}
}

SHA1withRSA NoSuchAlgorithmException

Hi I have the following function to convert a string into a PrivateKey in my application:
public static PrivateKey main() throws Exception {
// Read in the key into a String
StringBuilder pkcs8Lines = new StringBuilder();
BufferedReader rdr = new BufferedReader(new StringReader(PRIVATE_KEY));
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.replaceAll("\\n+","");
// Base64 decode the result
byte [] pkcs8EncodedBytes = Base64.decode(pkcs8Pem, Base64.DEFAULT);
// extract the private key
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pkcs8EncodedBytes);
KeyFactory kf = KeyFactory.getInstance("SHA1WITHRSA");
PrivateKey privKey = kf.generatePrivate(keySpec);
return privKey;
}
and I get the following exception:
W/System.err: java.security.NoSuchAlgorithmException: SHA1withRSA KeyFactory not available
W/System.err: at java.security.KeyFactory.(KeyFactory.java:161)
at java.security.KeyFactory.getInstance(KeyFactory.java:195)
so I have tried to find all the alghoritms I can use through this code:
TreeSet<String> algorithms = new TreeSet<>();
for (Provider provider : Security.getProviders())
for (Provider.Service service : provider.getServices())
if (service.getType().equals("Signature"))
algorithms.add(service.getAlgorithm());
for (String algorithm : algorithms)
System.out.println(algorithm);
and in the response "SHA1withRSA" is included, do you know where the problem is?
SHA1withRSA is a signature type, you see that in the list because you have
if (service.getType().equals("Signature"))
If you edit that to
if (service.getType().equals("KeyFactory"))
you should see a list that looks something like this
DSA
EC
RSA
RSASSA-PSS
X25519
X448
XDH

How to read a rsa public key file in java?

I have a RSA public key file like this:
-----BEGIN RSA PUBLIC KEY-----
this is content
-----END RSA PUBLIC KEY-----
and i use java to read it:
KeyFactory factory = KeyFactory.getInstance("RSA");
KeySpec spec = new X509EncodedKeySpec(bytesFromThisFile); // bytesFromThisFile is created and filled correctly
PublicKey publicKey = factory.generatePublic(spec);
then i get an exception:
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format
How to read the file properly? Is there a way to convert this rsa public key file to a java-readable format?
Try this method:
/**
* reads a public key from a file
* #param filename name of the file to read
* #param algorithm is usually RSA
* #return the read public key
* #throws Exception
*/
public PublicKey getPemPublicKey(String filename, String algorithm) throws Exception {
File f = new File(filename);
FileInputStream fis = new FileInputStream(f);
DataInputStream dis = new DataInputStream(fis);
byte[] keyBytes = new byte[(int) f.length()];
dis.readFully(keyBytes);
dis.close();
String temp = new String(keyBytes);
String publicKeyPEM = temp.replace("-----BEGIN PUBLIC KEY-----\n", "");
publicKeyPEM = publicKeyPEM.replace("-----END PUBLIC KEY-----", "");
BASE64Decoder b64 = new BASE64Decoder();
byte[] decoded = b64.decodeBuffer(publicKeyPEM);
X509EncodedKeySpec spec = new X509EncodedKeySpec(decoded);
KeyFactory kf = KeyFactory.getInstance(algorithm);
return kf.generatePublic(spec);
}
source: Load RSA public key from file
This is my implementation; can read PEM with key or certificate.
Tested only in java11.
/**
* reads a public key from a file
* #param f file to read
* #return the read public key
* #throws Exception
*/
public static PublicKey getPublicKeyFromPem(File f)
throws Exception
{
byte[] keyBytes = Files.readAllBytes(f.toPath());
String temp = new String(keyBytes);
String publicKeyPEM = temp;
if(temp.contains("-----BEGIN PUBLIC KEY-----"))
{
publicKeyPEM = temp
.replace("-----BEGIN PUBLIC KEY-----\n", "")
.replace("-----END PUBLIC KEY-----", "")
.trim();
}
else if(temp.contains("-----BEGIN RSA PUBLIC KEY-----"))
{
publicKeyPEM = temp
.replace("-----BEGIN RSA PUBLIC KEY-----\n", "")
.replace("-----END RSA PUBLIC KEY-----", "")
.trim();
}
else if(temp.contains("-----BEGIN CERTIFICATE-----"))
{
CertificateFactory fact = CertificateFactory.getInstance("X.509");
try (FileInputStream is = new FileInputStream(f))
{
X509Certificate cer = (X509Certificate) fact.generateCertificate(is);
return cer.getPublicKey();
}
}
Base64.Decoder b64 = Base64.getDecoder();
byte[] decoded = b64.decode(publicKeyPEM);
X509EncodedKeySpec spec = new X509EncodedKeySpec(decoded);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePublic(spec);
}

How to use SubjectPublicKeyInfo encrypt data?

I'm newer to RSA and used BC get SubjectPublicKeyInfo from a public key.
String key = "-----BEGIN RSA PUBLIC KEY-----\n" +
"........\n" +// Multiple lines here
"-----END RSA PUBLIC KEY-----\n";
Security.addProvider(new BouncyCastleProvider());
PEMParser reader = new PEMParser(new StringReader(key));
SubjectPublicKeyInfo subjectPublicKeyInfo = (SubjectPublicKeyInfo) reader.readObject();
And then I want encrypt datas. I found some one use RSAEngine to do it:
AsymmetricKeyParameter aKey = (RSAKeyParameters) PublicKeyFactory.createKey(subjectPublicKeyInfo);
AsymmetricBlockCipher engine = new RSAEngine();
engine.init(false, aKey);
byte[] dataEncrypted = engine.processBlock(data, 0, data.length);
After I run those code, I found the result isn't equal to the expection. So I want to know is there any mistake in my code?
Finally I found my way out.
If anyone is familiar with BouncyCastle, he can point me the low-level mistakes.
Firstly, to encrypt data should init Engine with true at first arg in init function.
Secondly, my public key is start with '-----BEGIN RSA PUBLIC KEY-----'. It's PKCS#1 format RSA public key and should use BouncyCastle to read in, but encrypt data should have padding. So, I shouldn't use RSAEngine directly, use PKCS1Encoding instead.
At last , post my encrypt code and decrypt code:
Encryption:
Security.addProvider(new BouncyCastleProvider());
PEMParser reader = new PEMParser(new StringReader(key));
SubjectPublicKeyInfo subjectPublicKeyInfo = (SubjectPublicKeyInfo) reader.readObject();
RSAKeyParameters rsaKeyParameters = (RSAKeyParameters)
PublicKeyFactory.createKey(subjectPublicKeyInfo);
PKCS1Encoding engine = new PKCS1Encoding(new RSAEngine());
engine.init(true, rsaKeyParameters);
return engine.processBlock(data, 0, data.length);
Decryption:
public static byte[] decryptByPublicKey(String data, String key) throws Exception {
byte[] rawData = Base64.decode(data);
Security.addProvider(new BouncyCastleProvider());
PEMParser reader = new PEMParser(new StringReader(key));
PEMKeyPair pemKeyPair = (PEMKeyPair) reader.readObject();
SubjectPublicKeyInfo publicKeyInfo = pemKeyPair.getPublicKeyInfo();
PrivateKeyInfo privateKeyInfo = pemKeyPair.getPrivateKeyInfo();
RSAKeyParameters rsaKeyParameters = (RSAKeyParameters)
PrivateKeyFactory.createKey(privateKeyInfo);
PKCS1Encoding engine = new PKCS1Encoding(new RSAEngine());
engine.init(false, rsaKeyParameters);
return engine.processBlock(rawData, 0, rawData.length);
}
For encryption , you can use modulus and public exponent to create a key that support by JDK:
Security.addProvider(new BouncyCastleProvider());
PEMParser reader = new PEMParser(new StringReader(key));
PemObject obj = reader.readPemObject();
org.bouncycastle.asn1.pkcs.RSAPublicKey rsaPublicKey = org.bouncycastle.asn1.pkcs.RSAPublicKey.getInstance(obj.getContent());
BigInteger modulus = rsaPublicKey.getModulus();
BigInteger publicExponent = rsaPublicKey.getPublicExponent();
KeyFactory keyFactory = KeyFactory.getInstance("RSA", "BC");
RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(modulus, publicExponent);
PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC");//This line should use right padding.For PKCS#1 format RSA key , it should be this.
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
return cipher.doFinal(data);
See Also:Basic RSA example.

Categories