1

RSA encryption and decryption work well in java side with modulus and exponent as below:

Java RSA Modulus and Exponent:

String nModulusPublic = "AJ+L/dVL9jnRX6IM87H8x2fR24t6wpzBDV7bcgPWblegR0LNK91z/OSX+lSLUgHSKJ9to/Eo8OMsREpNoJlEzI0=";
String eExponentPublic = "AQAB";
String eExponentPrivate = "AIpmE5C9TiAlgYG/Hn5dOlTS9FFv8fWseX65eZPepOUY4ivxN0lOZ+MsugZd03wmKvnxBuCGu5nv2qrUBTPzjcE=";

Java Public and Private Key Generators:

static PublicKey GetPublicKey(String publicKString, String publicExponentStr) throws Exception {
    byte[] modulusBytes = Base64.getDecoder().decode(publicKString);
    byte[] exponentBytes = Base64.getDecoder().decode(publicExponentStr);
    BigInteger modulus = new BigInteger(1, modulusBytes);
    BigInteger exponent = new BigInteger(1, exponentBytes);

    RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, exponent);
    KeyFactory fact = KeyFactory.getInstance("RSA");
    PublicKey pubKey = fact.generatePublic(rsaPubKey);
    return pubKey;
}

static PrivateKey GetPrivateKey(String nModulusPublic, String eExponentPrivate) throws Exception {
    byte[] modulusBytes = Base64.getDecoder().decode(nModulusPublic);
    byte[] exponentBytes = Base64.getDecoder().decode(eExponentPrivate);
    BigInteger modulus = new BigInteger(1, modulusBytes);
    BigInteger exponent = new BigInteger(1, exponentBytes);

    RSAPrivateKeySpec privSpec = new RSAPrivateKeySpec(modulus, exponent);
    KeyFactory fact = KeyFactory.getInstance("RSA");
    PrivateKey privKey = fact.generatePrivate(privSpec);
    return privKey;
}

I use nModulusPublic and eExponentPublic in c# to encrypting and decrypting in Java but doesn't work. Worked on RSA.Encrypt(textBytes, true); parameters in c# function change it to false and RSAEncryptionPadding.Pkcs1 but doesn't' work. When I use the result of the c# Encrypt function in java to decrypt it always encounter with this error :

javax.crypto.IllegalBlockSizeException: Data must not be longer than 64 bytes

C# encrypt function:

static string Encrypt(string text)
    {
        string outputB64 = string.Empty;
        byte[] textBytes = Encoding.UTF8.GetBytes(text);

        RSAParameters result = new RSAParameters()
        {
            Modulus = Convert.FromBase64String(nModulusPublic),
            Exponent = Convert.FromBase64String(eExponentPublic)
        };

        using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
        {
            RSA.ImportParameters(result);
            byte[] encryptedData = RSA.Encrypt(textBytes, true);
            outputB64 = Convert.ToBase64String(encryptedData);
        }          
        
        return outputB64;
    }

Extra Information, Java Encrypt and Decrypt main functions:

 static String Decrypt(String encodedString,PrivateKey privKey) {
    try {
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.DECRYPT_MODE, privKey);
        byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encodedString));
        return new String(decrypted, "UTF-8");
    } catch (Exception err) {
        return err.fillInStackTrace().toString();
    }
}
 static String Encrypt(String encodedString,PublicKey pubKey) {
    try {
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        byte[] plainBytes = new String(encodedString).getBytes("UTF-8");
        byte[] cipherData = cipher.doFinal(plainBytes);
        String encryptedString = Base64.getEncoder().encodeToString(cipherData);
        return encryptedString;
    } catch (Exception err) {
        return err.fillInStackTrace().toString();
    }
}

Update:

I was working on it and found that java encrypts function and c# have two different types, Java result always ended with "==" but c# function have one "=" at the end, It seems this is the problem.

C# Encrypt function result:

AJiltxqa1/8HU20XZlKJsJvclQ8PyQetpWdbCOpbqrXVg0q
/v4x5tXLxbzGKbO5InvKkib7tDQp+9BU0SYbZLv0=

Java Encrypt function result:

RlarFQBo2mcCWjidQ5l7ho2EOG6KGQWpR3ByXXHsGo6+HRQzmO4v7
TUTMdfB9wjI3aO6quruSReitrWu7QF9Vw==
0

2 Answers 2

2

On C# encrypt function you give the parameter 'true':

byte[] encryptedData = RSA.Encrypt(textBytes, true);

This means that C# is NOT using the PKCS1Padding but the OEAPPadding.

Simply change on Java-side in your Decrypt-method (and in your ENCRYPT-method as well :-) the line

// change:
//Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
// to
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING");

I tested it with your keypair and it works like expected.

Edit: On C#-side I run this code:

string plaintext = "The quick brown fox";
string encryptedDataBase64So = Encrypt(plaintext);
Console.WriteLine("encrypted SO : " + encryptedDataBase64So);

Console output:
encrypted SO : ZLylMsqcqbuDM7DprrmqIU8c8Q79fPXHudOY4INCNAo+iU7Oor3mZ8i+PP5PjtDkifqAXKYT8ON/ia9WjEFqRQ==

On Java-side I took the base64-String as input:

String fromCsharp = "Ew3nTEQuOX1tWfRNJEERa75A1o2bn6+HurVPYzGzA7kt+HAZAMdXKNACY2emvU6Bf42i8zpBO89lqvzuxNmRIw==";
String decryptedtext = DecryptWorking(fromCsharp, privateKey);
System.out.println("\ndecrypted from c#: " + decryptedtext);

Console output:
decrypted from c#: The quick brown fox

BTW: this is the PublicKey on C#-side that I generated from the PublicKey on Java-side and used it like this as source for the RSA-Encryption:

var publicKey = "<RSAKeyValue><Modulus>n4v91Uv2OdFfogzzsfzHZ9Hbi3rCnMENXttyA9ZuV6BHQs0r3XP85Jf6VItSAdIon22j8Sjw4yxESk2gmUTMjQ==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
RSA.FromXmlString(publicKey);
Sign up to request clarification or add additional context in comments.

4 Comments

Tested but doesn't work, Can you please share me output of c# encrypt function.
@motevalizadeh kindly see my edited answer with test data.
Thanks for your time but I could not handle it, there is something in your codes that I have not If it's possible to share your full source code on Java side, Did you used my Java function to create public and private keys?
I used your keys and your GetPrivate/PublicKey methods to encrypt and decrypt on Java side. Only on C#-side I changed the code to get the PublicKey loaded to RSA, as I rebuild your PublicKey to a XML-string (the onliner is shown above. To get it working you need to change the Java-padding as well.
1

Besides the padding error described in detail in Michael Fehr's answer, there is another issue which is actually responsible for the error message IllegalBlockSizeException: Data must not be longer than 64 bytes. The inconsistent padding would throw a BadPaddingException if the IllegalBlockSizeException would not be thrown first.

The posted ciphertext has a leading 0 byte and is therefore 65 bytes in size:

Base64: AJiltxqa1/8HU20XZlKJsJvclQ8PyQetpWdbCOpbqrXVg0q/v4x5tXLxbzGKbO5InvKkib7tDQp+9BU0SYbZLv0=
Hex:    0098a5b71a9ad7ff07536d17665289b09bdc950f0fc907ada5675b08ea5baab5d5834abfbf8c79b572f16f318a6cee489ef2a489beed0d0a7ef415344986d92efd

If you try to decrypt this ciphertext on the Java side, you will get the posted error: IllegalBlockSizeException: Data must not be longer than 64 bytes.

Why does the C# code produce a too long ciphertext? This is because of the modulus, which also has a leading 0 byte and therefore a length of 65 bytes:

Base64: AJ+L/dVL9jnRX6IM87H8x2fR24t6wpzBDV7bcgPWblegR0LNK91z/OSX+lSLUgHSKJ9to/Eo8OMsREpNoJlEzI0=
Hex:    009f8bfdd54bf639d15fa20cf3b1fcc767d1db8b7ac29cc10d5edb7203d66e57a04742cd2bdd73fce497fa548b5201d2289f6da3f128f0e32c444a4da09944cc8d

The modulus was derived with BigInteger.toByteArray() (see this question, Update section), which returns the two's-complement representation and places a leading 0 byte in front if the frontmost byte has a value larger than 0x7f.

The leading 0 byte in the modulus results in a ciphertext generated by the C# code, which also has a leading 0 byte and thus an invalid length of 65 bytes. This does not make much sense and might be a bug.

To solve the problem the 0 byte in the modulus should be removed for the C# code, resulting in the following Base64 encoded modulus (which will produce 64 bytes ciphertexts):

n4v91Uv2OdFfogzzsfzHZ9Hbi3rCnMENXttyA9ZuV6BHQs0r3XP85Jf6VItSAdIon22j8Sjw4yxESk2gmUTMjQ==

Alternatively the 0 byte in the ciphertext can be removed, resulting in the following ciphertext (Base64 encoded):

mKW3GprX/wdTbRdmUomwm9yVDw/JB62lZ1sI6luqtdWDSr+/jHm1cvFvMYps7kie8qSJvu0NCn70FTRJhtku/Q==

which can now be successfully decrypted by the Java code to the plaintext (if a consistent padding is applied, see Michael Fehr's answer):

Davood

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.