Шифрование с помощью закрытого ключа 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()
);