Перевод С# RSACryptoServiceProvider в JAVA-код

Мне был предоставлен этот код С#, написанный командой веб-службы, которая предоставляет некоторые веб-службы, которые я планирую использовать. Мой пароль должен быть зашифрован этим кодом, чтобы веб-служба знала, как расшифровать его на своем конце.

using(RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
    rsa.FromXmlString(publicKey);
    byte[] plainBytes = Encoding.Unicode.GetBytes(clearText);
    byte[] encryptedBytes = rsa.Encrypt(plainBytes, false);
    return Convert.ToBase64String(encryptedBytes);
}

Я использую Java для использования этого веб-сервиса, и прямо сейчас у меня возникла проблема с переводом кода #C на Java-код, потому что этот веб-сервис не может дешифровать мой пароль должным образом.

Здесь моя текущая неудачная попытка: -

// my clear text password
String clearTextPassword = "XXXXX";

// these values are provided by the web service team
String modulusString = "...";
String publicExponentString = "...";

BigInteger modulus = new BigInteger(1, Base64.decodeBase64(modulusString.getBytes("UTF-8")));
BigInteger publicExponent = new BigInteger(1, Base64.decodeBase64(publicExponentString.getBytes("UTF-8")));

KeyFactory keyFactory = KeyFactory.getInstance("RSA");

RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(modulus, publicExponent);
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);

Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);

String encodedEncryptedPassword = new String(Base64.encodeBase64(cipher.doFinal(clearTextPassword.getBytes("UTF-8"))));

Что я сделал неправильно? Большое спасибо.

2013-08-07 - ОБНОВЛЕНИЕ

Я читал этот веб-сайт, и я понял, что значение модуля и значение публичного показателя не находятся в Hex. Итак, я немного изменил свой код и попытался с помощью RSA/ECB/PKCS1PADDING, как упоминалось в @Dev.

// my clear text password
String clearTextPassword = "XXXXX";

// these are the actual values I get from the web service team
String modulusString = "hm2oRCtP6usJKYpq7o1K20uUuL11j5xRrbV4FCQhn/JeXLT21laKK9901P69YUS3bLo64x8G1PkCfRtjbbZCIaa1Ci/BCQX8nF2kZVfrPyzcmeAkq4wsDthuZ+jPInknzUI3TQPAzdj6gim97E731i6WP0MHFqW6ODeQ6Dsp8pc=";
String publicExponentString = "AQAB";

Base64 base64Encoder = new Base64();

String modulusHex = new String(Hex.encodeHex(modulusString.getBytes("UTF-8")));
String publicExponentHex = new String(Hex.encodeHex(publicExponentString.getBytes("UTF-8")));

BigInteger modulus = new BigInteger(modulusHex, 16);
BigInteger publicExponent = new BigInteger(publicExponentHex);

KeyFactory keyFactory = KeyFactory.getInstance("RSA");

RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(modulus, publicExponent);
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);

Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);

String encodedEncryptedPassword = new String(base64Encoder.encode(cipher.doFinal(clearTextPassword.getBytes("UTF-8"))));

Когда я нахожусь в веб-сервисе, я получаю эту ошибку: "Расширяемые данные превышают максимальный для этого модуля 128 байт". Кажется, что текстовый пароль еще не зашифрован правильно.

Любая помощь или предложение приветствуются. Спасибо.

2013-08-09 - РЕШЕНИЕ

Я опубликовал свое окончательное рабочее решение ниже.

Ответ 1

Найден решение.

String modulusString = "hm2oRCtP6usJKYpq7o1K20uUuL11j5xRrbV4FCQhn/JeXLT21laKK9901P69YUS3bLo64x8G1PkCfRtjbbZCIaa1Ci/BCQX8nF2kZVfrPyzcmeAkq4wsDthuZ+jPInknzUI3TQPAzdj6gim97E731i6WP0MHFqW6ODeQ6Dsp8pc=";
String publicExponentString = "AQAB";

byte[] modulusBytes = Base64.decodeBase64(modulusString);
byte[] exponentBytes = Base64.decodeBase64(publicExponentString);
BigInteger modulus = new BigInteger(1, modulusBytes);
BigInteger publicExponent = new BigInteger(1, exponentBytes);

RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, publicExponent);
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 = clearTextPassword.getBytes("UTF-16LE");
byte[] cipherData = cipher.doFinal(plainBytes);
String encryptedStringBase64 = Base64.encodeBase64String(cipherData);

Ответ 2

В соответствии с документами MSDN на RSACryptoServiceProvider.Encrypt, когда второй аргумент false, шифр использует дополнение PKCS # 1 v1.5. Так что с самого начала ваша спецификация шифрования неверна.

Попробуйте RSA/ECB/PKCS1PADDING вместо этого.

Вы конвертируете свой ключевой материал во второй пример кода, и вы его испортили, что в конечном итоге заставляет ваш шифр думать, что у вас есть больше ключевых материалов, чем у вас на самом деле, и делает ваше сообщение слишком длинным (что вызывает вашу ошибку), поскольку так же как и непонятный для шифрования дешифрования на другом конце. Преобразуйте непосредственно в байтовые массивы и передайте их в BigInteger.

String modulusString = "...";
String publicExponentString = "...";

byte[] mod = Base64.decodeBase64(modulusString);
byte[] e = Base64.decodeBase64(publicExponentString);

BigInteger modulus = new BigInteger(1, mod);
BigInteger publicExponent = new BigInteger(1, e);