4

I am currently creating a sign hash by encrypting data by public key and then signing it using RSACryptoServiceProvider.SignData method

String data = "some string here";
// **Step 1: encrypt data with public key**
Byte[] encryptedData = publicKeyRsa.Encrypt(System.Text.Encoding.UTF8.GetBytes(data), false);

// **Step 2: sign the encrypted data with private key**
Byte[] sign = privateKeyRsa.SignData(encryptedData, new SHA1CryptoServiceProvider());

// **Step 3: get hash for sign**
String signHash = System.Web.HttpServerUtility.UrlTokenEncode(sign);

I am unable to successfully implement the same algorithm in Java. This is what I currently have

    Base64 base64Encoder = new Base64();

    // initialize cipher to encrypt
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.ENCRYPT_MODE, pubKey);

    // **Step 1: encrypt data with public key**
    byte[] encBytes = cipher.doFinal(VALUE.getBytes("UTF-8"));
    byte[] encryptedData  = base64Encoder.encode(encBytes);
    String encryptedDataString = bytes2String(encryptedData);
    System.out.println("data encrypted: " + encryptedData);

    // **Step 2: sign the encrypted data with private key**
    Signature sig = Signature.getInstance("SHA1WithRSA");
    sig.initSign(privKey);
    sig.update(encryptedData);
    byte[] signData = sig.sign();

    // **Step 3: get hash for sign**
    byte[] signDataEncrypted = base64Encoder.encode(signData);
    String signDataString = bytes2String(signDataEncrypted);
    System.out.println("hash: "+signDataString);

my implementation of bytes2String is from here

Using SHA1 and RSA with java.security.Signature vs. MessageDigest and Cipher

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 C# code works perfectly, but the java code does not provide the "right values" (as per the server). Does the Java code look correct? Is there something I am doing wrong as compared to the C# code?

Thanks

Community
  • 1
  • 1
Dexter
  • 1,621
  • 3
  • 18
  • 38
  • It could be a mismatch between the implementation of the RSA algorithms. Please edit and add the code for the RSA object creation in C#. Also, are you completely sure you are using the same key in both encryptors? – Camilo Terevinto Jan 11 '16 at 18:47
  • Where are the keys from? If I remember correctly you had to remove the first byte from the rsa exponent and modulus for JAVA<->c# comparability. – jHilscher Jan 11 '16 at 19:12
  • Do you already see a mismatch in `encryptedDataString` or only in the hash? – jHilscher Jan 11 '16 at 19:17
  • @jHilscher , the hash and encrypted data is different everytime for the same values (in .NET and Java implementations), so there is no way to confirm that. Do you suspect anything done wrong on the Java side as compared to the .NET version of the code? – Dexter Jan 11 '16 at 19:44
  • you could try `Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC");` that's why I used, when dealing with JAVA+c# RSA Keys – jHilscher Jan 11 '16 at 20:15
  • *encryptedData = base64Encoder.encode(encBytes)* - Is there a special reason why you Base64 encode the encrypted data? – mkl Jan 12 '16 at 12:28
  • 1
    Having looked at it some more I would say that without the base64 encoding call (for which I see no corresponding operation in your c# code) the cryptographical operations look ok- To be sure I'd also explicitly use the block chaining mode and the padding in the cipher but you do not have to select the BouncyCastle provider. – mkl Jan 12 '16 at 15:26

1 Answers1

2

I was finally able to successfully solve the issue. :) Thank you guys for all the help!

The following were the fixes

Problem 1: Incorrect Cipher algo

I changed the Cipher algo from "RSA" to "RSA/ECB/PKCS1Padding"

Problem 2: bytes2String() method

I replaced my bytes2String() logic with this

public String bytes2String(byte[] bytes) {
  return Base64.encodeBase64URLSafeString(bytes);
}

Problem 3: C# UrlTokenEncode method

I assumed the Java and C# method for converting to string would be identical. Actually, C# adds additional padding characters as mentioned here (http://infospace.com/partners/sdk/csr/signingSample.html).

Hopefully this helps someone!

Dexter
  • 1,621
  • 3
  • 18
  • 38