Как использовать хранилище ключей в 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() для этого экземпляра. Тот, кто хочет получить ваш ключ, получит его.

Тем не менее, я думаю, что решение заключается в том, что вы привязываете ключ к окружающей среде, а не к программе. Подпись означает, что данные получены из известного источника и не были подделаны с тех пор, как этот источник их предоставил. В настоящее время вы пытаетесь сказать "гарантировать, что моя программа произвела данные". Вместо этого измените ваше требование, чтобы "гарантировать, что данные были получены конкретным пользователем моей программы". Затем бремя перекладывается на этого пользователя, чтобы позаботиться о его ключе.

Другие вопросы по тегам