0

I need implement login to .NET Soap Web Service. This Web Service has method

 AuthenticateUser(username, password)

and password should be encrypted with RSA public key. Below what I am trying to do:

 public static final String PUBLIC = "q/9CujExqL6rsMMO22WWIotoXDCw5KEmGQJqL9UJEfoErwZ9ZCm3OwMTSlAMSfoXEMA04Y1rhfYC3MtU/7dYEoREfsvOPGDBWanTKyMzv2otCfiURyQoghEdkhv3ipQQaaErT7lfBKobJsdqJlvxo4PCOUas2Z6YpoMYgthzTiM=";
    public static final String EXPONENT = "AQAB";

    public static PublicKey getPublicKey() throws Exception{
        byte[] modulusBytes = Base64.decode(PUBLIC, 0);
        byte[] exponentBytes = Base64.decode(EXPONENT,    0);

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

        RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        return kf.generatePublic(spec);
    }

    public static byte[] encrypt(Key publicKey, String s) throws Exception{
        byte[] byteData = s.getBytes("UTF-8");
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); 
        cipher.init(Cipher.ENCRYPT_MODE, publicKey); 
        byte[] encryptedData = cipher.doFinal(byteData);
        return encryptedData;
    }

    public static String arrayAsString (byte [] array){
        String p = "";
        for (int i = 0; i < array.length; i++) {
            p +=  unsignedToBytes(array[i]);
            if (i < array.length - 1)
                p+= ",";
        }
        return p;
    }

    public static int unsignedToBytes(byte b) {
        return b & 0xFF;
    }

   public static void main(String[] args){
        PublicKey publicKey = getPublicKey();
        byte [] encrypted = encode(publicKey, "passwordHere");
        String pass = arrayAsString(encrypted);
        webservice.AuthenticateUser("testAdmin", pass); 
   }

I also have .NET code from Web Service side

    private static string publicKey = "<RSAKeyValue><Modulus>q/9CujExqL6rsMMO22WWIotoXDCw5KEmGQJqL9UJEfoErwZ9ZCm3OwMTSlAMSfoXEMA04Y1rhfYC3MtU/7dYEoREfsvOPGDBWanTKyMzv2otCfiURyQoghEdkhv3ipQQaaErT7lfBKobJsdqJlvxo4PCOUas2Z6YpoMYgthzTiM=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
    private static UnicodeEncoding _encoder = new UnicodeEncoding();

    public static string Encrypt(string data)
    {
        var rsa = new RSACryptoServiceProvider();
        rsa.FromXmlString(publicKey);
        var dataToEncrypt = _encoder.GetBytes(data);
        var encryptedByteArray = rsa.Encrypt(dataToEncrypt, false).ToArray();
        var length = encryptedByteArray.Count();
        var item = 0;
        var sb = new StringBuilder();
        foreach (var x in encryptedByteArray)
        {
            item++;
            sb.Append(x);

            if (item < length)
                sb.Append(",");
        }

        return sb.ToString();
    }



    public static string Decrypt(string data)
    {
        var rsa = new RSACryptoServiceProvider();
        var dataArray = data.Split(new char[] { ',' });
        byte[] dataByte = new byte[dataArray.Length];
        for (int i = 0; i < dataArray.Length; i++)
        {
            dataByte[i] = Convert.ToByte(dataArray[i]);
        }

        rsa.FromXmlString(privateKey);
        var decryptedByte = rsa.Decrypt(dataByte, false);
        return _encoder.GetString(decryptedByte);
    }

Is somebody have any idea what I am doing wrong? Why Web Service always returns me AuthenticateUserResponse{AuthenticateUserResult=false; }

2
  • Have you tried debugging your webservice? Is the output of Decrypt on the service side the same as the data that was encrypted on the client side? This aside, I think the real problem here is that you're rolling your own crypto protocol. My suggestion would be to have the webservice accessible only via SSL, which should mitigate insecurities in the code you're using now (like the fact that there's no replay protection). Commented Apr 19, 2014 at 9:11
  • Thanks for reply. Unfortunately I do not have access to webservice side, because this is 3rd party webservice, I can't check output and can't change security. What are you mean "you're rolling your own crypto protocol"? Commented Apr 21, 2014 at 4:53

1 Answer 1

1

I think the problem here is may be to do with text encoding, rather than the encryption/decryption process itself. On the Java side, you're encrypting the UTF-8 encoded password, whereas on the .NET side, it's using UnicodeEncoding which is UTF-16. Try using UTF-16 on the Java side before encryption instead.

Sign up to request clarification or add additional context in comments.

3 Comments

Tried, still doesn't work. I think there are two things and I may be messed up. First - java byte signed, .NET byte unsigned. I do convertion - unsignedToBytes, but maybe I do it in wrong place? Second - byte array endian. As I understood java uses BigEndian, .NET uses little endian. That means in byte array case this is just reverted array, I tried to revert encryption result, but it also doesn't work. Thanks.
@GeorgyGobozov I think it's still an encoding issue - the default UTF-16 encoding in Java adds a byte-order-mark, which the .NET UnicodeEncoding isn't expecting and corrupts the output. You need to use UTF-16LE as the encoding in Java. I have been able to successfully encode a string in Java and decode in .NET with this encoding used to convert the password to a byte array in Java.
that's what it is! I just changed UTF-8 on UTF-16LE and it works! Thanks for help, appreciate it!

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.