Search code examples
androidasp.netwcfrsaencryption-asymmetric

The data to be decrypted exceeds the maximum for this modulus of 128 bytes while encrypting data in Android and Decrypting in WCF Web Service


I am an Android Developer. The task at hand is to encrypt data in my Android Application using the RSA algorithm via the Public Key modulus and Exponent provided to me and then send it over the network via JSON String to a .Net Web Service. This Web Service will decrypt the data and further use it.

The code that I use to encrypt the data is as follows:

public String RSAEncrypt (final String plain) throws Exception 
{
    try{
        String strModulus = "tr82UfeGetV7yBKcOPjFTWs7pHqqr/5YKKWMUZ/HG4HnCmWrZsOhuR1FBnMZ/g2YiosoSlu0zd7Ukz9lX7wv2RLfWXfMvZYGpAAvfYWwzbyQ2i1q+tKE/thgKNscoSRellDD+uJcYn1H4hnaudVyYJH9miVhOKhKlExMzw8an6U=";
        String strExponent = "AQAB";
        byte[] modulusBytes = strModulus.getBytes();
        byte[] exponentBytes = strExponent.getBytes();
        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);

        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);

        byte[] plainBytes = new String("Manchester United").getBytes("UTF-8");
        byte[] cipherData = cipher.doFinal(plainBytes);
        encryptedString = Base64.encodeToString(cipherData, Base64.NO_PADDING);
    }
    catch(Exception e){
        Log.e("Error", e.toString());
    }

    return encryptedString;
}

The above code gives me a string that I pass to the .Net Web Service. But for some reason the Web Service is not being able to decrypt this data appropriately and presents the error: The data to be decrypted exceeds the maximum for this modulus of 128 bytes

I tried to help out but I cannot understand what is happening.

I made the following alterations in my code: Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); instead of Cipher cipher = Cipher.getInstance("RSA");

Also provided 'Base64.NO_PADDING' while encrypting the data.

The ASP.Net code is as follows:

            const int PROVIDER_RSA_FULL = 1;
            const string CONTAINER_NAME = "Tracker";

            CspParameters cspParams;
            cspParams = new CspParameters(PROVIDER_RSA_FULL);
            cspParams.KeyContainerName = CONTAINER_NAME;
            RSACryptoServiceProvider rsa1 = new RSACryptoServiceProvider(cspParams);
            rsa1.FromXmlString("<RSAKeyValue><Modulus>tr82UfeGetV7yBKcOPjFTWs7pHqqr/5YKKWMUZ/HG4HnCmWrZsOhuR1FBnMZ/g2YiosoSlu0zd7Ukz9lX7wv2RLfWXfMvZYGpAAvfYWwzbyQ2i1q+tKE/thgKNscoSRellDD+uJcYn1H4hnaudVyYJH9miVhOKhKlExMzw8an6U=</Modulus><Exponent>AQAB</Exponent><P>6e0nv7EBFBugtpoB+ozpg1J4js8E+DVyWCuBsERBPzqu4H7Z/oeLIRSC8Gi5GZgrCpBf3EvyIluM7rzaIfNThQ==</P><Q>x/29X9ns1WcXC42IJjLDjscz5ygdVh79dm8B2tQVbqwyhDsQ6OIOQdu5+eHf4hUMoTrM9KkS2F6FGlLXuaOFoQ==</Q><DP>kTS2LMaJ/dpce5zDx6w6s1q5HSSiWBSNIu/2s9zah448yXvUg6vNkD40PVk0NRAA/7C44H2AExWzOOqfmN17JQ==</DP><DQ>xtAx9drQPWnpl/uQUOEAVa0kpPTVDStrr9Q1FNTnpYkcAyYw7kLkB4anAIoSpk9kqdeprsNxz5VPXtbiTFMKYQ==</DQ><InverseQ>O0594NMjnjSp+/NAa1kQxoQNzn1qqq+p1Zb+kT3/jRc/0d7ZnqSSpxFMXfxx3yZkNAOPDOdbckPQbRZ13RKBHg==</InverseQ><D>bjVEagwvkrZaTt9CTW1hd3362weLFlX6DpE/3R3RcrpVfkSwKGpEhqGrNeeGPlsuqiaf5rAFir4eTqrF1QVliKsU4XE0RyzP5lHGc7dlX4DOHMjs2R9nNWv8QOTPoaRuLrLGorqBXlw/jQPxFI6gQzkIIjzuf//lDVnFam3dw4E=</D></RSAKeyValue>");

            string data2Decrypt = "SeuUUjdSbFQlcwaCFVZ9fN0t3aXpItXU4+pkuztVgky77SBokBATKj+56+irtCfT1lSGRZbbzgQTd8zpcjPsT6J+7AyBwRwuv418JyKINNxPsDVFKfupViu8MOoxWzjmjZE5p54AjByA6dzGSR9UogFHhFSMZWJ5OELwZFSz5wFHyMaeIm1UnEiRDDjPTY/aIuh56WnZPXUmP3D54bAwDXPFtY0JjjiyxZetnA";

            byte[] encyrptedBytes = Convert.FromBase64String(data2Decrypt);

            byte[] plain = rsa1.Decrypt(encyrptedBytes, false);
            string decryptedString = System.Text.Encoding.UTF8.GetString(plain);

The error occurs here: byte[] plain = rsa1.Decrypt(encyrptedBytes, false);

Decrypt is a function of the RSACryptoProvider class in .Net itself.

I have checked a few links like: The data to be decrypted exceeds the maximum for this modulus of 128 bytes. RSA DECRYPTION c#

The data to be decrypted exceeds the maximum for this modulus of 128 bytes

However, I am not being able to implement the suggestions. Any help will be appreciated. Thank you!


Solution

  • In your Java code, you have the modulus and exponent encoded as Base64 strings, but you are converting those to byte arrays by decoding using the string encoding (e.g. UTF-8) which gives you bogus byte values. This is giving you an entirely different RSA key than you expect:

    Sun RSA public key, 1375 bits modulus: 750169282846494125860884712723073313436806987678989257696854519163422196468501094334772708285571263987960096312310946772203386096382092764988823316042225715695209682181694351362408270131738979229545667503402617569939108631330090897309670319383704572983438399762295114985980168234669536869729771611691862551491497864929321166916789165923322527018195770714618713254889722551163557798154618552019060264304749542004029 public exponent: 1095844162

    Your ciphertext is in modulus 1375, not 1024, so the error string is correct. The Java-produced ciphertext of modulus 1375 (172 bytes) exceeds the modulus of the .NET code, which is still 1024 (limited to 128 bytes.)

    If instead, you Base64-decode those strings like this, for example:

    byte[] modulusBytes = DatatypeConverter.parseBase64Binary("tr82UfeGetV7yBKcOPjFTWs7pHqqr/5YKKWMUZ/HG4HnCmWrZsOhuR1FBnMZ/g2YiosoSlu0zd7Ukz9lX7wv2RLfWXfMvZYGpAAvfYWwzbyQ2i1q+tKE/thgKNscoSRellDD+uJcYn1H4hnaudVyYJH9miVhOKhKlExMzw8an6U=");
    byte[] exponentBytes = DatatypeConverter.parseBase64Binary("AQAB");
    

    then you will get the key that you wanted:

    Sun RSA public key, 1024 bits modulus: 128329253200625851747417306407495181460638722403079978934516135424027698446198581565013203888628021918042144433585511434660221274570695228957705446643239452347022609986771847076542293947545868471690675464836702700925020694185362910844461481736938124375366838112503820421836105957170854998527632432367452987301 public exponent: 65537

    and your Java code will product this result:

    "P2ENQbBu3rpBcrfnzbOj6MLCGBABclQnVY6QpHJ54uXZnKSd2Ll9fJ6g+avsvbWib9SNKsL9Yx+PeRdC20W6BXfblSnXMAbZxJ2VQCQho44rR+k6B9HrB2i0zl9pdLSRxm9k0poQVG1I/yplmK1H9TGqlZp1oYnbzWrS8JiRd5w="

    and your .NET code will decrypt correctly to "Manchester United".

    EDIT:

    Base64.decode should match the output of DatatypeConverter.parseBase64Binary. The output I get with this loop:

    for (int i = 0; i < modulusBytes.length; i++)
    {
        System.out.print(" ");
        System.out.print(modulusBytes[i]);
    }
    System.out.println();
    

    is this:

     -74 -65 54 81 -9 -122 122 -43 123 -56 18 -100 56 -8 -59 77 107 59 -92 122 -86 -81 -2 88 40 -91 -116 81 -97 -57 27 -127 -25 10 101 -85 102 -61 -95 -71 29 69 6 115 25 -2 13 -104 -118 -117 40 74 91 -76 -51 -34 -44 -109 63 101 95 -68 47 -39 18 -33 89 119 -52 -67 -106 6 -92 0 47 125 -123 -80 -51 -68 -112 -38 45 106 -6 -46 -124 -2 -40 96 40 -37 28 -95 36 94 -106 80 -61 -6 -30 92 98 125 71 -30 25 -38 -71 -43 114 96 -111 -3 -102 37 97 56 -88 74 -108 76 76 -49 15 26 -97 -91
    

    Try Base64-decoding the string on the .NET platform, and see if it matches the decode result on the Java platform.