Данные, зашифрованные в C #, имеют длину на 1 байт больше, чтобы их можно было расшифровать в Java.

У меня есть сервер, написанный на Java, который перед отправкой клиенту преобразует свой ключ RSA в формат XML, используемый .NET:

public String getPublicKeyXML() {
    try {
        KeyFactory factory = KeyFactory.getInstance("RSA");
        RSAPublicKeySpec publicKey = factory.getKeySpec(this.keyPair.getPublic(), RSAPublicKeySpec.class);

        byte[] modulus = publicKey.getModulus().toByteArray();
        byte[] exponent = publicKey.getPublicExponent().toByteArray();

        String modulusStr = Base64.encodeBytes(modulus);
        String exponentStr = Base64.encodeBytes(exponent);

        String format = 
            "<RSAKeyValue>" +
                "<Modulus>%s</Modulus>" +
                "<Exponent>%s</Exponent>" +
            "</RSAKeyValue>";

        return String.format(format, modulusStr, exponentStr);
    } catch (Exception e) {
        this.server.logException(e);
        return "";
    }
}

Клиент, написанный на C #, затем загружает ключ и использует его для шифрования 256-битного ключа AES:

    public static byte[] encrypt(string xmlKey, byte[] bytes)
    {
        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
        rsa.FromXmlString(xmlKey);
        byte[] cipherBytes = rsa.Encrypt(bytes, false);
        rsa.Clear();
        return cipherBytes;
    }

Затем сервер должен расшифровать ключ AES, используя свой закрытый ключ RSA:

public byte[] decrypt(byte[] data) {
    try {
        PrivateKey privateKey = this.keyPair.getPrivate();
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] cipherData = cipher.doFinal(data);
        return cipherData;
    } catch (Exception e) {
        this.server.logException(e);
        return new byte[0];
    }
}

Однако сервер выходит из строя с сообщением об ошибке «Данные не должны быть длиннее 384 байта». Посмотрев на данные, которые нужно расшифровать, я заметил, что это 385 байт. Я попытался увеличить длину ключа RSA, и теперь сервер сообщает мне, что данные не должны быть длиннее 512 байт, в то время как зашифрованные данные от клиента составляют 513 байт. Почему зашифрованные данные всегда на один байт длиннее ожидаемого?

РЕДАКТИРОВАТЬ:

Вот пример ключа в формате XML, который передается с сервера клиенту:

<RSAKeyValue><Modulus>ANsMd2dCF6RsD5v5qjlHEjHm0VWD99gSYHP+pvyU8OgNL9xM5+o+yMAxWISOwMii9vJk1IzYGf18Fj2sMb5BsInlG2boZHb6KHh7v8ObPa4MuwB/U63i8AVU3N/JTugaPH0TKvo1WNUooXEHT23nOk+vh1QipzgKQYGl68qU35vKmpNAa79l1spXA66LckTWal4art9T08Rxgn9cMWujlF+wh9EQKQoxxgj4gCoXWRDTFYjRo/Mp5xDPwNjloTs/vFCPLvY7oI+lVrHhrPyz1R473ZuEhZm+rSeGBcY9I8vhg0AIixN7KYBLhrIecmqoNZHi6LohjD2F9zhdLaTU0IIU8eeKpbEZ5eB1kYngMONBq3A/IoG0Qa/7EcSAMMspBEObffK9kCNzvnbFg5wLuy8EHNaK3nmnuTppgCwCyNqZyHeAbZaUBjNguLhHtqkHFiPJ063Xesj9UbSsCmlBliGTDXWfeJANnjGP6D3R+uLXVy9SZe+cY92JW3eZA2k//w==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>

Я подтвердил, что отправленные данные совпадают с полученными.

Удаление последнего байта приводит к возникновению исключения BadPaddingException. Я тоже пробовал сбивать первый байт, с тем же результатом.


person Joseph    schedule 30.07.2012    source источник
comment
ммм. вы можете опубликовать пример xml?   -  person Markus Mikkolainen    schedule 31.07.2012
comment
попробуйте отбросить последний байт зашифрованного текста и посмотреть, что произойдет - это может быть нулевой терминатор или что-то в этом роде.   -  person mfrankli    schedule 31.07.2012
comment
Как вы передали сами данные?   -  person Jon Skeet    schedule 31.07.2012
comment
И, возможно, пример данных. Вы уверены, что клиент создает материал, используя тот же самый шифр, что и сервер? т.е. обивка и все? также проверьте длину данных непосредственно перед шифрованием, чтобы убедиться, что она правильная.   -  person Markus Mikkolainen    schedule 31.07.2012
comment
Вы пробовали другой инструмент для сравнения? Итак, вы знаете, чего ожидать.   -  person keiki    schedule 31.07.2012
comment
Я бы сделал, как говорит mfrankli, если это не удастся, сделайте так, как говорит MarkusMikkolainen, создав один и тот же зашифрованный текст как на Java, так и на C #, если это возможно, и сравните их.   -  person flindeberg    schedule 31.07.2012
comment
Шифрование одного и того же сервера данных и клиентской стороны приводит к разному зашифрованному тексту. Как я могу заставить обе стороны использовать один и тот же точный шифр?   -  person Joseph    schedule 31.07.2012
comment
Ваш модуль имеет 385 байтов, а показатель степени - 3 байта (декодирование данных base-64). Если я затем отрежу последний байт декодированной базы 64 модуля и повторно закодирую его по базе 64, это будет 384 байта, а зашифрованные данные - 384 байта. Итак, я думаю, возникает вопрос: почему getPublicKeyXML генерирует слишком большой модуль?   -  person Jesse C. Slicer    schedule 31.07.2012
comment
@Jesse Хорошая находка. Я начинаю думать, что это как-то связано с тем, как модуль BigInteger преобразуется в массив байтов, поскольку я убедился, что кодировка base64 верна.   -  person Joseph    schedule 31.07.2012


Ответы (2)


Я нашел проблему. Функция BigInteger toByteArray () по какой-то причине включала начальный ноль. Я просто удалил ведущие нули из массива, и теперь он работает как шарм!

person Joseph    schedule 31.07.2012
comment
Спасибо! Я бился головой об стену. Я все еще не могу заставить его работать, но, по крайней мере, проблема не в этом. - person Wheezil; 11.02.2019

Это не решит проблему (я безрезультатно тестировал), но хочу обратить ваше внимание на то, что RSACryptoServiceProvider реализует IDisposable и поэтому должен быть должным образом утилизирован после завершения. Ваш метод C # encrypt можно написать немного лучше (и более кратко!) Как таковой:

    public static byte[] encrypt(string xmlKey, byte[] bytes)
    {
        using (var rsa = new RSACryptoServiceProvider())
        {
            rsa.FromXmlString(xmlKey);
            return rsa.Encrypt(bytes, false);
        }
    }
person Jesse C. Slicer    schedule 30.07.2012
comment
Не могли бы проголосовать против, пожалуйста, объясните причину своего отрицательного голоса? Может быть, мой комментарий к вопросу будет включен? - person Jesse C. Slicer; 31.07.2012
comment
Я проголосовал против, потому что вы опубликовали ответ, который не был ответом. Я согласен с комментариями стиля, но они должны быть в комментарии. - person Nick Garvey; 01.08.2012
comment
Спасибо за комментарий. Я бы с удовольствием втиснул этот пример в комментарий, но здесь мало что может уместиться. - person Jesse C. Slicer; 01.08.2012