10

I have the following data signing code in C#

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();

string PrivateKeyText = "<RSAKeyValue><Modulus>....</D></RSAKeyValue>";

rsa.FromXmlString(PrivateKeyText);

string data = "my data";        

byte[] SignedByteData = rsa.SignData(Encoding.UTF8.GetBytes(data), new SHA1CryptoServiceProvider());

and I want reproduce the same code in Java (Android):

String modulusElem = "...";
String expElem = "...";

byte[] expBytes = Base64.decode(expElem, Base64.DEFAULT);
byte[] modulusBytes = Base64.decode(modulusElem, Base64.DEFAULT);

BigInteger modulus = new BigInteger(1, modulusBytes);
BigInteger exponent = new BigInteger(1, expBytes);

try {
    KeyFactory factory = KeyFactory.getInstance("RSA");

    Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");

    String data = "my data";

    MessageDigest md = MessageDigest.getInstance("SHA-1");
    byte[] hashedData = md.digest(data.getBytes("UTF-8"));

    RSAPublicKeySpec pubSpec = new RSAPublicKeySpec(modulus, exponent);

    PublicKey publicKey = factory.generatePublic(pubSpec);

    cipher.init(Cipher.ENCRYPT_MODE, publicKey);

    byte[] SignedByteData = cipher.doFinal(hashedData);

} catch (Exception e){

}

But I get mismatched output byte arrays. Where am I wrong and What should be the transformation used in Cipher.getInstance(...) ?

Mohsen Afshin
  • 13,273
  • 10
  • 65
  • 90
  • Check this http://stackoverflow.com/questions/18089923/translating-c-sharp-rsacryptoserviceprovider-into-java-code – Zohra Khan Jan 27 '14 at 09:52
  • @ZohraKhan, I wrote my Java code from that post in the first place. The method used in that post is 'Encrypt' while I'm using SignData which has a hashing function built-in. – Mohsen Afshin Jan 27 '14 at 09:56

1 Answers1

8

Use Signature.getInstance("SHA1withRSA"). Encryption is not the same as signature generation. Different padding mechanisms for one.


Update by Afshin

Complete solution. Note the use of the private exponent, ie <D>, rather the public <Exponent>

String modulusElem = "...";
String dElem = "...";

byte[] modulusBytes = Base64.decode(modulusElem, Base64.DEFAULT);
byte[] dBytes = Base64.decode(dElem, Base64.DEFAULT);

BigInteger modulus = new BigInteger(1, modulusBytes);
BigInteger d = new BigInteger(1, dBytes);

String data = "my data";            

try {
        Signature signature = Signature.getInstance("SHA1withRSA");

        KeyFactory factory = KeyFactory.getInstance("RSA");

        RSAPrivateKeySpec privateKeySpec = new RSAPrivateKeySpec(modulus, d);

        PrivateKey privateKey = factory.generatePrivate(privateKeySpec);

        signature.initSign(privateKey);

        signature.update(data.getBytes("UTF-8"));

        byte[] SignedByteData = signature.sign();

} catch(Exception e) {
    e.printStackTrace();
}
Leigh
  • 28,765
  • 10
  • 55
  • 103
Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • PS I'm presuming the older PKCS#1 padding here, RSACryptoServiceProvider docs forgets to mention the padding mechanism used. One of my older answers also asumes this and it seems correct. – Maarten Bodewes Jan 27 '14 at 12:10