Как использовать хранилище ключей в Java для хранения закрытого ключа?
Я использовал KeyPairGenerator
генерировать пару ключей RSA. Если я не ошибаюсь, хранилище ключей используется только для хранения сертификатов, а не ключей. Как правильно хранить закрытый ключ на компьютере?
4 ответа
Вы можете сделать что-то вроде этого:
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair kp = kpg.genKeyPair();
KeyFactory fact = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pub = fact.getKeySpec(kp.getPublic(),
RSAPublicKeySpec.class);
saveToFile(PUBLIC_KEY_FILE,
pub.getModulus(), pub.getPublicExponent());
RSAPrivateKeySpec priv = fact.getKeySpec(kp.getPrivate(),
RSAPrivateKeySpec.class);
saveToFile(PRIVATE_KEY_FILE,
priv.getModulus(), priv.getPrivateExponent());
Функция сохранения:
private static void saveToFile(String fileName,
BigInteger mod, BigInteger exp)
throws SomeException {
ObjectOutputStream oout = new ObjectOutputStream(
new BufferedOutputStream(new FileOutputStream(fileName)));
try {
oout.writeObject(mod);
oout.writeObject(exp);
} catch (Exception e) {
throw new SomeException(e);
} finally {
oout.close();
}
}
И прочитайте так же назад:
private static PublicKey readPublicKey() throws SomeException {
InputStream in = new FileInputStream(PUBLIC_KEY_FILE);
ObjectInputStream oin =
new ObjectInputStream(new BufferedInputStream(in));
try {
BigInteger m = (BigInteger) oin.readObject();
BigInteger e = (BigInteger) oin.readObject();
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(keySpec);
return pubKey;
} catch (Exception e) {
throw new SomeException(e);
} finally {
oin.close();
}
}
Чтение закрытого ключа похоже.
Этот блок кода сгенерирует и сохранит KeyPair в AndroidKeyStore. (ПРИМЕЧАНИЕ. Исключения исключаются)
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
String alias = "my_key"; // replace as required or get it as a function argument
int nBefore = keyStore.size(); // debugging variable to help convince yourself this works
// Create the keys if necessary
if (!keyStore.containsAlias(alias)) {
Calendar notBefore = Calendar.getInstance();
Calendar notAfter = Calendar.getInstance();
notAfter.add(Calendar.YEAR, 1);
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(this)
.setAlias(alias)
.setKeyType("RSA")
.setKeySize(2048)
.setSubject(new X500Principal("CN=test"))
.setSerialNumber(BigInteger.ONE)
.setStartDate(notBefore.getTime())
.setEndDate(notAfter.getTime())
.build();
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
generator.initialize(spec);
KeyPair keyPair = generator.generateKeyPair();
}
int nAfter = keyStore.size();
Log.v(TAG, "Before = " + nBefore + " After = " + nAfter);
// Retrieve the keys
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(alias, null);
RSAPrivateKey privateKey = (RSAPrivateKey) privateKeyEntry.getPrivateKey();
RSAPublicKey publicKey = (RSAPublicKey) privateKeyEntry.getCertificate().getPublicKey();
Log.v(TAG, "private key = " + privateKey.toString());
Log.v(TAG, "public key = " + publicKey.toString());
В зависимости от формата вашего закрытого ключа вам может потребоваться преобразовать его в формат, который может использовать Java Keytool.
Но если он поддерживает формат keytool, вы можете импортировать его, используя keytool. больше информации на:
http://docs.oracle.com/javase/tutorial/security/toolfilex/rstep1.html
http://docs.oracle.com/javase/1.5.0/docs/tooldocs/windows/keytool.html
http://snipplr.com/view/18368/
ИЛИ ЖЕ
http://docs.oracle.com/javase/1.5.0/docs/api/java/security/KeyStore.html
ИЛИ ЖЕ
http://java.sun.com/docs/books/tutorial/security/apisign/vstep2.html Это наиболее перспективно
ИЛИ ЖЕ
Невозможно получить ключ в ненадежной среде. Вы можете запутать свой код, вы можете создать ключ из произвольных переменных, что угодно. В конечном итоге, предполагая, что вы используете стандартную библиотеку javax.crypto, вы должны вызвать Mac.getInstance(), а через некоторое время вы вызовете init() для этого экземпляра. Тот, кто хочет получить ваш ключ, получит его.
Тем не менее, я думаю, что решение заключается в том, что вы привязываете ключ к окружающей среде, а не к программе. Подпись означает, что данные получены из известного источника и не были подделаны с тех пор, как этот источник их предоставил. В настоящее время вы пытаетесь сказать "гарантировать, что моя программа произвела данные". Вместо этого измените ваше требование, чтобы "гарантировать, что данные были получены конкретным пользователем моей программы". Затем бремя перекладывается на этого пользователя, чтобы позаботиться о его ключе.