Шифрование с помощью закрытого ключа 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 правильный ключ?
  • Любые мысли о неверной ошибке спецификации ключа?

Ответ 1

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

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

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

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

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

Ответ 2

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

Вам нужно использовать подпись. Вот фрагмент кода, чтобы сделать это,

signer = Signature.getInstance("SHA1withRSA");
signer.initSign(privateKey); // PKCS#8 is preferred
signer.update(dataToSign);
byte[] signature = signer.sign();

Ответ 3

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

Ответ 4

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

Недавно я наткнулся на ту же проблему, представив 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);

Ответ 5

попробуйте следующее:

java.security.Security.addProvider(
                     new org.bouncycastle.jce.provider.BouncyCastleProvider()
            );