简体   繁体   中英

RSA Interoperability between C# and Java

I am working on API that will perform a certain handshake with [Java,C#] agents by giving them RSA key parameters [Exponent,Modulus,D]. I managed to make both agents encrypt and decrypt data given the parameters.

I tried to test the interoperability "when given the same parameters" between both. Java agent can seamlessly decrypt C# encrypted data but I can't get it to work the other way around " to decrypt java-encrypted data with C# "

Here is a brief code to demonstrate the problem

→ Java ←

RSAParameters.java

class RSAParameters 
{    
    public BigInteger Exponent;
    public BigInteger Modulus;
    public BigInteger P;
    public BigInteger Q;
    public BigInteger DP;
    public BigInteger DQ;
    public BigInteger InverseQ;
    public BigInteger D;

    public RSAParameters(){}

    public RSAParameters(String ExponentString,String ModulusString,String DString)
    {
        this.Exponent = new BigInteger(1, Base64.getDecoder().decode(ExponentString.trim()));
        this.Modulus  = new BigInteger(1, Base64.getDecoder().decode(ModulusString.trim()));
        this.D        = new BigInteger(1, Base64.getDecoder().decode(DString.trim()));
    }

    public RSAParameters(String ExponentString,String ModulusString)
    {
        this.Exponent = new BigInteger(1, Base64.getDecoder().decode(ExponentString.trim()));
        this.Modulus  = new BigInteger(1, Base64.getDecoder().decode(ModulusString.trim()));
    }
}

RSA.java

public class RSA 
{

    public static final RSAParameters HandshakeSharedRSAParameters = new RSAParameters(
            "AQAB",
            "vsn+4HB74ypJ4dqetNWUpKueFAb9V0Vbb1TISWklNa4d1xSmDvF3eZ8bGSciU1PvvPgPVFHh+85ArL/jLqCbMuk8Bx2+y3UJVxXPXpazzv0qPTHd3UXyKeJa/LW+wD+J1Yjy823nT7D8NYOpdt8l9agIO5Me9JiebtxLbljcLMk=",
            "en19YeNV5rbT0Gln03n8gOyeBQWnyUwCNCwemuMivKAZEGl1Y8qrhi4cW73AT/dnx88LKHuZtuzooQBhfyImASGVPXMHYVf4I+f/ZbsYe+ZByyQ/OBlxOYrQxGoDW13us9S+biMyQVQ7MA2TQBmv52e1+LyX7RIsCzxQyUuYFTE="  
    );
    public static String Encrypt(String PlainText,RSAParameters RSAParameters)  throws Exception
    {
        KeyFactory factory = KeyFactory.getInstance("RSA");
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        RSAPublicKeySpec RSAPublicKeySpec = new RSAPublicKeySpec(RSAParameters.Modulus, RSAParameters.Exponent);
        PublicKey PublicKey = factory.generatePublic(RSAPublicKeySpec);
        cipher.init(Cipher.ENCRYPT_MODE, PublicKey);        
        return Base64.getEncoder().encodeToString(cipher.doFinal(PlainText.getBytes()));
    } 
}

Main.java

public class Main
{
    public static void main(String[] args) throws Exception
    {
        String PlainTextToEncrypt = "hello android";
        String Encrypted = RSA.Encrypt(PlainTextToEncrypt,RSA.HandshakeSharedRSAParameters);        
        System.out.println("Encrypted" +":  "+Encrypted);
        //Encrypted changes every execution
        //iDIsNj4QiVWlE8ck48uV0w3tnV5D2ro+3SOMkXan2D4feU6nV5TIVqJGLvMWKvkC+duN9jJzSWTR0CAsK2O2IDx88/9/ycpL0Tk9fumEY2KOINEOXASGxjZvzZ0lCf4AeP9koUp2MHZD8agcYDLe7PLVhA+x8kkAWXMUfyvIS4E=
     }
 }

→ C# ←

RSA.cs

public class RSA
{
    public static readonly RSAParameters HandshakeSharedRSAParameters = new RSAParameters()
    {
        Exponent = Convert.FromBase64String("AQAB"),
        Modulus=Convert.FromBase64String("vsn+4HB74ypJ4dqetNWUpKueFAb9V0Vbb1TISWklNa4d1xSmDvF3eZ8bGSciU1PvvPgPVFHh+85ArL/jLqCbMuk8Bx2+y3UJVxXPXpazzv0qPTHd3UXyKeJa/LW+wD+J1Yjy823nT7D8NYOpdt8l9agIO5Me9JiebtxLbljcLMk="),
        P = Convert.FromBase64String("0l6/pEuwqlpHzjYFb3R9eOa+bQMcidn1h6qKR8DLyDPqA2eCgsBj7fvQvLnl9u6QJMzZdZg8fZP56ZP8nUGG3w=="),
        Q = Convert.FromBase64String("6Cv3YUcsnD1ub6lsqAZaEQrazHtf2HBiIboQlA5sMihThEPyL7Tsc85a8Ln9hFysje6MhNtUF6zyIpAU6NaJVw=="),
        DP = Convert.FromBase64String("zf61jf4H+mf5FDXV0LOzAaaBJWH8mgfx42zdhzGE2n/rUHYVWE9oCuugFI28X7ZvM3ncHsh5w0YZW93raVl25Q=="),
        DQ = Convert.FromBase64String("DsIsuYxSs6PcD1EPzSaKNycffXwiPZn3QvmW8DJygkW5+WBwVsQDe+EUOtU33mAdv+/4EsH2eILP6Y6LJbnthQ=="),
        InverseQ = Convert.FromBase64String("sBvjeZ0HbGT8/JfaPRe8eewHliWp/kpQNLiAGBE2CyFIB0mnkBXa+Vs52niLcMpGI1MLMSmdkDZo2/y+KIFcyg=="),
        D = Convert.FromBase64String("en19YeNV5rbT0Gln03n8gOyeBQWnyUwCNCwemuMivKAZEGl1Y8qrhi4cW73AT/dnx88LKHuZtuzooQBhfyImASGVPXMHYVf4I+f/ZbsYe+ZByyQ/OBlxOYrQxGoDW13us9S+biMyQVQ7MA2TQBmv52e1+LyX7RIsCzxQyUuYFTE=")
    };
    public static String Decrypt(String EncryptedText, RSAParameters RSAParameters)
    {
        RSACryptoServiceProvider CryptoServiceProvider = new RSACryptoServiceProvider();
        CryptoServiceProvider.ImportParameters(RSAParameters);
        return Encoding.Unicode.GetString(CryptoServiceProvider.Decrypt(Convert.FromBase64String(EncryptedText), false));
    }
}

c# demo

String AndroidEncrypted = "iDIsNj4QiVWlE8ck48uV0w3tnV5D2ro+3SOMkXan2D4feU6nV5TIVqJGLvMWKvkC+duN9jJzSWTR0CAsK2O2IDx88/9/ycpL0Tk9fumEY2KOINEOXASGxjZvzZ0lCf4AeP9koUp2MHZD8agcYDLe7PLVhA+x8kkAWXMUfyvIS4E=";
Console.WriteLine(RSA.Decrypt(AndroidEncrypted,RSA.HandshakeSharedRSAParameters));
//Expected -> hello android
//Output -> 敨汬湡牤楯�

You are forgetting about the character decoding in C#. I would always standardize on UTF-8. This is the default character set on Android but not in Windows / .NET - where it is UTF-16LE (assuming a little endian system such as Windows on Intel or ARM).

In Windows, do:

Encoding.UTF8.GetBytes(plaintext);

You're better off to use StandardCharsets.UTF_8 in Android as well, because if you'd ever use this on a system that has a different character encoding (eg Windows, with Windows-1252) then your code would suddenly fail again if you don't.

So always indicate the character encoding in eg String#getBytes(StandardCharsets.UTF_8) and new String(byte[] bytes, StandardCharsets.UTF_8) .


Note that cryptographic operation must be valid if you get any output at all for RSA. RSA PKCS#1 always validates the padding after decryption, and you'd expect that to fail with an exception if the keys or padding scheme is incorrect.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM