Статус: Активный участник
Группы: Участники
Зарегистрирован: 25.07.2019(UTC) Сообщений: 31  Сказал(а) «Спасибо»: 2 раз
|
Автор: two_oceans  Не совсем так, вот смотрите - когда подписываете своим закрытым ключом, на самом деле зашифровываете значение хэша закрытым ключом. При этом любой кто имеет сертификат, соответствующий этому ключу, может при помощи открытого сертификата расшифровать зашифрованный хэш и сравнить с фактических хэшем, то есть проверить подпись. Для упрощения сертификат даже прикладывается к подписи. это подписание. Другими словами у заинтересованных лиц не возникнет сложности узнать открытый ключ из сертификата и расшифровать хэш. Теперь смотрите шифрование файла от чужих глаз - если его зашифровать также закрытым ключом, то любой, кто имеет сертификат (открытый ключ) сможет его прочитать, что согласитесь, противоречит цели закрыть файл от чужих глаз. Поэтому была разработана схема согласования ключей - в общих чертах (не бейте меня за неточности, сотрудники КриптоПро) работает примерно так:
для каждого файла генерируется уникальный ключ (сессионный) и прилагается к файлу в зашифрованном виде, но чтобы ключ смог использовать только получатель, сам ключ тоже шифруется на ключе согласования. Ключ согласования в свою очередь вырабатывается на комбинации открытого ключа получателя (в конкретном случае берется из сертификата ФСС) и закрытого ключа отправителя. Изюминка в том, что если взять наоборот сертификат отправителя (который замените в зашифрованном запросе) и закрытый ключ получателя (который есть у ФСС) получится тот же ключ согласования, то есть ключ согласования симметричный (одинаков для шифрования и расшифровки) и не требуется пересылать закрытый ключ для получения ключа согласования. Так как ключ согласования получается одинаковый сколько бы раз не посылался запрос-ответ, то напрямую им шифровать данные нежелательно во избежание различных методов подборов ключа. Поэтому ключом согласования шифруется случайный сессионный ключ. Сервис ФСС в свою очередь получив ключ согласования сможет расшифровать сессионный ключ из сообщения и уже сессионным ключом расшифровать само сообщение.
Смысл в том, что при шифровании помимо своего закрытого ключа нужно еще и указать сертификат получателя и тогда расшифровать всю эту хитрую схему смогут только отправитель и получатель, так как только у них есть закрытые ключи для получения общего ключа согласования. Поэтому Вам надо начать с того чтобы где-то добыть сертификат ФСС и указать как-то его при шифровании, а перед отправкой заменить сертификат ФСС в результате на свой сертификат. Автор: PashaTechnique  Ведь сертификат выданный УЦ, имеет закрытый ключ для шифрования. Более точно, сначала была сгенерирована ключевая пара (открытый и закрытый ключ), хранящиеся в контейнере. Потом на основе ключевой пары создан запрос на сертификат (в запрос включается открытый ключ, сам запрос подписан закрытым ключом). УЦ на основе запроса на сертификат добавляет свои поля и подписывает, что получилось (сертификат, содержащий открытый ключ). Затем происходит установка сертификата в хранилище (при этом опционально может быть добавление сертификата в контейнер и установление связи между сертификатом в хранилище и контейнером). Это все происходит быстро в случае тестового УЦ, а некоторые УЦ сами генерирую ключевую пару и создают сертификат, поэтому действительно можно запутаться. Сам по себе сертификат ФСС тоже получен в УЦ, разница только в присутствии контейнера с закрытым ключом и наличии связи сертификата с контейнером. Если я вас правильно понял, все что вы сейчас описали делает следующая вещь. Данный метод как раз берет тот самый сертификат ФСС. Для того чтобы пройти ту самую подлинность. Код:
public static X509Certificate ExtractCertFromCertStore()
throws NoSuchProviderException, KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException {
KeyStore allCertStore = null;
String storepass = "pass";
String alias = "fss_test_cert_2019_34.10-2012.cer";
allCertStore = KeyStore.getInstance("CertStore");
File f = new File("C:\\Users\\shashkov\\Documents\\fssstore\\fssstore");
allCertStore.load(new FileInputStream(f), storepass.toCharArray());
X509Certificate UserCert = (X509Certificate) allCertStore.getCertificate(alias);
if (UserCert!=null)
System.out.println("Сертификат из файла, загружен.");
else
System.out.println("Сертификат из файла, не загружен.");
return UserCert;
}
Этот метод берет тот самый ключ для подписи: Код:
public static X509Certificate GetCertificateFromStorage(String Alias)
throws NoSuchProviderException, KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException {
if(!JCPXMLDSigInit.isInitialized()) {
JCPXMLDSigInit.init();
}
KeyStore ks = KeyStore.getInstance("HDImageStore");
ks.load(null, null);
X509Certificate certificate = (X509Certificate)ks.getCertificate(Alias);
if (certificate!=null)
System.out.println("Сертификат из хранилища HDImageStore, загружен.");
else
System.out.println("Сертификат из хранилища HDImageStore, не загружен.");
return certificate;
}
Далее при шифровании происходит следующее: Код:
...
//Шифрование подписанного документа
org.w3c.dom.Document doc = StartEncrypt(KeyCertificate.ExtractCertFromCertStore(), nameFile);
X509Certificate.addTextNode(KeyCertificate.certToBase64(KeyCertificate.GetCertificateFromStorage("zeus")));
....
public static Document StartEncrypt(X509Certificate cert , String nameFile) throws Exception
{
XmlInit.init();
MessageFactory mf = MessageFactory.newInstance();
SOAPMessage message = mf.createMessage();
SOAPPart soapPart = message.getSOAPPart();
FileInputStream is = new FileInputStream("C:\\Storage\\Store\\"+nameFile); // ЕСЛИ берем из файла
soapPart.setContent(new StreamSource(is));
Document doc = message.getSOAPPart().getEnvelope().getOwnerDocument();
//Создание случайного сессионного ключа.
final KeyGenerator kg = KeyGenerator.getInstance("GOST28147");
final SecretKey sessionKey = kg.generateKey();
//Зашифрование сессионного ключа.
EncryptedKey encryptedKey = wrapKey(doc, sessionKey, cert);
// EncryptedKey encryptedKey = wrapKey(doc, pk, cert);
//зашифрование документа
Element element = doc.getDocumentElement();
XMLCipher xmlCipher = XMLCipher.getInstance(Consts.URI_GOST_CIPHER);
xmlCipher.init(XMLCipher.ENCRYPT_MODE, sessionKey);
// добавляем шифрованный ключ.
EncryptedData encryptedData = xmlCipher.getEncryptedData();
KeyInfo keyInfo = new KeyInfo(doc);
keyInfo.add(encryptedKey);
encryptedData.setKeyInfo(keyInfo);
//зашифрование документа
xmlCipher.doFinal(doc, element, false);
is.close();
return doc;
}
Трудно на словах разобраться что там происходит, я даже половины не понял того что и вы то описали. Можете попробовать какими-то наводящими примерами? Большая часть кода в проекте взята из исходников примеров предоставляемых самими Crypto Pro, естественно некоторые нюансы такие как пути к хранилищам, доступ к ним же так же проверен, все работает, на ура. Эх какая же тут путаница...
|