Асимметричное шифрование Java: предпочтительный способ хранения открытых / закрытых ключей
этот код генерирует пару открытый/частный ключи:
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(1024);
KeyPair keypair = keyGen.genKeyPair();
PrivateKey privateKey = keypair.getPrivate();
PublicKey publicKey = keypair.getPublic();
что я хотел бы знать, как вы обычно храните открытый ключ:
Вариант 1: хранить байты
byte[] privateKeyBytes = privateKey.getEncoded();
byte[] publicKeyBytes = publicKey.getEncoded();
// ... write to file
// convert bytes back to public/private keys
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
мне не нравится привязывать код к конкретным реализациям, таким как PKCS8EncodedKeySpec
и X509EncodedKeySpec
.
Вариант 2: сохранить модуль и показатель
KeyFactory fact = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pub = fact.getKeySpec(publicKey, RSAPublicKeySpec.class);
RSAPrivateKeySpec priv = fact.getKeySpec(privateKey,RSAPrivateKeySpec.class);
// store modulus and exponent as BigIntegers
BigInteger modulus = pub.getModulus());
BigInteger exponent = pub.getPublicExponent());
// ... write to file
// recreate public key (the same applies to the private key)
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, exponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(keySpec);
второй вариант легче реализовать, но я не знайте, если это может быть менее эффективным.
какие посоветуете ?
3 ответов
в наших приложениях мы храним открытые и закрытые ключи в формате DER, чтобы их можно было использовать и манипулировать вне java более легко. В нашем случае на закрытых ключах нет паролей.
чтобы преобразовать закрытый ключ в нечто более удобное для использования в java:
openssl pkcs8 -topk8 -nocrypt -in key.pem -inform PEM -out key.der -outform DER
затем вы можете получить закрытый ключ RSA напрямую:
public static RSAPrivateKey getPrivateKey(File privateKeyFile) throws IOException, GeneralSecurityException {
byte[] keyBytes = new byte[(int)privateKeyFile.length()];
FileInputStream fis = new FileInputStream(privateKeyFile);
fis.read(keyBytes);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPrivateKey privKey = (RSAPrivateKey) keyFactory.generatePrivate(spec);
return privKey;
}
открытый ключ похож:
openssl rsa -in private.pem -pubout -outform DER -out public.der
и читать это:
public static RSAPublicKey getPublicKey(File publicKeyFile) throws IOException, GeneralSecurityException {
byte[] keyBytes = new byte[(int)publicKeyFile.length()];
FileInputStream fis = new FileInputStream(publicKeyFile);
fis.read(keyBytes);
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory factory = KeyFactory.getInstance("RSA");
RSAPublicKey pubKey = (RSAPublicKey)factory.generatePublic(publicKeySpec);
return pubKey;
}
много люди тогда магазин хранилищ. Для наших целей нам нужен был один и тот же ключ для совместного использования несколькими приложениями на нескольких языках, и мы не хотели дублировать файлы на диске.
в любом случае производительность не должна быть большой проблемой, потому что вы, вероятно, будете хранить эти ключи в каком-то Одноэлементном или кэше вместо того, чтобы регенерировать их каждый раз.
вы фактически храните байты в обоих случаях, понимаете вы это или нет. Я полагаю, что правильный ответ намекается в ответе @Brian M. Carr, который должен хранить объект более высокого уровня в его самой естественной форме. В случае открытых ключей очевидным выбором является ASN RSAPublicKey PKCS#1.1 структура, закодированная DER, или как X509 SubjectPublicKeyInfo ASN.1 структура, закодированная DER. Последнее-это то, что дают вам поставщики Sun, которые поддерживает sun class X509EncodedKeySpec. Аналогично, PKCS8EncodedKeySpec поддерживает формат закрытого ключа. Оба эти формата являются стандартами и поддерживаются openssl, например. Sun стремится - стремится: (- поддерживать существующие стандарты, а не определять свои собственные.
Если вы хотите определить формат для хранения ключей, я бы выбрал формат, который расходуется, чтобы он не ломался, когда вы хотите изменить шифрование (когда старый становится слабым, например).
поэтому я бы сохранил байты, закодированные как base64, вместе со строкой, которая описывает формат, возможно, "rsa".