Ключевое слово в защите информации
КЛЮЧЕВОЕ СЛОВО
в защите информации
Получить ГОСТ TLS-сертификат для домена (SSL-сертификат)
Добро пожаловать, Гость! Чтобы использовать все возможности Вход или Регистрация.

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline R_markov  
#1 Оставлено : 19 апреля 2019 г. 16:18:37(UTC)
R_markov

Статус: Новичок

Группы: Участники
Зарегистрирован: 19.04.2019(UTC)
Сообщений: 4
Российская Федерация

Создаю KeyPair из неё PublicKey сохраняю в созданный сертификат, а его в хранилище сертификатов; PrivateKey сохраняю в контейнер ключей. После создания контейнера и сертификата, пытаюсь подписать этим ключом подпись, а потом пройти верификацию, но выдаёт false. Ошибки не вылетают. Я проверил ключи на эквивалентность,полученный из сертификата PublicKey эквивалентен изначально созданному из keyPair , а полученный из контейнера PrivateKey не эквивалентен изначально созданному из keyPair. Подскажите где может быть ошибка?

Вот ссылка на Git: https://github.com/Rodion1234/SignatureJCP

В файле CreateKeyStores.java идет создание хранилищ для сертификата и ключа и создание самих сертификата и ключа.
В файле GettingKeyStores.java получение KeyStore
В файле GettingKeys.java получение из хранилищ приватного и публичного ключа.
Offline R_markov  
#2 Оставлено : 23 апреля 2019 г. 9:54:11(UTC)
R_markov

Статус: Новичок

Группы: Участники
Зарегистрирован: 19.04.2019(UTC)
Сообщений: 4
Российская Федерация

Добрый день, оставил заявку, ответ пока не найден. Может быть сложность в том, что тяжело разобраться с кодом, залью его сюда с пояснениями.

Код:

package CertificatesJ;

import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import ru.CryptoPro.JCP.JCP;
import ru.CryptoPro.JCPRequest.GostCertificateRequest;

import com.objsys.asn1j.runtime.Asn1Boolean;
import com.objsys.asn1j.runtime.Asn1ObjectIdentifier;
import com.objsys.asn1j.runtime.Asn1OctetString;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import ru.CryptoPro.JCP.ASN.PKIX1Explicit88.Extension;
import ru.CryptoPro.JCP.JCP;
import ru.CryptoPro.JCPRequest.GostCertificateRequest;

/**
 *
 * @author rodion
 */
public class CreateKeyStores {


    private static final String HTTP_ADDRESS = "http://www.cryptopro.ru/certsrv/";
    //провайдер
    private static final String PROVIDER_NAME = JCP.PROVIDER_NAME;

    //алгоритм для генерации ключевой пары KeyPairGenerator -> KeyPair
    private static final String KEY_ALG = JCP.GOST_EL_DEGREE_NAME;

    //алгоритм Алгоритм подписи сертификата
    private static final String SIGN_ALG = JCP.GOST_EL_SIGN_NAME;


// * @param alias Алиас ключа для сохранения.
// * @param storePath Путь к хранилищу сертификатов.
// * @param dnName DN-имя сертификата.
// * @param passw паролль на хранилища.
// * @throws Exception 
    public void createStoresKey(
            String alias, String storePath, String dnName, String passw) throws NoSuchAlgorithmException, NoSuchProviderException, Exception {

        //генератор ключевой пары, по алгоритму 
        KeyPairGenerator kpg = KeyPairGenerator.getInstance(KEY_ALG, PROVIDER_NAME);
        KeyPair keyPair = kpg.generateKeyPair();

        // отправка запроса центру сертификации и получение от центра
        // сертификата в DER-кодировке
        byte[] encoded = createRequestAndGetCert(keyPair, SIGN_ALG, PROVIDER_NAME, dnName);

        // инициализация генератора X509-сертификатов
        CertificateFactory cf = CertificateFactory.getInstance("X509");
        // генерирование X509-сертификата из закодированного представления сертификата
        Certificate cert
                = cf.generateCertificate(new ByteArrayInputStream(encoded));
        
        //создание хранилища контейнеров HDImageStore
        createHDImageStore(cert, alias, keyPair, passw);
        //создание хранилища сертификатов createCertStore
        createCertStore(alias, cert, storePath, passw);
        
        //проверка на совпадение
        PublicKey publicKey = new GettingKeys().getPublicKeyFromCertificate("CertStore", "new_2001", "password", "newcert_2001");
        PrivateKey privateKey = new GettingKeys().getPrivateKeyFromHDImageStore("HDImageStore", "keynewCert_2001", "password");
        
        if (publicKey.equals(keyPair.getPublic())) System.out.println("publicKey : true");
        else System.out.println("publicKey : false");
       // if(privateKey == null) System.out.println("asdf");
       
        if (privateKey.equals(keyPair.getPrivate())) System.out.println("privateKey : true");
        else System.out.println("privateKey : false");
    }

    //создание хранилища контейнеров HDImageStore
    private void createHDImageStore(Certificate cert, String alias, KeyPair keyPair, String passw) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException {
        Certificate[] chainCert = new Certificate[1];
        chainCert[0] = cert;

        //* запись закрытого ключа и цепочки сертификатов в хранилище
        // определение типа ключевого носителя, на который будет осуществлена запись ключа
        final KeyStore hdImageStore = KeyStore.getInstance(JCP.HD_STORE_NAME);
        // загрузка содержимого носителя (предполагается, что не существует
        // хранилища доверенных сертификатов)
        hdImageStore.load(null, null);
        // запись на носитель закрытого ключа и цепочки
        hdImageStore.setKeyEntry("key" + alias, keyPair.getPrivate(), passw.toCharArray(), chainCert);
        File file = new File("C:\\Users\\rodion\\Documents" + File.separator + "_new_2001.keystore");
        // сохранение содержимого хранилища
        hdImageStore.store(new FileOutputStream(file), passw.toCharArray());
    }

    //создание хранилища сертификатов createCertStore
    private void createCertStore(String alias, Certificate cert, String storePath, String passw) throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException {
        /* Запись полученного от центра сертификата*/
        // инициализация хранилища доверенных сертификатов именем ключевого носителя
        // (жесткий диск)
        KeyStore keyStore = KeyStore.getInstance(JCP.CERT_STORE_NAME);
        System.out.println(JCP.HD_STORE_NAME);
        // загрузка содержимого хранилища (предполагается, что инициализация
        // хранилища именем CertStoreName производится впервые, т.е. хранилища
        // с таким именем пока не существует)
        keyStore.load(null, null);

        // запись сертификата в хранилище доверенных сертификатов
        // (предполагается, что на носителе с именем CertStoreName не существует
        // ключа с тем же именем alias)
        keyStore.setCertificateEntry(alias, cert);

        // определение пути к файлу для сохранения в него содержимого хранилища
        File file = new File(storePath);
        // сохранение содержимого хранилища в файл
        keyStore.store(new FileOutputStream(file), passw.toCharArray());
    }

    public static byte[] createRequestAndGetCert(KeyPair pair, String signAlgorithm,
            String signatureProvider, String dnName) throws Exception {

        // формирование запроса
        GostCertificateRequest request = createRequest(pair,
                signAlgorithm, signatureProvider, dnName);

        // отправка запроса центру сертификации и получение от центра
        // сертификата в DER-кодировке
        return request.getEncodedCert(HTTP_ADDRESS);
    }

    public static GostCertificateRequest createRequest(KeyPair pair, String signAlgorithm,
            String signatureProvider, String dnName) throws Exception {
        /* Генерирование запроса на сертификат в соответствии с открытым ключом*/
        // создание генератора запроса на сертификат
        GostCertificateRequest request = new GostCertificateRequest(signatureProvider);
        // инициализация генератора
        // @deprecated с версии 1.0.48
        // вместо init() лучше использовать setKeyUsage() и addExtKeyUsage()
        // request.init(KEY_ALG);

        /*
    Установить keyUsage способ использования ключа можно функцией
    setKeyUsage. По умолчанию для ключа подписи, т.е. для указанного в первом
    параметре функции init() алгоритма "GOST3410EL" используется комбинация
    DIGITAL_SIGNATURE | NON_REPUDIATION. Для ключа шифрования, т.е. для
    алгоритма "GOST3410DHEL" добавляется KEY_ENCIPHERMENT | KEY_AGREEMENT.
         */
        final String keyAlgorithm = pair.getPrivate().getAlgorithm();
        if (keyAlgorithm.equalsIgnoreCase(JCP.GOST_EL_DEGREE_NAME)
                || keyAlgorithm.equalsIgnoreCase(JCP.GOST_EL_2012_256_NAME)
                || keyAlgorithm.equalsIgnoreCase(JCP.GOST_EL_2012_512_NAME)) {
            int keyUsage = GostCertificateRequest.DIGITAL_SIGNATURE
                    | GostCertificateRequest.NON_REPUDIATION;
            request.setKeyUsage(keyUsage);
        } // if
        else {
            int keyUsage = GostCertificateRequest.DIGITAL_SIGNATURE
                    | GostCertificateRequest.NON_REPUDIATION
                    | GostCertificateRequest.KEY_ENCIPHERMENT
                    | GostCertificateRequest.KEY_AGREEMENT;
            request.setKeyUsage(keyUsage);
        } // else

        /*
    Добавить ExtendedKeyUsage можно так. По умолчанию для ключа подписи,
    т.е. для алгоритма "GOST3410EL" список будет пустым. Для ключа
    шифрования, т.е. для алгоритма "GOST3410DHEL" добавляется OID
    INTS_PKIX_CLIENT_AUTH "1.3.6.1.5.5.7.3.2", а при установленном в true
    втором параметре функции init() еще добавляется INTS_PKIX_SERVER_AUTH
    "1.3.6.1.5.5.7.3.1"
         */
        request.addExtKeyUsage(GostCertificateRequest.INTS_PKIX_EMAIL_PROTECTION);
        /**
         * ExtendedKeyUsage можно указывать строкой "1.3.6.1.5.5.7.3.3", или
         * можно массивом int[]{1, 3, 6, 1, 5, 5, 7, 3, 4} или объектом типа
         * ru.CryptoPro.JCP.params.OID
         */
        request.addExtKeyUsage("1.3.6.1.5.5.7.3.3");
        /**
         * пример добавления в запрос собственного расширения Basic Constraints
         */

        Extension ext = new Extension();
        int[] extOid = {2, 5, 29, 19};
        ext.extnID = new Asn1ObjectIdentifier(extOid);
        ext.critical = new Asn1Boolean(true);
        byte[] extValue = {48, 6, 1, 1, -1, 2, 1, 5};
        ext.extnValue = new Asn1OctetString(extValue);
        request.addExtension(ext);

       
        // определение параметров и значения открытого ключа
        request.setPublicKeyInfo(pair.getPublic());
        // определение имени субъекта для создания запроса
        request.setSubjectInfo(dnName);
        // подпись сертификата на закрытом ключе и кодирование запроса
        request.encodeAndSign(pair.getPrivate(), signAlgorithm);

        return request;
    }
}


В этом классе основные методы createStoresKey - создание контейнеров и сертификатов и сохранение в них ключей, тут же есть и проверка (под комментарием //проверка на совпадение). Этот метод вызывается в main с такими параметрами.
Код:

CreateKeyStores cks = new CreateKeyStores();
cks.createStoresKey("newCert_2001",
"C:\\Users\\rodion\\Documents" + File.separator + "new_2001.keystore", "CN=" + "newCert_2001" + ", O=CryptoPro, C=RU","password");


В проверке идет вызов классов для получения KeyStore И PublicKey, PrivateKey

Вот реализация методов для получения KeyStore
Код:

public class GettingKeyStores {
    
    private static final String STORE_URL = "C:\\Users\\rodion\\Documents\\";
    private static final String POSTFIX = ".keystore";
    
    public KeyStore instenceCertStore(String typeKeyStore, String nameKeyStore, String password) throws KeyStoreException, FileNotFoundException, IOException, NoSuchAlgorithmException, CertificateException{
       KeyStore keyStore = KeyStore.getInstance(typeKeyStore);
       keyStore.load(new FileInputStream(new File(STORE_URL+nameKeyStore+POSTFIX)), password.toCharArray());
       
       return keyStore;
    }
    
    public KeyStore instenceHDImageStore(String typeKeyStore) throws KeyStoreException, FileNotFoundException, IOException, NoSuchAlgorithmException, CertificateException{
       KeyStore keyStore = KeyStore.getInstance(typeKeyStore);
       keyStore.load(new FileInputStream(new File("C:\\Users\\rodion\\Documents" + File.separator + "_new_2001.keystore")), "password".toCharArray());
       
       return keyStore;
    }
    
}


Вот реализация методов для получения Public и Private Key
Код:

public class GettingKeys {

    public PublicKey getPublicKeyFromCertificate(String typeKeyStore, String nameKeyStore, String password, String nameCetr) throws KeyStoreException, IOException, FileNotFoundException, NoSuchAlgorithmException, CertificateException {

        KeyStore keyStore = new GettingKeyStores().instenceCertStore(typeKeyStore, nameKeyStore, password);
        Certificate certificate = keyStore.getCertificate(nameCetr);

        PublicKey publicKey = certificate.getPublicKey();
        return publicKey;
    }

    public PrivateKey getPrivateKeyFromHDImageStore(String typeKeyStore, String nameKey, String password) throws UnrecoverableKeyException, IOException, KeyStoreException, FileNotFoundException, NoSuchAlgorithmException, CertificateException, NoSuchProviderException {

        KeyStore keyStore1 = new GettingKeyStores().instenceHDImageStore(typeKeyStore);
        PrivateKey privateKey = (PrivateKey) keyStore1.getKey(nameKey, password.toCharArray());

        return privateKey;
    }
}


Напомню в чем была проблема: Код работает без ошибок, дело в том, что когда мы берем PrivateKey из хранилища, он не совпадает начальному PrivateKey, и поэтому никаких документов мы подписывать не сможем. Подскажите в чём может быть ошибка?

Отредактировано пользователем 23 апреля 2019 г. 10:09:31(UTC)  | Причина: Уменьшил код для удобочитаемости.

Offline Евгений Афанасьев  
#3 Оставлено : 24 апреля 2019 г. 14:45:08(UTC)
Евгений Афанасьев

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 06.12.2008(UTC)
Сообщений: 3,910
Российская Федерация
Откуда: Крипто-Про

Сказал(а) «Спасибо»: 20 раз
Поблагодарили: 685 раз в 646 постах
Здравствуйте.
Как вы проверяете, что ключи подходят? С помощью equals? Этот метод не реализован для закрытого ключа в JCP. В следующих версиях будет возможность проверить, соответствует ли закрытый ключ открытому.
Offline R_markov  
#4 Оставлено : 25 апреля 2019 г. 12:26:19(UTC)
R_markov

Статус: Новичок

Группы: Участники
Зарегистрирован: 19.04.2019(UTC)
Сообщений: 4
Российская Федерация

Автор: Евгений Афанасьев Перейти к цитате
Здравствуйте.
Как вы проверяете, что ключи подходят? С помощью equals? Этот метод не реализован для закрытого ключа в JCP. В следующих версиях будет возможность проверить, соответствует ли закрытый ключ открытому.


Да, я проверял через equals. Евгений, я правильно понимаю, что бы мне подписать документ, нужно создать keypair = new KeyPair()и в его конструктор передать PublicKey из сертификата и PrivateKey из ключевого носителя ранее созданных. А уже потом с помощью keypair.getPublic() и keypair.getPrivate() использовать их для подписи и верификации? Просто, если я на прямую передаю эти ключи без создания KeyPair, то верификация не проходит.
Offline Евгений Афанасьев  
#5 Оставлено : 29 апреля 2019 г. 15:26:51(UTC)
Евгений Афанасьев

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 06.12.2008(UTC)
Сообщений: 3,910
Российская Федерация
Откуда: Крипто-Про

Сказал(а) «Спасибо»: 20 раз
Поблагодарили: 685 раз в 646 постах
Создаете ключи, сохраняете в контейнер (закрытый ключ + сертификат). Подписать можно как как ключом из keypair, так и извлеченным/прочитанным из контейнера.
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.