Каковы различия между C # и Java (Android) при шифровании с использованием RSA с заполнением PKCS1? - PullRequest
0 голосов
/ 03 сентября 2018

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

Это код C # , который отлично работает:

static void Main(string[] args)
    {
        var plainData = "plain_text";
        RSA publicKeyEncryptor = getRSAPublic(@"<public_key>");
        var plainBytes = Encoding.ASCII.GetBytes(plainData);
        string encryptedPayload = System.Convert.ToBase64String(publicKeyEncryptor.Encrypt(plainBytes, RSAEncryptionPadding.Pkcs1));
        Console.WriteLine(encryptedPayload);
    }

public static RSA getRSAPublic(string publicKey)
    {
        string publicKeyPem = $"-----BEGIN PUBLIC KEY-----\r\n{ publicKey }\r\n-----END PUBLIC KEY-----\r\n";
        var pemReader = new PemReader(new StringReader(publicKeyPem));
        AsymmetricKeyParameter keyPairRaw = (AsymmetricKeyParameter)pemReader.ReadObject();
        RSAParameters rsaParams = DotNetUtilities.ToRSAParameters((RsaKeyParameters)keyPairRaw);
        RSA rsaObj = System.Security.Cryptography.RSA.Create();
        rsaObj.ImportParameters(rsaParams);
        return rsaObj;
    }

Когда я пытаюсь преобразовать его в Java (Android), это код, который я придумал, но он не генерирует действительный вывод:

public static void main(String args[]) {
    String stringToEncrypt = "plain_text";
    String publicKey = "<public_key>";
    System.out.println(encrypt(stringToEncrypt, publicKey))
}

public String encrypt(String plain, String publicKey) {
    try {
        byte[] keyBytes = Base64.decode(publicKey, Base64.DEFAULT);
        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        PublicKey rsaPublicKey = KeyFactory.getInstance("RSA").generatePublic(spec);
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, rsaPublicKey);
        byte[] plainTextBytes = plain.getBytes(Charset.forName("US-ASCII"));
        byte[] encryptedBytes = cipher.doFinal(plainTextBytes);
        return Base64.encodeToString(encryptedBytes, Base64.NO_WRAP));
    } catch (Exception e) {
        e.printStackTrace();
    }
    return "";
}

Что может быть другим?

Спасибо!

Ответы [ 2 ]

0 голосов
/ 04 сентября 2018

Оба кода верны. Вы можете зашифровать данные таким же образом с версией Java и версией C #. Если один из них работает, а другой не работает, возможно, вы используете неправильный открытый ключ (ошибка копирования / вставки, некоторые другие байты и т. Д.)

0 голосов
/ 03 сентября 2018

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

RFC 8017, раздел 7.2.1 подробно объясняет, что происходит. В частности, шаг 2а говорит:

Генерация строки октетов PS длиной k - mLen - 3 состоящий из псевдослучайно сгенерированных ненулевых октетов. Длина PS будет не менее восьми октетов.

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

...