проверка подписи RSA от C# в java - PullRequest
2 голосов
/ 23 апреля 2020

Я пытаюсь сгенерировать подпись RSA SHA512 на своем серверном приложении (написано в C#) и проверить эту подпись на клиентском приложении (написано в Java). Перед обменом сигнатурами сервер генерирует пару publi c - и секретный ключ и делится ключом publi c с клиентским приложением, передавая ему значения модуля и экспоненты, которые были сгенерированы. Клиентское приложение сохраняет значения для последующего использования, когда необходимо проверить подпись.

Сервер генерирует 128-байтовый модуль и 128-байтовую подпись. Я просто использую байтовый массив [0x00, 0x01, 0x02, 0x03] в качестве исходных данных для подписи во время тестирования.

По какой-то причине мое приложение Java всегда терпит неудачу при проверке подпись.

Мой C# код (создает подпись):

RSACryptoServiceProvider crypto = new RSACryptoServiceProvider();
crypto.FromXmlString(this.myStoredPrivateKeyXml);

List<byte> signatureBytes = new List<byte>();
signatureBytes.Add(0x00);
signatureBytes.Add(0x01);
signatureBytes.Add(0x02);
signatureBytes.Add(0x03);

byte[] signature = crypto.SignData(signatureBytes.ToArray(), "SHA512");

Мой Java код (который получает / проверяет подпись):

byte[] expectedData = new byte[4];
expectedData[0] = 0;
expectedData[1] = 1;
expectedData[2] = 2;
expectedData[3] = 3;

byte[] exponent = getStoredExponent(); // three-byte value from server
byte[] modulus = getStoredModulus(); // 128-byte value from server

RSAPublicKeySpec spec = new RSAPublicKeySpec(new BigInteger(modulus), new BigInteger(exponent));
PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(spec);

Signature verifier = Signature.getInstance("SHA512withRSA");
verifier.initVerify(publicKey);
verifier.update(expectedData);

if(verifier.verify(signature)) {
  System.out.println("signature verified");
} else {
  System.out.println("signature failed verification"); // always ends up here :(
}

Криптообъекты на стороне C# взяты из пространства имен System.Security.Cryptography и java .security на стороне Java.

Байты передаются между приложениями через веб-сервисы и строки base64. Я просмотрел и напечатал значения самих байтовых массивов, чтобы убедиться, что значения правильны для показателя степени, модуля и сигнатуры между двумя приложениями. Есть ли причина, по которой подпись не будет совместима между двумя языками / приложениями? Может, я пропускаю какой-то параметр? Я сделал их оба RSA с SHA512, но, возможно, нужно учитывать и другие аспекты подписи?

1 Ответ

2 голосов
/ 24 апреля 2020

В представлении XML на стороне C# данные хранятся в формате без знака с прямым порядком байтов (и в кодировке Base64).

Однако, конструктор Java BigInteger(byte[] val) ожидает данные как со знаком (дополняют два) с прямым порядком байтов .

Следовательно, необходимо использовать конструктор BigInteger(int signum, byte[] magnitude), который ожидает знак в первом параметре и данные во втором параметре как беззнаковый старший порядковый номер , т.е. необходимо внести следующие изменения:

RSAPublicKeySpec spec = new RSAPublicKeySpec(new BigInteger(1, modulus), new BigInteger(1, exponent));
...