RSA-шифрование с заданным открытым ключом (на Java) - PullRequest
30 голосов
/ 26 апреля 2011

Я ищу пример Java, как сделать шифрование RSA с заданным открытым ключом (у меня он в формате base64, кажется, его длина 1024 бит).

Нижемой код, но у меня есть исключение InvalidKeySpec.

String publicKey = "AJOnAeTfeU4K+do5QdBM2BQUhfrRI2rYf/Gk4a3jZJB2ewekgq2VgLNislBdql/glA39w0NjXZyTg0mW917JdUlHqKoQ9765pJc4aTjvX+3IxdFhteyO2jE3vKX1GgA3i3n6+sMBAJiT3ax57i68mbT+KAeP1AX9199aj2W4JZeP";
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] res = new Base64Encoder().decode(publicKey.getBytes());
X509EncodedKeySpec KeySpec = new X509EncodedKeySpec(res);
RSAPublicKey pubKey = (RSAPublicKey)keyFactory.generatePublic(KeySpec);

// here the exception occurs..

Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] cipherData = cipher.doFinal(input.getBytes());
return cipherData;

Пожалуйста, дайте мне образец,

Ответы [ 4 ]

41 голосов
/ 06 ноября 2011

Вот как мне удается зашифровать строку только с открытым ключом RSA.

Сначала сохраните открытый ключ в формате PEM под именем pubkey.pem

-----BEGIN PUBLIC KEY-----
AJOnAeTfeU4K+do5QdBM2BQUhfrRI2rYf/Gk4...
-----END PUBLIC KEY-----

Найдитемодуль открытого ключа RSA

$ openssl rsa -pubin -in pubkey.pem -modulus -noout
Modulus=F56D...

Найдите экспонент открытого ключа RSA

$ openssl rsa -pubin -in pubkey.pem -text -noout
...
Exponent: 65537 (0x10001)

Затем вставьте их в следующий код.

BigInteger modulus = new BigInteger("F56D...", 16);
BigInteger pubExp = new BigInteger("010001", 16);

KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(modulus, pubExp);
RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(pubKeySpec);

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

byte[] cipherData = cipher.doFinal(text.getBytes());
14 голосов
/ 26 апреля 2011

Ваш "ключ" не является действительным открытым ключом. Это строка Base64, которая при декодировании выдает последовательность из 129 байтов, первый из которых 0x00, а затем 0x93. Это недопустимый формат для открытого ключа RSA, но он подозрительно выглядит как кодирование со знаком с прямым порядком байтов 1024-битного целого числа (т. Е. Тип кодирования, возвращаемый BigInteger.toByteArray() и используемый в значениях "INTEGER" ASN.1) ). Открытый ключ RSA номинально состоит из двух целых чисел, одно из которых является модулем , а другое - открытым показателем . Типичный модуль RSA имеет длину 1024 бита, поэтому есть вероятность, что у вас здесь есть модуль. Вам все еще нужен открытый показатель для завершения ключа.

X509EncodedKeySpec ожидает кодирования DER структуры ASN.1, которая идентифицирует алгоритм как RSA, и содержит вложенную кодированную структуру, которая сама содержит два целых числа для открытого ключа RSA. Сборка такой структуры вручную может оказаться сложной (это выполнимо, но требует некоторого глубокого понимания ASN.1). Более простой способ - использовать RSAPublicKeySpec:

String modulusBase64 = "..."; // your Base64 string here
BigInteger modulus = new BigInteger(1,
        new Base64Encoder.decode(modulusBase64.getBytes("UTF-8")));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKeySpec ks = new RSAPublicKeySpec(modulus, pubExp);
RSAPublicKey pubKey = (RSAPublicKey)keyFactory.generatePublic(KeySpec);

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

Примечание: String.getBytes() использует кодировку платформы по умолчанию, которая не всегда одинакова. Если вы настаиваете на преобразовании строки в последовательность байтов, вам следует использовать явное имя кодировки, например "UTF-8", в противном случае вы можете столкнуться с проблемами, если ваш код когда-либо будет работать, например, в русской или китайской системе. Кроме того, я не знаю, откуда взялся ваш класс Base64Encoder (он не является частью стандартного API Java), но есть вероятность, что он также может работать непосредственно над String или StringReader, делая шаг преобразования нет необходимости.

0 голосов
/ 26 апреля 2011

Ваш открытый ключ не похож на кодированное Base64 1024-битное значение.Для 1024-битного значения потребуется 172 символа (последний - заполнитель =), и здесь у нас есть 175 символов.

Для теста замените последние четыре символа в вашей строкес одиночным = и проверьте, устраняет ли это исключение.Это не решит проблему, но может указывать правильное направление.

0 голосов
/ 26 апреля 2011

Ваш открытый ключ действительно закодирован X509? Если нет, то должен помочь незашифрованный Keyspec.

...