Шифрование закрытым ключом RSA в Java

Я пытаюсь зашифровать некоторый контент с помощью закрытого ключа RSA.

Я следую этому примеру: http://www.junkheap.net/content/public_key_encryption_java

, но преобразовав его для использования закрытых ключей, а не открытых. Следуя этому примеру, я думаю, что мне нужно сделать следующее:

  • Читать в закрытом ключе в формате DER
  • Создайте PCKS8EncodedKeySpec
  • вызовите generatePrivate () из KeyFactory, чтобы получить объект закрытого ключа
  • Используйте этот объект закрытого ключа с объектом Cipher для шифрования.

Итак, шаги:

Ключ был сгенерирован из openssl с помощью:

openssl genrsa -aes256 -out private.pem 2048

а затем был преобразован в формат DER с помощью:

openssl rsa -in private.pem -outform DER -out private.der

Я генерирую PKCS8EncodedKeySpec с помощью:

byte[] encodedKey = new byte[(int)inputKeyFile.length()];

try {
    new FileInputStream(inputKeyFile).read(encodedKey);
} catch (FileNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedKey);
return privateKeySpec;

А затем сгенерируйте объект закрытого ключа с помощью:

PrivateKey pk = null;

try {
    KeyFactory kf = KeyFactory.getInstance(RSA_METHOD);
    pk = kf.generatePrivate(privateKeySpec);
} catch (NoSuchAlgorithmException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (InvalidKeySpecException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}
return pk;

Однако по призыву:

pk = kf.generatePrivate(privateKeySpec);

Я получил:

java.security.spec.InvalidKeySpecException: Unknown key spec.
at com.sun.net.ssl.internal.ssl.JS_KeyFactory.engineGeneratePrivate(DashoA12275)
at com.sun.net.ssl.internal.ssl.JSA_RSAKeyFactory.engineGeneratePrivate(DashoA12275)
at java.security.KeyFactory.generatePrivate(KeyFactory.java:237)

Вопросы:

  • Верен ли общий подход?
  • Подходит ли PCKS8EncodedKeySpec для использования?
  • Есть какие-нибудь мысли о неверной ключевой ошибке спецификации?

person wadesworld    schedule 08.09.2009    source источник
comment
Я прошел через это и сгенерировал их с помощью Java: stackoverflow.com/questions/19640735/   -  person Hayro    schedule 27.02.2014


Ответы (5)


Прежде всего, я не понимаю, почему вы планируете использовать Cipher для шифрования с помощью закрытого ключа, а не подписывать с помощью Signature. Я не уверен, что все поставщики RSA Cipher будут использовать правильный тип блока для настройки, но попробовать стоит.

Однако, если оставить это в стороне, я думаю, что вы пытаетесь загрузить ключ нестандартного формата OpenSSL. Преобразование его в DER с помощью rsa - это, по сути, просто декодирование base-64; структура ключа не является PKCS # 8.

Вместо этого после genrsa используйте команду openssl pkcs8 для преобразования сгенерированного ключа в незашифрованный PKCS # 8, формат DER:

openssl pkcs8 -topk8 -nocrypt -in private.pem -outform der -out private.der

Это создаст незашифрованный закрытый ключ, который можно загрузить с помощью PKCS8EncodedKeySpec.

person erickson    schedule 08.09.2009
comment
Честно говоря, я не знал о подписи. Чтобы убедиться, что я понимаю его использование, я бы инициализировал объект подписи, вызвал обновление с байтами, которые я хочу подписать, а затем позывной? И тогда я могу сохранить байты, возвращенные подписью, в качестве моей цифровой подписи? - person wadesworld; 08.09.2009
comment
Привет. Кто-нибудь наконец решил проблему? У меня есть privateKey, который я не могу загрузить в Java, чтобы продолжить этап подписания. Мой privateKey - RSA, PKCS # 8 DER, и у него есть пароль. Как я могу загрузить это в Java? Исключением в моем случае является java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : DER input, Integer tag error - person BRabbit27; 10.12.2011
comment
@ BRabbit27 Чтобы загрузить закрытый ключ напрямую, он должен быть незашифрованным. Используйте команду openssl pkcs8, которую я показал выше, добавив параметр -inform der; он запросит у вас пароль. Если вы хотите сохранить свой закрытый ключ в зашифрованном виде (что я настоятельно рекомендую), вам необходимо добавить его в хранилище ключей (например, файл PKCS # 12) и получить к нему доступ через KeyStore API. в Java. - person erickson; 10.12.2011
comment
@erickson Я пробовал команду, но она показывает ошибку (я использую WinOpenSSL) ключ расшифровки ошибки. Я использовал команду openssl pkcs8 -topk8 -nocrypt -in myKey.key -inform der -outform der -out myNoCryptKey.key - person BRabbit27; 12.12.2011
comment
ОБНОВЛЕНИЕ Что должна делать опция -nocrypt? Я думаю, что нашел обходной путь, подобный этому openssl pkcs8 -inform DER -in myKey.key -outform PEM -out myKeyInPEM.key он запросил мой пароль, а затем openssl pkcs8 -topk8 -nocrypt -in myKeyInPEM -outform DER -out myKeyInDERNoCrypted.key он не спросил мой пароль, но файл результатов кажется равным myKey.key - person BRabbit27; 12.12.2011
comment
@ BRabbit27 Параметр -nocrypt означает, что выходной файл не будет зашифрован паролем. Файл кажется равным или файл равен? Вы можете вычислить хэш обоих файлов с помощью OpenSSL, верно? - person erickson; 12.12.2011
comment
@erickson кажется равным. На самом деле я вычислил хеш, и он другой. Наконец-то я смог загрузить его из java. Остались только вопросы: почему я должен переходить с DER-Encrypted на PEM на DER-NoCrypt? Должен ли я преобразовать все имеющиеся у меня ключи в DER-NoCrypt, чтобы иметь возможность загружать их из java? Большое спасибо! - person BRabbit27; 12.12.2011
comment
Я не уверен, почему вам пришлось использовать промежуточный файл PEM. Я, вероятно, не смог бы сказать вам, если бы не попробовал сам с одним из ваших ключей. Когда я попробовал этот процесс, используя свои ключи, мне не пришлось проходить этот шаг. - person erickson; 12.12.2011

Вы не можете зашифровать закрытым ключом. Если JCE позволяет вам это делать, то это случайно.

Вам нужно использовать подпись. Вот фрагмент кода для этого:

signer = Signature.getInstance("SHA1withRSA");
signer.initSign(privateKey); // PKCS#8 is preferred
signer.update(dataToSign);
byte[] signature = signer.sign();
person ZZ Coder    schedule 08.09.2009
comment
s/public/private/ в вашей первой строке. - person caf; 08.09.2009

Не случайно разрешено шифрование с закрытым ключом. Если вы хотите разбить подпись на индивидуальное хеширование и шифрование, тогда шифрование с помощью закрытого ключа имеет важное значение. Допустим, у меня есть документ, который мне нужно подписать, а мой ключ находится в сетевом HSM. Теперь либо я передаю весь документ в HSM для подписи, либо могу создать локальный хэш и передать его в HSM только для шифрования. Мой выбор будет зависеть от того, даст ли мне локальное вычисление хэша лучшую производительность, а именно делегированное вычисление хэша с задержкой в ​​сети.

person Kapil    schedule 22.04.2010

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

Недавно я наткнулся на ту же проблему, отправил PMR 22265,49R, и служба поддержки IBM после консультации с разработчиками (кем бы они ни были) постановила, что закрытые ключи не могут использоваться для шифрования. Как бы я ни пытался спорить с ними о том, что закрытые ключи не следует использовать для защиты данных, что является единственной целью шифрования, и что использование закрытых ключей для шифрования для достижения неотрекаемости совершенно нормально, они были непоколебимы. в их вере. Вы должны любить людей, которые настаивают на том, что 2x2 = 5.

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

RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey) ks.getKey(keyAlias, ksPassword.trim().toCharArray());
RSAPublicKeySpec spec = new RSAPublicKeySpec(
   privateKey.getModulus(),
   privateKey.getPrivateExponent()
);
Key fakePublicKey = KeyFactory.getInstance("RSA").generatePublic(spec);
encryptCipher.init(Cipher.ENCRYPT_MODE, fakePublicKey);
person dmitry    schedule 08.02.2014
comment
Это очень рискованно, если вы относитесь к показателю закрытого ключа как к общедоступному показателю и распространяете его, потому что с учетом закрытого ключа (который вы называете открытым ключом) легко получить фактический открытый ключ (который вы сейчас называете закрытым ключом). ключ). Не выпускайте открытый ключ случайно, иначе ваша система будет скомпрометирована. Это может быть так же просто, как предположить, что показатель закрытого ключа равен 65537. - person Jim Flood; 24.05.2014
comment
Я так долго это искал. Я так благодарен за этот ответ. Имя закрытый и открытый ключ в этом случае совершенно неверны, но бывают ситуации, когда это уместно. - person BluBb_mADe; 30.06.2015
comment
@JimFlood Если я правильно понимаю и моя ситуация аналогична, dmitry создал RSAPublicKeySpec для хранения данных закрытого ключа. Очевидно, что он не собирается распространять закрытый ключ, а только исходный открытый ключ, который теперь можно использовать для доказательства (расшифровки) того, что закрытый ключ предназначен для шифрования, то есть для предотвращения отказа от авторства. - person Guss; 24.07.2017

попробуй это:

java.security.Security.addProvider(
                     new org.bouncycastle.jce.provider.BouncyCastleProvider()
            );
person Jimmy Chan    schedule 06.05.2015