Hi. I'm having the same problem: I need to encode a string using JAVA, and the public key is provided by .NET as follows:
<RSAKeyValue>
<Modulus>pJbz24aBed556dtzQGn7Dn+NmaaEWONSg82HQLn3T2x0DkTQEuU40Shr5jcLTyvwxRxA0HG7NlYE7JEPLoUCKIpdBh5sRonn4ZGgF7jYIhWaHqT4sB7+oCVazdKe5c1EmBwS9c0JJPiU4mPSeVEY4NbRduxakMHp/jjMJe25OamWex8cn3ktEPbe15OWCN9hoTnK/anGQmXkzWL/YDNI7WwXIpCI2hxEt3l0AhkgZecOwTYn08wj7YTei8I15pXYiV1nNuxB5AuZrTVxFIwXYHOonblWoubJa68dAkCr5leNfuIa/JzyBAsHMnXU4aLOlrJgQx5yRdd7n0g1YMF9uw==</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
I managed to encode the string using the Cipher class, but tried the "RSA", "RSA/ECB/NoPadding" and "RSA/ECB/PKCS1Padding" and the resulted string wasn't what I expected
For example, the string 'hola' should convert to '2BC19BA2FDD7512F624B647CD153CE061BF5760A505B185DD6DD751B685BB9F5EA1BA4F8963D01FEDB72BE9C13F29F782E7AD87FEFB51B7CBFA6740C4814A8E84A80C2768C5248A6B11BE847388945C318B268C611563C1D7E3758ED5D0086DAC6425D9808F04BEAAC72AB54D623BE530815AC9F562E85F1EF61892B6B91E8A06BC89BA62AB7ED7864AC61C9AF048836DA7C5BB3F98A4FAD20FA46D4ABDA652E645DB3F98B0479BFCFED717F4FC891E768FDBA49BFB95774D84E80BCA235634044F5995674582AF8835B5C74E124704B1B629E9C115B369F61AF699EE128054F15A64743BA4F81024384BC299D83B5A491CA825F9CD3463437297B545502ECE6'
, could anybody help me to achieve this?
Thanks
Here's the class I'm using:
import java.security.interfaces.*;
import java.math.*;
import sun.misc.*;
import java.io.*;
import javax.crypto.Cipher;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
public class RSA implements RSAPublicKey
{
final String rsaPublicKeyAsXMLString = "<RSAKeyValue><Modulus>pJbz24aBed556dtzQGn7Dn+NmaaEWONSg82HQLn3T2x0DkTQEuU40Shr5jcLTyvwxRxA0HG7NlYE7JEPLoUCKIpdBh5sRonn4ZGgF7jYIhWaHqT4sB7+oCVazdKe5c1EmBwS9c0JJPiU4mPSeVEY4NbRduxakMHp/jjMJe25OamWex8cn3ktEPbe15OWCN9hoTnK/anGQmXkzWL/YDNI7WwXIpCI2hxEt3l0AhkgZecOwTYn08wj7YTei8I15pXYiV1nNuxB5AuZrTVxFIwXYHOonblWoubJa68dAkCr5leNfuIa/JzyBAsHMnXU4aLOlrJgQx5yRdd7n0g1YMF9uw==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
final BigInteger modulus;
final BigInteger exponent;
public RSA() throws Exception
{
String modulusAsBase64String = null;
String exponentAsBase64String = null;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.parse(new ByteArrayInputStream(rsaPublicKeyAsXMLString.getBytes("UTF-8")));
Element root = document.getDocumentElement();
// Go down the children looking for our interest nodes
NodeList nodeList = root.getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++)
{
Node node = nodeList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE)
{
Element element = (Element)node;
String nodeName = element.getNodeName();
if (nodeName.equals("Modulus"))
{
modulusAsBase64String = element.getTextContent();
}
else if (nodeName.equals("Exponent"))
{
exponentAsBase64String = element.getTextContent();;
}
}
}
assert modulusAsBase64String != null;
assert exponentAsBase64String != null;
final BASE64Decoder base64Decoder = new BASE64Decoder();
final byte[] modulusAsBytes = base64Decoder.decodeBuffer(modulusAsBase64String);
final byte[] exponentAsBytes = base64Decoder.decodeBuffer(exponentAsBase64String);
modulus = new BigInteger(1, modulusAsBytes);
exponent = new BigInteger(1, exponentAsBytes);
}
public String getAlgorithm()
{
return "RSA";
}
public String getFormat()
{
return "MS"; // I don't know what the correct format specification should be!
}
public byte[] getEncoded()
{
try
{
return rsaPublicKeyAsXMLString.getBytes("UTF-8");
}
catch (Exception e)
{
return null;
}
}
public BigInteger getPublicExponent()
{
return exponent;
}
public BigInteger getModulus()
{
return modulus;
}
public String codificar(String args)
{
byte[] encryptedData = null;
try
{
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, this);
byte[] dateToEncrypt = args.getBytes();
encryptedData = cipher.doFinal(dateToEncrypt);
System.out.println("RSA: " + toHexString(encryptedData).toUpperCase());
cipher = Cipher.getInstance("RSA/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, this);
dateToEncrypt = args.getBytes();
encryptedData = cipher.doFinal(dateToEncrypt);
System.out.println("RSA/ECB/NoPadding: " + toHexString(encryptedData).toUpperCase());
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, this);
dateToEncrypt = args.getBytes();
encryptedData = cipher.doFinal(dateToEncrypt);
System.out.println("RSA/ECB/PKCS1Padding: " + toHexString(encryptedData).toUpperCase());
}
catch (Exception e)
{
e.printStackTrace();
}
//String a = new String(encryptedData.toString());
//return Arrays.toString(encryptedData);
//return toBase64String(encryptedData, Base64Chars);
return toHexString(encryptedData).toUpperCase();
}
private static final char[] HexChars = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
public static final String toHexString(byte[] bytes) {
StringBuffer sb = new StringBuffer();
int i;
for (i=0; i < bytes.length; i++) {
sb.append(HexChars[(bytes >> 4) & 0xf]);
sb.append(HexChars[bytes & 0xf]);
}
return new String(sb);
}
private static final char[] Base64Chars = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/',
'='
};
public static final String toBase64String(byte[] bytes, char[] chars) {
StringBuffer sb = new StringBuffer();
int len = bytes.length, i=0, ival;
while (len >= 3) {
ival = ((int)bytes[i++] + 256) & 0xff;
ival <<= 8;
ival += ((int)bytes[i++] + 256) & 0xff;
ival <<= 8;
ival += ((int)bytes[i++] + 256) & 0xff;
len -= 3;
sb.append(chars[(ival >> 18) & 63]);
sb.append(chars[(ival >> 12) & 63]);
sb.append(chars[(ival >> 6) & 63]);
sb.append(chars[ival & 63]);
}
switch (len) {
case 0:// No pads needed.
break;
case 1: // Two more output bytes and two pads.
ival = ((int)bytes[i++] + 256) & 0xff;
ival <<= 16;
sb.append(chars[(ival >> 18) & 63]);
sb.append(chars[(ival >> 12) & 63]);
sb.append(chars[64]);
sb.append(chars[64]);
break;
case 2:// Three more output bytes and one pad.
ival = ((int)bytes[i++] + 256) & 0xff;
ival <<= 8;
ival += ((int)bytes + 256) & 0xff;
ival <<= 8;
sb.append(chars[(ival >> 18) & 63]);
sb.append(chars[(ival >> 12) & 63]);
sb.append(chars[(ival >> 6) & 63]);
sb.append(chars[64]);
break;
}
return new String(sb);
}
}
Fr3dYa at 2007-7-15 13:25:56 >

Hi. Sorry for the non-compiling code, I just removed some stuff before copying the text and didn't checked it out.
About the 'hola' string encoding to '2BC...' , it's just because I asked the .NET guy to encode it, so I could compare with the strings I was getting with the JAVA code. I don't know if they use padding or not, here's the .net function:
Private Shared Function EncryptRSA(ByVal sTexto As String) As String
Dim sTextoEnc As String
Dim CspParameters As CspParameters = New CspParameters
CspParameters.Flags = CspProviderFlags.UseMachineKeyStore
Dim rsa As New RSACryptoServiceProvider(CspParameters)
Dim i As Integer
Dim PlainTextBArray As Byte()
Dim CypherTextBArray As Byte()
Dim xmlPublicKey As String
Dim oAcceso As Espec.IAccesoDatos
Try
'Get the public key from the registry
oAcceso = New Espec.AccesoDatos
xmlPublicKey = oAcceso.ReadKeyFromRegistry(Espec.IAccDatNoTrans.TpKey.PublicKey)
If xmlPublicKey <> Constantes.ERROR_KEY_NOT_FOUND Then
rsa.FromXmlString(xmlPublicKey)
If sTexto.Length > 58 Then
Throw New Exception("Key too long")
End If
'Convert the key to Byte Array
PlainTextBArray = (New UnicodeEncoding).GetBytes(sTexto)
'Encrypt
CypherTextBArray = rsa.Encrypt(PlainTextBArray, False)
'Convert the Byte Array to a String of its elements in Hex format
For i = 0 To CypherTextBArray.Length - 1
sTextoEnc &= Right("0" & Hex(CypherTextBArray(i)), 2)
Next i
Else
Throw New Exception("There is no Public Key")
End If
Catch ex As Exception
Finally
EncryptRSA = sTextoEnc
Funciones.DisposeSeguro(oAcceso)
Funciones.DisposeSeguro(rsa)
End Try
End Function
Fr3dYa at 2007-7-15 13:25:56 >

Thanks for your help. I managed to encode the string and now the .NET webservice accepts it.
The problem now is that the decoded .NET string doesn't match the original one. How is this possible?
Here's the .NET function that does the decoding:
Private Shared Function DecryptRSA(ByVal sTexto As String, Optional ByVal bPrivado As Boolean = False) As String
Dim sTextoDesenc As String
Dim CspParameters As CspParameters = New CspParameters
CspParameters.Flags = CspProviderFlags.UseMachineKeyStore
Dim rsa As New RSACryptoServiceProvider(CspParameters)
Dim i As Integer
Dim CypherTextBArray(255) As Byte
Dim oAcceso As Centralizada.IAccesoDatosT
Dim xmlKeys As String
Try
For i = 1 To sTexto.Length Step 2 'Get the Byte Array from the Hex String
CypherTextBArray((i - 1) / 2) = CByte(CInt("&H" & Mid(sTexto, i, 2)))
Next
oAcceso = New Centralizada.AccesoDatos
If bPrivado Then 'If encrypted with private key, we decode using the public one
xmlKeys = oAcceso.LeeClaveDelRegistro(AccesoDatos.TpClave.ClavePublica)
Else
xmlKeys = oAcceso.LeeClaveDelRegistro(AccesoDatos.TpClave.ClavePrivada)
End If
If xmlKeys <> AccesoDatos.ERROR_KEY_NOT_FOUND Then
rsa.FromXmlString(xmlKeys)'Get the RSA object
Dim RestoredPlainText As Byte() = rsa.Decrypt(CypherTextBArray, False) 'Decode the key
For i = 0 To (RestoredPlainText.Length - 1) Step 2'Convert the Byte Array to String and get the decoded key
sTextoDesenc &= Chr(RestoredPlainText(i))
Next i
Else
Throw New Exception("There is no private key")
End If
Catch ex As Exception
If ex.GetType.FullName = "System.Security.Cryptography.CryptographicException" Then
Throw New Exception("Active Directory; Error decoding RSA: " & ex.Message)
Else
Throw ex
End If
Finally
DecryptRSA = sTextoDesenc
Funciones.DisposeSeguro(oAcceso)
End Try
End Function
Fr3dYa at 2007-7-15 13:25:56 >
