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
Related
I need some help with JWS Signing with RSA 256 privatekey -RSASSA-PKCS1-v1.5 SHA-256
I m working on SAP PI/PO.
I am unable to retrieve the RSA privatekey saved in server's OS folder, so I am trying to pass the pem(base64 encoded) key as a string.
My requirement is to generate Header & payload & signed it.
Sample input Header:
{"alg": "RS256","kid": "asff1233dd"}
sample Json Payload:
{"CompInvoiceId": "0009699521","IssueDtm": "20220623"}<br />
Error: I am able to generate Header.payload in base64 url encode but the signature part is getting corrupted when I convert the privatekey to PKCS8encoding.
The generated JWS looks like:
eyJhbGciOiJSUzI1NiIsImtpZCI6Imh5d3kzaHIifQ.eyJDb21waW52b2ljZSI6IjAwOTk5MzMzIiwic3VibWl0SWQiOiIxMjM0NSJ9.[B#42ace6ba
This is signature part which is getting corrupted - [B#42ace6ba
Kindly help with below code:
This is because of this declaration byte[] signed = null, when I remove
that it just throwserror as cannot find variable for signed.
Please help me with passing privatekey & signature.
The Java code I am working on:
I am passing :
Json data= data,
header = header
Privatekey in base64 = key
String jwsToken(String key, String data, String header, Container container) throws
StreamTransformationException{
String tok = null;
byte[] signed = null;
try {
StringBuffer token = new StringBuffer();
//Encode the JWT Header and add it to our string to sign
token.append(Base64.getUrlEncoder().withoutPadding().encodeToString(header.getBytes("UTF-
8")));
token.append(".");
//Encode the Json payload
token.append(Base64.getUrlEncoder().withoutPadding().encodeToString(data.getBytes("UTF-8")));
//Separate with a period
token.append(".");
//String signedPayload =
Base64.getUrlEncoder().withoutPadding().encodeToString(signature.sign());
PrivateKey privatekey = null;
String privateKeyPEM = key;
//String key = new String(Files.readAllBytes(file.toPath()), Charset.defaultCharset());
byte[] decodePrivateKey = Base64.getDecoder().decode(key);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodePrivateKey);
privatekey = (PrivateKey) keyFactory.generatePrivate(keySpec);
Signature sig = Signature.getInstance( "SHA256withRSA" );
sig.initSign( ( PrivateKey ) privatekey );
sig.update(token.toString().getBytes("UTF-8"));
signed=sig.sign();
tok = (token.toString());
}
catch (Exception e) {
e.printStackTrace();
}
return tok;
}
Instead of appending byte array, encode it in base64 then append it
signed = sig.sign();
token.append(Base64.getUrlEncoder().withoutPadding().encodeToString(signed));
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
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));
}
I am trying to create a PrivateKey instance in an Android app from a pem file to decrypt some data but I am getting the following error:
java.lang.RuntimeException: error:0c0890ba:ASN.1 encoding routines:asn1_check_tlen:WRONG_TAG
The code:
// Read private key.
InputStream is = context.getResources().openRawResource(R.raw.private_key);
br = new BufferedReader(new InputStreamReader(is));
List<String> lines = new ArrayList<String>();
line = null;
while ((line = br.readLine()) != null)
lines.add(line);
// Removes the first and last lines of the file (comments).
if (lines.size() > 1 && lines.get(0).startsWith("-----") &&
lines.get(lines.size()-1).startsWith("-----")) {
lines.remove(0);
lines.remove(lines.size()-1);
}
// Concats the remaining lines to a single String.
StringBuilder sb = new StringBuilder();
for (String aLine: lines)
sb.append(aLine);
String keyString = sb.toString();
// Converts the String to a PublicKey instance
byte[] keyBytes = Base64.decode(keyString, Base64.DEFAULT);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
mKey = keyFactory.generatePrivate(spec);
Any help?
Seems your key is not PKCS8 format. Java does not support loading keys in PKCS#1 format. Check your key is in PKCS#8 format verifying that it starts with -----BEGIN PRIVATE KEY----- If it starts with ----BEGIN RSA PRIVATE KEY----- then you need to convert it to PKCS#8. See Convert PEM traditional private key to PKCS8 private key
use this lines:
if (privateKeyString.contains("-----BEGIN PRIVATE KEY-----") || privateKeyString.contains("-----END PRIVATE KEY-----"))
privateKeyString = privateKeyString.replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "");
if (privateKeyString.contains("-----BEGIN RSA PRIVATE KEY-----") || privateKeyString.contains("-----END RSA PRIVATE KEY-----"))
privateKeyString = privateKeyString.replace("-----BEGIN RSA PRIVATE KEY-----", "").replace("-----END RSA PRIVATE KEY-----", "");
Background:
I have created an applet to extract public key of a certificate extracted from a smart card.
This public key is then stored in database.
The private key of certificate is used to sign data and the public key is then used to verify the signature.
Code for extracting public key from certificate:
private byte[] getPublicKey(KeyStore paramKeyStore)
throws GeneralSecurityException {
Enumeration localEnumeration = paramKeyStore.aliases();
if (localEnumeration.hasMoreElements()) {
String element = (String) localEnumeration.nextElement();
Certificate[] arrayOfCertificate =
paramKeyStore.getCertificateChain(element);
byte[] publicKeyByteArray =
arrayOfCertificate[0].getPublicKey().getEncoded();
return publicKeyByteArray;
}
throw new KeyStoreException("The keystore is empty!");
}
This publicKeyByteArray is then storeed in database as BLOB after converting to string using bytes2String method:
private static String bytes2String(byte[] bytes) {
StringBuilder string = new StringBuilder();
for (byte b : bytes) {
String hexString = Integer.toHexString(0x00FF & b);
string.append(hexString.length() == 1 ? "0" + hexString : hexString);
}
return string.toString();
}
The content of the BLOB(key) saved in database is:
30820122300d06092a864886f70d01010105000382010f003082010a02820101009bd307e4fc38adae43b93ba1152a4d6dbf82689336bb4e3af5160d16bf1599fe070f7acbfefd93e866e52043de1620bd57d9a3f244fb4e6ef758d70d19e0be86e1b12595af748fbc00aad9009bd61120d3348079b00af8462de46e254f6d2b092cbc85c7f6194c6c37f8955ef7b9b8937a7e9999541dbbea8c1b2349c712565482dbd573cd9b7ec56a59e7683b4c246620cf0d8148ed38da937f1e4e930eb05d5b4c6054712928fa59870763468c07e71265525e1e40839b51c833579f5742d3c8e0588766e3ed6deef1593b10baad0a2abea34734de1505d37710e1cfaa4225b562b96a6a4e87fecb1d627d4c61916e543eba87054ee9212e8183125cdb49750203010001
After reading the stored public key byte[] from database, I try to convert it back to Public Key using following code:
Cipher rsa;
rsa = Cipher.getInstance("RSA");
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(pkey.getBytes());
PublicKey pk = keyFactory.generatePublic(publicKeySpec);
rsa.init(Cipher.DECRYPT_MODE, pk);
byte[] cipherDecrypt = rsa.doFinal(encryptedText.getBytes());
but it gives following error:
Caused by: java.security.InvalidKeyException: invalid key format
at sun.security.x509.X509Key.decode(X509Key.java:387)
at sun.security.x509.X509Key.decode(X509Key.java:403)
at sun.security.rsa.RSAPublicKeyImpl.<init>(RSAPublicKeyImpl.java:83)
at sun.security.rsa.RSAKeyFactory.generatePublic(RSAKeyFactory.java:298)
at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:201)
Please suggest the reason and resolution for this issue.
You must have an error in the way you read the key back from the database. The following code works just fine for me:
String key = "3082012230..."; // full key omitted for brevity
byte[] derPublicKey = DatatypeConverter.parseHexBinary(key);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(derPublicKey);
keyFactory.generatePublic(publicKeySpec);
I would guess, based on the use of pkey.getBytes(), that you've simply tried to get the bytes from the string rather than hex-decoding it.