In reference to this discussion: Decode South African (ZA) Drivers License
Please assist I seem to be getting an error trying to create PublicKey instance in Java on android. I have pasted the error below:
java.lang.RuntimeException: error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag
Here is the code snippet:
Cipher asymmetricCipher = null;
asymmetricCipher = Cipher.getInstance("RSA");
X509EncodedKeySpec publicKeySpec128 = new X509EncodedKeySpec(key128block);
X509EncodedKeySpec publicKeySpec74 = new X509EncodedKeySpec(key74block);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
Key key = keyFactory.generatePublic(publicKeySpec128);
asymmetricCipher.init(Cipher.DECRYPT_MODE, key);
byte[] plainText = asymmetricCipher.doFinal(topBlocksData[0]);
The encoded public keys you're trying to read are not of the format expected by X509EncodedKeySpec. Instead they are of an even simpler form which, unfortunately, is not supported by Java. However, you can use the Bouncycastle or Spongycastle library to code up a small java routine to parse the values. The code below is copied from my answer to this question.
import java.io.IOException;
import java.math.BigInteger;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DLSequence;
public class RsaAsn1Example {
// ...
public static BigInteger [] parseASN1RsaPublicKey(byte [] encoded) throws IOException {
ASN1InputStream asn1_is = new ASN1InputStream(encoded);
DLSequence dlSeq = (DLSequence) asn1_is.readObject();
ASN1Integer asn1_n = (ASN1Integer) dlSeq.getObjectAt(0);
ASN1Integer asn1_e = (ASN1Integer) dlSeq.getObjectAt(1);
asn1_is.close();
return new BigInteger[]{ asn1_n.getPositiveValue(), asn1_e.getPositiveValue()};
}
// ....
}
The values returned by parseASN1RsaPublicKey can be supplied to an RsaPublicKeySpec constructor to create the public key.
Also examine divanov's answer to the same questions for an alternative.
Related
I'm trying to decode/encode a signature with SHA256withECDSA.
I have a Java code that works fine:
public void verify() throws Exception {
Signature ecdsaVerify = Signature.getInstance("SHA256withECDSA"));
EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode("your public key goes here"));
KeyFactory keyFactory = KeyFactory.getInstance("EC");
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
ecdsaVerify.initVerify(publicKey);
ecdsaVerify.update("All the webhook field values (only the values) concatenated together using a semicolon ;".getBytes("UTF-8"));
boolean result = ecdsaVerify.verify(Base64.getDecoder().decode("Signature to verify")); //Must return true
}
but I need this solution for nodejs.
when I'm creating an base64 buffer in nodejs it's getting a different results from the Java code.
I currently use cryptojs & jwa npm's.
Edit:
this is my code for nodejs:
var jwa = require("jwa");
const verifySignature = () => {
let public_key = Buffer.from("public key here", "base64");
let signature = Buffer.from("Signature_here", "base64");
let payload = "data here seperated by semicolon";
let ecdsa = jwa("ES256");
let verify = ecdsa.verify(payload, signature, public_key);
}
verifySignature();
JWA implements the algorithms used in JOSE, and in particular for ECDSA uses the signature format (aka encoding) defined in P1363 that simply contains fixed-length R and S concatenated; see steps 2 and 3 of https://datatracker.ietf.org/doc/html/rfc7518#section-3.4 . This is not the format used by most other standards, and in particular by Java, which is an ASN.1 DER-encoded SEQUENCE of two INTEGER values, which are (both) variable length (all) with tag and length prefixes.
You don't need JWA at all; builtin 'crypto' has the functionality you need:
import java.security.KeyFactory;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class SO70655734 {
public static void main (String[] args) throws Exception {
String data = "some;test;data";
String pubkey = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEyOFORyCVCxX+W4QZevzH6skTbp2lVDtRLV0+7ypHjX26wFtSWSe4MTI0GZjIKDOAIT8KpbqH8HXI6Wo5S6/6hg==";
String sig = "MEQCICDLwztlKOXmQLuDJ0Hh96gGAT2/wsm2ymw3CDxSDnB3AiAK7eR8+C6g/zw5TmXUX0K/pV5kjIJTCieIkQXzH30WYA==";
Signature ecdsa = Signature.getInstance("SHA256withECDSA");
ecdsa.initVerify(KeyFactory.getInstance("EC").generatePublic(
new X509EncodedKeySpec(Base64.getDecoder().decode(pubkey)) ));
ecdsa.update(data.getBytes("UTF-8")); // or StandardCharsets.UTF_8
System.out.println(ecdsa.verify(Base64.getDecoder().decode(sig)));
}
}
-> true
const crypto = require('crypto');
const data = "some;test;data";
const pubkey = "-----BEGIN PUBLIC KEY-----\n"
+ "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEyOFORyCVCxX+W4QZevzH6skTbp2lVDtRLV0+7ypHjX26wFtSWSe4MTI0GZjIKDOAIT8KpbqH8HXI6Wo5S6/6hg==\n"
+ "-----END PUBLIC KEY-----\n";
const sig = "MEQCICDLwztlKOXmQLuDJ0Hh96gGAT2/wsm2ymw3CDxSDnB3AiAK7eR8+C6g/zw5TmXUX0K/pV5kjIJTCieIkQXzH30WYA==";
var ecdsa = crypto.createVerify('SHA256');
ecdsa.update(data,'utf8');
console.log( ecdsa.verify(pubkey, sig,'base64') );
-> true
Note: recent versions of nodejs can instead take DER-format pubkey (without the BEGIN/END lines added, but with the base64 converted to binary), but my most convenient test system only has 8.10.0 so I went the more compatible old way.
I am using the following code block to parse any RSA public key to encrypt.
static byte[] encrypt(byte[] publicKey, byte[] inputData) throws Exception {
PublicKey key = KeyFactory.getInstance(ALGORITHM).generatePublic(new X509EncodedKeySpec(publicKey));
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptedBytes = cipher.doFinal(inputData);
return encryptedBytes;
}
public static String getEncrypted(String data, String key) throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(key);
return new String(Base64.getEncoder().encode(encrypt(keyBytes, data.getBytes())));
}
But for the following RSA public Key
MIIBCgKCAQEAs6YyGDXibkazM7QSeFBXjkAn5A8P87k+nuU6v5+zLJiD1KwkZ/SYnLwVSluOx19AzPHj07abDTJtthKtKpp2997UiV4CNUSzkZM1Eorf1+iLFhqeOiz9J5tYfFkKN5qPzwoPK4aFz35hQi7R1ORF9rFDPL+Ex79Tc+ABQF/CH5tn/NTXCNUYzLezg2Y1VOZGNhxd2LIv/29ZDxpJS8dD34H20HMMZCMGGolTXUIxVKI3cR0d1XzNCvAx3jcSkEUEPPH0lfusXqQOfCxJSIjorAzi5ucaWicvXYq6BNGulPqLoGBZnJ4HrFQF0oq1SU4i60VHqOgoiqMPQ+8cyjFBHQIDAQAB
while parsing I am getting the following exception
Caused by: java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: algid parse error, not a sequence
at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:205)
at java.security.KeyFactory.generatePublic(KeyFactory.java:334)
Caused by: java.security.InvalidKeyException: IOException: algid parse error, not a sequence
at sun.security.x509.X509Key.decode(X509Key.java:397)
at sun.security.x509.X509Key.decode(X509Key.java:402)
at sun.security.rsa.RSAPublicKeyImpl.<init>(RSAPublicKeyImpl.java:86)
at sun.security.rsa.RSAKeyFactory.generatePublic(RSAKeyFactory.java:298)
at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:201)
Any idea what is failing and how to make a generic RSA public key parsing code.
Your problem is analagous to the problem in InvalidKeySpecException : algid parse error, not a sequence, though not the same. Just like PKCS8 is a generic format for private keys in (almost) any algorithm, by containing both an AlgorithmIdentifier that identifies the algorithm and algorithm-specific data, Java uses the generic format SubjectPublicKeyInfo (SPKI) defined by X.509/PKIX for public keys, which Java calls X509EncodedKeySpec, containing an AlgId plus algorithm-specific data. (See the javadoc for java.security.Key; for some reason I am currently unable to access docs.oracle.com to get a link.) You have only the algorithm-specific data defined by PKCS1 RSAPublicKey.
You can parse and use it 'manually' with BouncyCastle, or convert it to SPKI and use that. Or (given BC or another ASN.1 library) you could use the same approach as in #31941413 except omit the Integer version (0) and wrap the data in a DERBitString instead of a DEROctetString, or the simpler and more direct approach I show in RSA should I use X.509 or PKCS #1 .
Note this is not 'generic'. Your format is the opposite of algorithm-generic, which as noted is the purpose of SPKI and PCKS8. It is also not applciation-generic; among other things OpenSSH, PGP, Microsoft, PKCS11, JWK, and XML all use publickey formats different from this and not easily compatible with Java.
Your public key (here just the Base64-encoded part) seems to be a 'RSA Public Key'
and not a 'Public Key'. The later is the format that Java is been able to work with.
To read the 'RSA Public Key' you need the Bouncy Castle library and additional 7 lines of code. As you have the key without the 'wrapping' header and footer I add the two
line manually.
Please keep in mind that the following code has no proper exception handling and is for educational purposes only.
result:
key: Sun RSA public key, 2048 bits
params: null
modulus: 22678610734153400983507431374302231631648011897672768754638644005690558018788055145838420912495825001883497816406549666369767766949853573723573636289962789479998547620264293389522975840594912755684410510779642046063268111520844008640320545114702934792800828432077361704284837605938354936920018742130341245366517474980128047515437565419306561322350155414838564407700303406271838590880852369997316303577351737008942081641382006211591786506015023574950120763293965668830106827392978781367691242570394862298000041087969687942746452359360224223895623579995775734139473237799095359767270215802792812274542667250920043135261
public exponent: 65537
code:
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMParser;
import java.io.IOException;
import java.io.StringReader;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
public class MainSO {
public static void main(String[] args) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
System.out.println("https://stackoverflow.com/questions/63454577/failed-to-parse-rsa-publickey-in-java");
Security.addProvider(new BouncyCastleProvider());
String rsaPublicKeyHeader = "-----BEGIN RSA PUBLIC KEY-----\n";
String rsaPublicKeyFooter = "\n-----END RSA PUBLIC KEY-----";
String rsaPublicKeyString = "MIIBCgKCAQEAs6YyGDXibkazM7QSeFBXjkAn5A8P87k+nuU6v5+zLJiD1KwkZ/SYnLwVSluOx19AzPHj07abDTJtthKtKpp2997UiV4CNUSzkZM1Eorf1+iLFhqeOiz9J5tYfFkKN5qPzwoPK4aFz35hQi7R1ORF9rFDPL+Ex79Tc+ABQF/CH5tn/NTXCNUYzLezg2Y1VOZGNhxd2LIv/29ZDxpJS8dD34H20HMMZCMGGolTXUIxVKI3cR0d1XzNCvAx3jcSkEUEPPH0lfusXqQOfCxJSIjorAzi5ucaWicvXYq6BNGulPqLoGBZnJ4HrFQF0oq1SU4i60VHqOgoiqMPQ+8cyjFBHQIDAQAB";
PEMParser pemParser = new PEMParser(new StringReader(rsaPublicKeyHeader +
rsaPublicKeyString + rsaPublicKeyFooter));
SubjectPublicKeyInfo subjectPublicKeyInfo = (SubjectPublicKeyInfo) pemParser.readObject();
byte[] publicKey = subjectPublicKeyInfo.getEncoded();
// original code starts here
PublicKey key = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(publicKey));
// check key
System.out.println("key: " + key);
}
}
I have some java code I have been asked to convert to Python2.7 I have looked online and dont find a good example.
The Java code is building a signature using SecretKeySpec function and HmacSHA256.
It takes a keyString as parameter and a message string a
Below is the function I need to convert to Python:
public static String genSig(String key, String Params) throws Exception {
byte[] decodedKey = Base64.getDecoder().decode(key);
SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "HmacSHA256");
Mac hmacSha256 = Mac.getInstance("HmacSHA256");
hmacSha256.init(originalKey);
hmacSha256.update(Params.getBytes());
byte[] HmachSha256DigestBytes = hmacSha256.doFinal();
return Base64.getEncoder().encodeToString(HmachSha256DigestBytes);
}
I have looked into hmac and the hashlib libraries, but Im not sure what to use from these libraries to fulfill this conversion?
You can use the following code:
import hmac
import hashlib
import base64
def generateSignatureFromParams(key, params):
dig = hmac.new(base64.b64decode(key), msg=params, digestmod=hashlib.sha256).digest()
return base64.b64encode(dig).decode()
print generateSignatureFromParams("a2V5", "encrypt")
Notice to get HMACSha256, the digestmod=hashlib.sha256 is important.
I make encryption on python and try to decrypt it on Java, but always get decryption error
I have part of code for encrypt and decrypt message in JAVA encoded in RSA
For decrypt:
import java.security.*;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import javax.crypto.Cipher;
public class Decrypter
{
public static void main(String[] args)
{
try {
String encoded_data = "PueF1RC5giqmUK9U+X80SwjAjGmgfcHybjjQvWdqHSlua1rv6xr7o6OMutHBU+NRuyCJ3etTQssYOMGiWPITbEC8xr3WG9H9oRRnvel4fYARvQCqsGmf9vO9rXcaczuRKc2zy6jbutt59pKoVKNrbonIBiGN1fx+SaStBPe9Jx+aZE2hymDsa+xdmBSCyjF30R2Ljdt6LrFOiJKaDiYeF/gaej1b7D8G6p0/HBPxiHMWZhx1ZfylSvZ6+zyP0w+MJn55txR2Cln99crGtcdGeBDyBtpm3HV+u0VlW7RhgW5b+DQwjQ/liO+Ib0/ZIPP9M+3sipIwn2DKbC45o0FZHQ==";
byte[] decodeData = Base64.getDecoder().decode(encoded_data);
String publicKeyString = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxzN2+mrQRXKshq3k0r06" +
"0/FoWafOCl6fCCyuu/7SejNU95SN2LZyopA3ipamY5MeK1G1XHOhEfkPWcYcgUbz" +
"TdD166nqJGi/O+rNK9VYgfhhqD+58BCmLlNidYpV2iDmUZ9B/cvVsQi96GY5XOaK" +
"xuVZfwrDK00xcOq+aCojQEvMh+gry05uvzfSv9xK3ki5/iCMY62ReWlmrY0B19CQ" +
"47FuulmJmrxi0rv2jpKdVsMq1TrOsWDGvDgZ8ieOphOrqZjK0gvN3ktsv63kc/kP" +
"ak78lD9opNmnVKY7zMN1SdnZmloEOcDB+/W2d56+PbfeUhAHBNjgGq2QEatmdQx3" +
"VwIDAQAB";
KeyFactory kf = KeyFactory.getInstance("RSA");
byte[] encodedPb = Base64.getDecoder().decode(publicKeyString);
X509EncodedKeySpec keySpecPb = new X509EncodedKeySpec(encodedPb);
PublicKey pubKey = kf.generatePublic(keySpecPb);
Cipher cipherDecr = Cipher.getInstance("RSA");
cipherDecr.init(Cipher.DECRYPT_MODE, pubKey);
byte[] cipherDataDecr = cipherDecr.doFinal(decodeData);
String result = new String(cipherDataDecr);
System.out.println("result = "+result);
}catch (Exception e){
e.printStackTrace(System.out);
}
}
}
Unfortunately I can't make changes in this code, so all what I can is make changes in python part. This part work correctly. for check I use this code for encrypt:
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import javax.crypto.Cipher;
public class Encrypter
{
public static void main(String[] args)
{
try {
String data = "111111111222";
String privateKeyString = "here is my privat key";
byte [] encoded = Base64.getDecoder().decode(privateKeyString);
System.out.println("encoded = "+encoded);
java.security.Security.addProvider( new org.bouncycastle.jce.provider.BouncyCastleProvider());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
KeySpec ks = new PKCS8EncodedKeySpec(encoded);
RSAPrivateKey privKey = (RSAPrivateKey) keyFactory.generatePrivate(ks);
System.out.println("privKey = "+privKey);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
cipher.init(Cipher.ENCRYPT_MODE, privKey);
byte[] cipherData = cipher.doFinal(data.getBytes());
String card = Base64.getEncoder().encodeToString(cipherData);
System.out.println("data = "+card);
}catch (Exception e){
e.printStackTrace(System.out);
}
}
}
And when I use result from Java code for encrypt and put this result to decrypt Java file - all work's great. I need same encryption part, but writing with python.
Part for encrypt with python
import base64
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
data = '111111111222'
privat_key = 'here is my privat key'
key = RSA.importKey(privat_key)
cipher = PKCS1_v1_5.new(key)
encrypted_message = str(base64.b64encode(cipher.encrypt(base64.b64decode(data))), 'utf8')
print(encrypted_message)
So, questions is how I should encrypt message for correct decryption with on Java?
I tried different libs (standard rsa, Pycrypto RSA, PKCS1_OAEP, PKCS1_v1_5) and nothing help me
P.S. I know about wrong way for use keys pair, but it is requirements of the external system
UPDATE:
Using new instance fetch me to the some result. I changed format as Maarten Bodewes said
Cipher cipherDecr = Cipher.getInstance("RSA/ECB/NoPadding");
decryption result:
����2����ٰoܬ���(�RM#�/���u*�d�{���w�b+���v�ݏ[�$�#��xJo�s��F1���X��}���1 ���������t%`�YA/��?�
�ɼej�X�T�+6Y4D��!���
I can't read it, but it's not a Exception, it is good. Try to move this way
UPDATE:
I define that Java used RSA/ECB/PKCS1Padding as default. So I should use same in python
First of all I defined that java
Cipher cipher = Cipher.getInstance("RSA");
expanded in
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
or
Cipher cipher = Cipher.getInstance("RSA/None/PKCS1PADDING");
For RSA no different what is defined in second argument (None or ECB). RSA doesn't use it.
So I need add padding to my encryption in python. Unfortunately PyCrypto hasn`t PKCS1PADDING, so i can't encrypt with this padding.
Next step I found M2Crypto lib https://gitlab.com/m2crypto/m2crypto
This fork worked for python3. just download and build it(instruction in repo)
Than I wrote this code and it works:
import M2Crypto
# read privat key
privatKey = M2Crypto.RSA.load_key('privat.key')
# encrypt plaintext using privat key
ciphertext = privatKey.private_encrypt(data.encode('utf-8'), M2Crypto.RSA.pkcs1_padding)
encrypted_message = str(base64.b64encode(ciphertext), 'utf8')
print(encrypted_message)
That's all. It works for me, and I believe, it can help u.
According to my code, Bouncy uses the padding for signature generation, so I presume that is what is different. You can perform a "raw" decrypt (modular exponentiation) and remove the padding yourself.
i got problem Encrypting a string using RSA.
my RSA is in XML format, it looks like that:
<RSAKeyValue><Modulus>lT8ykfyV0R8o3mJZZezLKTKJpYB90Pzvp0moLzh9CTGfgsxLKYiAl+YGaoRfQ7hVQos5UlLIONHWKPNco9kKcmL6EBJvFc8wqBnhX0p4ML2WSv1yDIRsm9XXra82WHIa3+fxK8bNUJHrucxmpr9pDRPdZGZkz+Q9s94FcOyFKbs=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>
and i'm trying to encrypt a string using this class:
import java.io.BufferedReader;
import java.io.StringReader;
import java.security.KeyPair;
import java.security.PublicKey;
import java.security.Security;
import javax.crypto.Cipher;
import org.bouncycastle.openssl.PEMReader;
import android.util.Base64;
import android.util.Log;
public class RsaEncryption {
private String publicKey;
public RsaEncryption(String publicKey)
{
this.publicKey = publicKey;
}
/*
* Function to encrypt the data.
*
*/
public String encrypt( String data ) throws Exception
{
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
Cipher cipher = Cipher.getInstance("RSA/None/OAEPWithSHA1AndMGF1Padding", "BC");
byte[] keyBytes = Base64.decode( this.publicKey, 0 );
PublicKey publickey = strToPublicKey(new String(keyBytes));
cipher.init( Cipher.ENCRYPT_MODE , publickey );
// Base 64 encode the encrypted data
byte[] encryptedBytes = Base64.encode( cipher.doFinal(data.getBytes()), 0 );
return new String(encryptedBytes);
}
public static PublicKey strToPublicKey(String s)
{
PublicKey pbKey = null;
try {
BufferedReader br = new BufferedReader( new StringReader(s) );
PEMReader pr = new PEMReader(br);
Object obj = pr.readObject();
if( obj instanceof PublicKey )
{
pbKey = (PublicKey) pr.readObject();
}
else if( obj instanceof KeyPair )
{
KeyPair kp = (KeyPair) pr.readObject();
pbKey = kp.getPublic();
}
pr.close();
}
catch( Exception e )
{
Log.d("CIPHER", e.getMessage() );
}
return pbKey;
}
}
as you can see i'm using bouncycastle's jar
the error that i get is:
java.security.InvalidKeyException: unknown key type passed to RSA
I'm not sure about this part
Cipher cipher = Cipher.getInstance("RSA/None/OAEPWithSHA1AndMGF1Padding", "BC");
maybe this is the problem?
if it is, what need to be there instead?
i did hours of research and still didn't find a solution...
Thanks in advance :)
Cipher cipher = Cipher.getInstance("RSA/None/OAEPWithSHA1AndMGF1Padding", "BC");
maybe this is the problem?
No it's not.
OAEPWith<digest>And<mgf>Padding
Means Optimal Asymmetric Encryption Padding scheme defined in PKCS1, where <digest> should be replaced by the message digest algorithm and <mgf> by the mask generation function. Examples: OAEPWithMD5AndMGF1Padding and OAEPWithSHA-512AndMGF1Padding.
Reference Standard Names and RFC 4055.
The problem is in your Public Key generation. As your key is in XML, and Base64 encoded:
First you need to separate modulus and exponent.
Then Base64 decode both modulus and exponent.
After decoding you will get the byte array of modulus and exponent, so you can easily prepare public key object like the following procedure:
BigInteger modBigInteger = new BigInteger(1, modulus);//modulus must be byte array
BigInteger exBigInteger = new BigInteger(1, exponent);//exp must be byte array
RSAPublicKeySpec spec = new RSAPublicKeySpec(modBigInteger, exBigInteger);
KeyFactory factory = KeyFactory.getInstance("RSA");
PublicKey publicKey = factory.generatePublic(spec);
XML is not PEM.
You need to extract the modulus and the public exponent from the XML and then generate a key using an "RSA" KeyFactory instance and a RSAPublicKeySpec.