Java — асимметричное шифрование трафика с предварительно общими открытыми ключами и без проблем с хранилищем доверенных сертификатов.

Я пытаюсь общаться, используя предварительные ключи RSA и, в идеале, без махинаций с хранилищем доверенных сертификатов.

Настройка в основном такая:

На стороне клиента есть апплет, а на стороне сервера — сервлет (ага :) )

В апплете жестко закодирован открытый ключ RSA (Spub) сервлета.

Сервлет имеет собственный закрытый ключ RSA (Spriv), жестко запрограммированный.

Апплет They генерирует случайный ключ AES 256 (сеансовый ключ), шифрует его с помощью открытого ключа сервлета (который жестко запрограммирован), подключается к сервлету через сокет TCP и отправляет ключ, зашифрованный с помощью RSA, сервлету, который продолжает работу. чтобы расшифровать ключ сеанса и использовать его для любого дальнейшего взаимодействия с этим апплетом, пока длится это соединение сокета.

Я бы предпочел сделать все это, не связываясь с хранилищем доверенных сертификатов и т. Д. (В конце концов, это относительно простая настройка, которая позволяет использовать предварительно общий жестко закодированный открытый ключ)

Любые предложения относительно того, где я должен начать искать самообразование?


person Black    schedule 06.07.2012    source источник
comment
Апплет загружается через HTTPS?   -  person SLaks    schedule 06.07.2012
comment
Неа. Однако это подписанный апплет. Почему ? :)   -  person Black    schedule 07.07.2012
comment
Вы можете использовать сборку в SSL (JSSE), если просто создадите самозаверяющий сертификат для своего клиента и сервера. Java SSL имеет множество точек расширения, и вы также можете просто создать хранилище доверенных сертификатов в памяти.   -  person Maarten Bodewes    schedule 07.07.2012
comment
Как сказал Оулстед, вы можете использовать хранилище ключей в памяти, используя что-то вроде KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()), а затем импортировать свой жестко запрограммированный ключ/сертификат.   -  person DNA    schedule 07.07.2012
comment
Вау, не знал, что могу сделать хранилище ключей в памяти. Спасибо owlstead и ДНК!   -  person Black    schedule 07.07.2012
comment
Жестко запрограммированный SPub на самом деле является своего рода доверенным хранилищем. Нет причин не использовать JSSE.   -  person erickson    schedule 07.07.2012


Ответы (2)


Я согласен с комментариями о том, что SSL - достойный способ, но чтобы ответить на ваш прямой вопрос, схема, которую вы описали, довольно проста и, похоже, не раскрывает никаких секретов. Вот реализация RSA-части клиента, основанная на жестко запрограммированном открытом ключе.

// Hardcoded values extracted from getModulus of a generated KeySpec.
private static BigInteger mod = new BigInteger("113...");
private static BigInteger exp = new BigInteger("217...");

private PublicKey hardCodedKey() {
    RSAPublicKeySpec keySpec = new RSAPublicKeySpec(mod, exp);
    KeyFactory keyFactory = null;
    PublicKey rsaKey = null;
    try {
        keyFactory = KeyFactory.getInstance("RSA");
        rsaKey = keyFactory.generatePublic(keySpec);
    } catch (Exception ex) {
        throw new IllegalStateException(ex);
    }
    return rsaKey;
}

private byte[] encrypt(PublicKey pubKey, byte[] plaintext) {
    try {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        return cipher.doFinal(plaintext);
    } catch (Exception ex) {
        throw new IllegalStateException(ex);
    }
}
person phatfingers    schedule 07.07.2012
comment
Большое спасибо! Я думаю, что попробую это, затем попробую хранилище доверенных сертификатов в памяти (не знал, что это можно сделать) и посмотрю, есть ли какие-либо причины для использования того или другого. - person Black; 07.07.2012

Хотя вы можете использовать криптографические функции более низкого уровня, создав свой PublicKey и используя Cipher, стоит подумать об использовании JSSE: он предоставит все это в контексте сокетов. Кроме того, шифрование, предоставляемое SSL/TLS, осуществляется с помощью общих ключей, согласованных во время рукопожатия (среди прочего, это быстрее, чем асимметричное шифрование).

Вы можете создать хранилище доверенных сертификатов с самозаверяющим сертификатом для предварительного обмена этим открытым ключом. Вы можете загрузить его следующим образом (обратите внимание, что InputStream не обязательно должно быть FileInputStream, например, вы можете прочитать содержимое из памяти):

TrustManagerFactory tmf = TrustManagerFactory
    .getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance("JKS");
InputStream is = ...
ks.load(is, null);
// or ks.load(is, "thepassword".toCharArray());
is.close();

tmf.init(ks);

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);

SSLSocketFactory = sslContext.getSocketFactory();
// ...

Это нормальный способ использования JSSE. Если вы хотите использовать SSL/TLS со своим явным открытым ключом RSA, вам придется реализовать свой собственный TrustManager сделать явное сравнение (вместо использования TrustManagerFactory): это, безусловно, сделало бы код немного длиннее и сложнее.

Если вы запускаете все это в апплете, у вас все равно могут возникнуть проблемы с системой разрешений апплета для создания сокет-соединений. См. раздел Что могут и чего не могут делать апплеты.

person Bruno    schedule 07.07.2012