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

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline al  
#1 Оставлено : 9 октября 2019 г. 13:59:21(UTC)
al

Статус: Активный участник

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

Сказал(а) «Спасибо»: 16 раз
Поблагодарили: 1 раз в 1 постах
Здравствуйте.
Пытаюсь проверить в CP CSP 4.0.9708 (лицензионный) подпись, сформированную в JCP 2.0.40424 (триал на 90 дней).
Платформа Windows 7 x64.

В java-порограмме, использующей JCP подпись генерируется (и проверяется) следующим образом (файл CertificateService.java):
Цитата:

package cryptopro.jcp.example;

import ru.CryptoPro.JCP.Key.GostPublicKey;
import ru.CryptoPro.JCP.Key.PublicKeySpec;
import ru.CryptoPro.JCP.Sign.GostElSign2012_256;
import ru.CryptoPro.JCP.JCP;

import javax.xml.bind.DatatypeConverter;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;

import java.io.Console;
import java.nio.charset.Charset;
import java.io.BufferedWriter;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.Files;
import java.io.IOException;

public class CertificateService {

private void declare_byte_array(byte[] b, StringBuilder sb){
for(int i=0;i<b.length;++i) {
String bi=String.format("%02X", b[i]);
sb.append("0x");
sb.append(bi);
if(i==(b.length-1)) sb.append("};"); else sb.append(", ");
}
sb.append("\n");
}

public static void main(String[] args) throws Exception {

java.security.Security.addProvider(new JCP());

KeyPairGenerator kg = KeyPairGenerator.getInstance(JCP.GOST_EL_2012_256_NAME);
KeyPair keyPair = kg.genKeyPair();

String dataToSign = "The quick brown fox jumps over the lazy dog";

System.out.println("Data to Sign : " + dataToSign);
System.out.println("Data to Sign [hex]: " + DatatypeConverter.printHexBinary(dataToSign.getBytes()));
System.out.println();

System.out.println("Public Key CSP BLOB: " + DatatypeConverter.printHexBinary(keyPair.getPublic().getEncoded()));
System.out.println("Public Key RAW: " + DatatypeConverter.printHexBinary(((PublicKeySpec) ((GostPublicKey) keyPair.getPublic()).getSpec()).encode()));

CertificateService certificateService = new CertificateService();

System.out.println();
System.out.println("Signing...");
byte[] sign = certificateService.sign(JCP.GOST_SIGN_2012_256_NAME, keyPair.getPrivate(), dataToSign.getBytes());

System.out.println("Signature: " + DatatypeConverter.printHexBinary(sign));

System.out.println();
System.out.println("Verifying Signature");
System.out.println("Verification Algorithm: " + JCP.GOST_SIGN_2012_256_NAME);

boolean isSignatureValid = certificateService.verify(
JCP.GOST_SIGN_2012_256_NAME,
keyPair.getPublic(),
dataToSign.getBytes(),
sign);

System.out.println("Signature Valid? " + isSignatureValid);

//формирование инклуда для c-файла
Charset charset = Charset.forName("UTF-8");
StringBuilder sb = new StringBuilder();
sb.append("unsigned char data[]={");
byte[] b = dataToSign.getBytes();
certificateService.declare_byte_array(b,sb);
sb.append("int data_len="); sb.append(String.format("%d", b.length));sb.append(";\n");
sb.append("unsigned char pub_key[64]={");
b = ((PublicKeySpec) ((GostPublicKey) keyPair.getPublic()).getSpec()).encode();
certificateService.declare_byte_array(b,sb);
sb.append("unsigned char signature[64]={");
b = sign;
certificateService.declare_byte_array(b,sb);
String s=sb.toString();
BufferedWriter writer = null;
try {
Path path = Paths.get("./csp_test.inc");
writer = Files.newBufferedWriter(path, charset);
writer.write(s, 0, s.length());
} catch (IOException x) {
System.err.format("IOException: %s%n", x);
} finally {
if (writer != null) writer.close();
}

}

private byte[] sign(String algorithmName, PrivateKey privateKey, byte[] data) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
final Signature sign = Signature.getInstance(algorithmName);
sign.initSign(privateKey);
sign.update(data);
System.out.println("Signature Algorithm: " + sign.getAlgorithm());
System.out.println("Signature Provider Name: " + sign.getProvider().getName());
System.out.println("Signature Provider Info: " + sign.getProvider().getInfo());
System.out.println("Signature Params: " + ((GostElSign2012_256) sign).toString());
return sign.sign();
}

private boolean verify(String algorithmName, PublicKey publicKey, byte[] data, byte[] signature) throws Exception {
final Signature sig = Signature.getInstance(algorithmName);
sig.initVerify(publicKey);
sig.update(data);
return sig.verify(signature);
}
}


Во время работы этой java-программы, формируется кусок сишного кода (csp_test.inc), в который записывается объявление переменных data, pub_key и signature.
Затем csp_test.inc инклудится в сишний файл, в котором я проверяю подпись на CSP, сформированную в JCP. Вот этот сишный файл (test_csp.c):
Цитата:

#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>
#include <WinCryptEx.h>

#ifdef _WIN32
#pragma warning( push )
#pragma warning( disable : 4996 )
#endif

#define CONTAINER_256 "\\\\.\\REGISTRY\\test_cont_"

unsigned char PIN_TO_CONT[]={'1','1','1','1','1','1','1','1','\0'};

HCRYPTPROV hProv = 0;
HCRYPTHASH hHash = 0;
HCRYPTKEY hKey = 0;
HCRYPTKEY hPubKey = 0;
BYTE *pbSignature = NULL;
BYTE *pbKeyBlob = NULL;

static void CleanUp(void)
{
if(pbSignature) free(pbSignature);
if(pbKeyBlob) free(pbKeyBlob);
if(hHash) CryptDestroyHash(hHash);
if(hKey) CryptDestroyKey(hKey);
if(hPubKey) CryptDestroyKey(hPubKey);
if(hProv) CryptReleaseContext(hProv, 0);
}

static void HandleError(const char *s, long line)
{
DWORD err = GetLastError();
printf("Error number : 0x%x\n", err);
printf("[L:%ld] Error description: %s\n", line,s);
CleanUp();
if(!err) err = 1;
exit(err);
}

#ifndef CERT_ENCODING_TYPE
#define CERT_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
#endif

static int EncodeObject(LPCSTR lpszStructType, const void *pvStructInfo, LPBYTE *pbEncoded, LPDWORD pcbEncoded){

if(!CryptEncodeObject(
CERT_ENCODING_TYPE,
lpszStructType,
pvStructInfo,
NULL,
pcbEncoded))
{
HandleError("Can't EncodeObject",__LINE__);
}

*pbEncoded = (BYTE *)malloc(*pcbEncoded);

if(!CryptEncodeObject(
CERT_ENCODING_TYPE,
lpszStructType,
pvStructInfo,
*pbEncoded,
pcbEncoded))
{
HandleError("Can't EncodeObject",__LINE__);
}

return 1;
}

//импортировать открытый ключ
int ImportPublicKey(LPBYTE pbKey, LPBYTE pbPubKeyBlob, DWORD * pcbPubKeyBlobLen){

CRYPT_ATTRIBUTE blob;
LPBYTE pbPKParam = NULL;
LPBYTE pbDgParam = NULL;
DWORD cbEncoded = 0;
BYTE pklen;
BYTE dglen;
BYTE OF_TAG = 2;
BYTE OF_LEN = 3;
LPBYTE pbkeyblob = NULL;
DWORD cbkeyblob;
LPBYTE ptr = NULL;
CRYPT_PUBKEY_INFO_HEADER keyheader;
LPBYTE hash_oid=szOID_CP_GOST_R3411_12_256;

keyheader.BlobHeader.bType = PUBLICKEYBLOB;
keyheader.BlobHeader.bVersion = BLOB_VERSION;
keyheader.BlobHeader.reserved = 0;
keyheader.BlobHeader.aiKeyAlg = CALG_GR3410_12_256;

keyheader.KeyParam.Magic = GR3410_1_MAGIC;
keyheader.KeyParam.BitLen = 64*8;

blob.pszObjId = szOID_GostR3410_2001_CryptoPro_A_ParamSet;
blob.cValue = 0;
blob.rgValue = NULL;
if(!EncodeObject(
PKCS_ATTRIBUTE,
&blob,
&pbPKParam,
&cbEncoded
))return 0;
pklen = pbPKParam[OF_LEN]+2; // +tag+len

blob.pszObjId = hash_oid;
blob.cValue = 0;
blob.rgValue = NULL;
if(!EncodeObject(
PKCS_ATTRIBUTE,
&blob,
&pbDgParam,
&cbEncoded
))return 0;
dglen = pbDgParam[OF_LEN]+2; // +tag+len

cbkeyblob = sizeof(keyheader)+2+pklen+dglen+64;
pbkeyblob = (BYTE *)malloc(cbkeyblob);
ptr = pbkeyblob;
memcpy(ptr, &keyheader, sizeof(keyheader)); ptr += sizeof(keyheader);
ptr[0] = 0x30; // set of
ptr[1] = pklen+dglen; ptr += 2;
memcpy(ptr, pbPKParam+OF_TAG, pklen); ptr += pklen;
memcpy(ptr, pbDgParam+OF_TAG, dglen); ptr += dglen;
memcpy(ptr, pbKey, 64);
memcpy(pbPubKeyBlob,pbkeyblob,cbkeyblob);
*pcbPubKeyBlobLen=cbkeyblob;
if(pbkeyblob) free(pbkeyblob);
if(pbPKParam) free(pbPKParam);
if(pbDgParam) free(pbDgParam);

return 1;
}

int main(){

#include "./csp_test.inc"

LPBYTE p=NULL;
BYTE pbBuffer[2048];
DWORD dwBufferLen;
DWORD dwSigLen;
BYTE pbKeyBlob[1024];
DWORD dwBlobLen;

// Получение дескриптора контекста криптографического провайдера
if(CryptAcquireContext(&hProv, CONTAINER_256, NULL, PROV_GOST_2012_256, 0)) {
printf("Container %s exists\n", CONTAINER_256);
CryptSetProvParam(hProv, PP_KEYEXCHANGE_PIN, PIN_TO_CONT, 0);
if(!CryptAcquireContext(&hProv, CONTAINER_256, NULL, PROV_GOST_2012_256, CRYPT_DELETEKEYSET)) {
HandleError("Can't delete Container",__LINE__);
}
printf("Container %s deleted\n", CONTAINER_256);
}
//создаем новый контейнер
if(!CryptAcquireContext(&hProv,CONTAINER_256, NULL, PROV_GOST_2012_256, CRYPT_NEWKEYSET)) {
HandleError("Could not create a new key container",__LINE__);
}
printf("A new key container has been created\n");

//установка ПИНа на контейнер
CryptSetProvParam(hProv, PP_KEYEXCHANGE_PIN, PIN_TO_CONT, 0);

if(!CryptSetProvParam(hProv, PP_SIGNATUREOID, (LPBYTE)szOID_GostR3410_2001_CryptoPro_A_ParamSet, 0)) {
HandleError("Could not set hash_oid",__LINE__);
}

// http://cpdn.cryptopro.ru...44f9e75b9888e0e4db3.html
//
// KP_HASHOID
// Идентификатор функции хэширования. Строка, заканчивающаяся нулем.
// Не допускается задавать для объектов типа
// ... CALG_GR3411_2012_256 / CALG_GR3411_2012_512
//
// if(!CryptSetProvParam(hProv, PP_HASHOID, (LPBYTE)szOID_CP_GOST_R3411_12_256, 0))
// HandleError("Could not set hash_oid",__LINE__);

if(!CryptSetProvParam(hProv, PP_CIPHEROID, (LPBYTE)szOID_Gost28147_89_TC26_Z_ParamSet, 0)) {
HandleError("Could not set cipher_oid",__LINE__);
}

// Формирование хеша по данным, полученным извне
dwBufferLen=data_len;
memcpy(pbBuffer,data,dwBufferLen);
if(CryptCreateHash(
hProv,
CALG_GR3411_2012_256,
0,
0,
&hHash)
) {
printf("Hash object created\n");
} else {
HandleError("Error during CryptCreateHash",__LINE__);
}

// if(!CryptSetHashParam(hHash, KP_HASHOID, (LPBYTE)szOID_CP_GOST_R3411_12_256, 0)) {
// HandleError("Could not set hash_oid",__LINE__);
// }

if(CryptHashData(
hHash,
pbBuffer,
dwBufferLen,
0)
) {
printf("The data buffer has been hashed\n");
} else {
HandleError("Error during CryptHashData",__LINE__);
}

//импорт паблика
if(!ImportPublicKey(pub_key, pbKeyBlob, &dwBlobLen))
HandleError("CryptGetHashParam failed",__LINE__);
if(CryptImportKey(
hProv,
pbKeyBlob,
dwBlobLen,
0,
0,
&hPubKey)
) {
printf("The key has been imported\n");
} else {
HandleError("Public key import failed",__LINE__);
}

//проверка подписи
dwSigLen=64;
pbSignature = (BYTE *)malloc(dwSigLen);
if(!pbSignature)
HandleError("Out of memory",__LINE__);
memcpy(pbSignature,signature,dwSigLen);

if(CryptVerifySignature(
hHash,
pbSignature,
dwSigLen,
hPubKey,
NULL,
0)
) {
printf("The signature has been verified\n");
} else {
HandleError("Signature not validated!",__LINE__);
}

CleanUp();

return 0;

}
#ifdef _WIN32
#pragma warning( pop )
#endif


Атрибуты объекта "подпись" (sign) в JCP:
Цитата:

Signature Algorithm: GOST3411_2012_256withGOST3410_2012_256
Signature Provider Name: JCP
Signature Provider Info: CryptoPro Java Provider
Signature Params: Gost Signature
params: ru.CryptoPro.JCP.params.AlgIdSpec: 1.2.643.7.1.1.1.1
ru.CryptoPro.JCP.params.EllipticParamsSpec: 1.2.643.2.2.35.1
ru.CryptoPro.JCP.params.DigestParamsSpec: 1.2.643.7.1.1.2.2
ru.CryptoPro.JCP.params.CryptParamsSpec: 1.2.643.7.1.2.5.1.1


Атрибуты в сишном коде
Цитата:

провайдер - PROV_GOST_2012_256
PP_SIGNATUREOID - szOID_GostR3410_2001_CryptoPro_A_ParamSet (т.е. кривая от "старого-доброго" 3410-2001)
PP_CIPHEROID - szOID_Gost28147_89_TC26_Z_ParamSet
параметр PP_HASHOID (на hProv) или KP_HASHOID (на hHash) выставить не дает, ибо -
http://cpdn.cryptopro.ru...44f9e75b9888e0e4db3.html


Паблик, созданный в JCP импортируется в CSP.
хеш (по данным из java-программы) в CSP формируется.
Подаю этот хеш (сформированный в CSP) и подпись (сформированную в java-программе) в CryptVerifySignature
- подпись не верна: NTE_BAD_SIGNATURE (0x80090006),

Подозрение на то, что хеш в JCP и CSP формируется по-разному.
Либо я что-то делаю не так.
Подскажите, пожалуйста, что нужно сделать, чтобы подпись, сформированная в JCP проверялась в CSP.

PS. Как собрать и запустить java-программу, а затем сишную программу:
в пустом директории (например, C:\Junk) создаем директорий bin и директории src\cryptopro\jcp\example\
в последний кладем java-программу (файл CertificateService.java). Переходим в C:\Junk и запускаем окружение сборки, например такое:
Цитата:

@echo on
set JAVA_HOME=C:\Java\jdk1.8.0_221
set PATH=%JAVA_HOME%\bin
set CLASSPATH=C:\Java\jre1.8.0_221\lib\ext\*;.\bin

собираем и запускаем:
Цитата:

javac -d bin src/cryptopro/jcp/example/CertificateService.java
java cryptopro.jcp.example.CertificateService


в этот же директорий (C:\Junk) кладем сишный файл (test_csp.c), собираем и запускаем:
Цитата:

cl -D__WIN32__ -D_WIN32 -DWIN32 -D_WINDOWS /W3 /EHsc /MDd /ZI /c -I. /Fd"vc70.pdb" -Fotest_csp.obj test_csp.c
link /OPT:NOICF /OPT:NOLBR /OPT:NOREF /nologo /subsystem:console /MACHINE:IX86 kernel32.lib user32.lib crypt32.lib advapi32.lib /OUT:test_csp.exe test_csp.obj

./test_csp.exe

Отредактировано пользователем 9 октября 2019 г. 14:01:04(UTC)  | Причина: Не указана

Offline al  
#2 Оставлено : 9 октября 2019 г. 15:48:10(UTC)
al

Статус: Активный участник

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

Сказал(а) «Спасибо»: 16 раз
Поблагодарили: 1 раз в 1 постах
Добавил пару дефайнов в сишный файл (test_csp.c)
Цитата:

//если нижеследующий дефайн определен, то исходные данные инклудятся из файла ./csp_test.inc
//если не определен, то берутся вшитые в код данные, на которых подпись проверяется
//#define USE_CSP_TEST_INC

//если нижеследующий дефайн определен, то используются самописные функции импорта ключа
//ели не определен, то делается "хитро" - генерится пара, экспортируется паблик, на его место в блобе
//записывается новый паблик, на котором будем проверять подпись
#define USE_OUR_OWN_IMPORT


Первый - чтоб посмотреть, что подпись проверяется-таки (на заведомо правильных данных - из встречного тестирования нашей карты и CSP).
Второй - задействует либо нашу самописную функцию импорта паблика, либо делает "хитро" (оба варианта рабочие).

Итак:
Цитата:

//если нижеследующий дефайн определен, то исходные данные инклудятся из файла ./csp_test.inc
//если не определен, то берутся вшитые в код данные, на которых подпись проверяется
//#define USE_CSP_TEST_INC

//если нижеследующий дефайн определен, то используются самописные функции импорта ключа
//ели не определен, то делается "хитро" - генерится пара, экспортируется паблик, на его место в блобе
//записывается новый паблик, на котором будем проверять подпись
#define USE_OUR_OWN_IMPORT

#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>
#include <WinCryptEx.h>

#ifdef _WIN32
#pragma warning( push )
#pragma warning( disable : 4996 )
#endif

#define CONTAINER_256 "\\\\.\\REGISTRY\\test_cont_"

unsigned char PIN_TO_CONT[]={'1','1','1','1','1','1','1','1','\0'};

HCRYPTPROV hProv = 0;
HCRYPTHASH hHash = 0;
HCRYPTKEY hKey = 0;
HCRYPTKEY hPubKey = 0;
BYTE *pbBuffer=NULL;

static void CleanUp(void)
{
if(pbBuffer)free(pbBuffer);
if(hHash) CryptDestroyHash(hHash);
if(hKey) CryptDestroyKey(hKey);
if(hPubKey) CryptDestroyKey(hPubKey);
if(hProv) CryptReleaseContext(hProv, 0);
}

static void HandleError(const char *s, long line)
{
DWORD err = GetLastError();
printf("Error number : 0x%x\n", err);
printf("[L:%ld] Error description: %s\n", line,s);
CleanUp();
if(!err) err = 1;
exit(err);
}

#ifndef CERT_ENCODING_TYPE
#define CERT_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
#endif

static int EncodeObject(LPCSTR lpszStructType, const void *pvStructInfo, LPBYTE *pbEncoded, LPDWORD pcbEncoded){

if(!CryptEncodeObject(
CERT_ENCODING_TYPE,
lpszStructType,
pvStructInfo,
NULL,
pcbEncoded))
{
HandleError("Can't EncodeObject",__LINE__);
}

*pbEncoded = (BYTE *)malloc(*pcbEncoded);

if(!CryptEncodeObject(
CERT_ENCODING_TYPE,
lpszStructType,
pvStructInfo,
*pbEncoded,
pcbEncoded))
{
HandleError("Can't EncodeObject",__LINE__);
}

return 1;
}

//импортировать открытый ключ
int ImportPublicKey(LPBYTE pbKey, LPBYTE pbPubKeyBlob, DWORD * pcbPubKeyBlobLen){

CRYPT_ATTRIBUTE blob;
LPBYTE pbPKParam = NULL;
LPBYTE pbDgParam = NULL;
DWORD cbEncoded = 0;
BYTE pklen;
BYTE dglen;
BYTE OF_TAG = 2;
BYTE OF_LEN = 3;
LPBYTE pbkeyblob = NULL;
DWORD cbkeyblob;
LPBYTE ptr = NULL;
CRYPT_PUBKEY_INFO_HEADER keyheader;
LPBYTE hash_oid=szOID_CP_GOST_R3411_12_256;

keyheader.BlobHeader.bType = PUBLICKEYBLOB;
keyheader.BlobHeader.bVersion = BLOB_VERSION;
keyheader.BlobHeader.reserved = 0;
keyheader.BlobHeader.aiKeyAlg = CALG_GR3410_12_256;

keyheader.KeyParam.Magic = GR3410_1_MAGIC;
keyheader.KeyParam.BitLen = 64*8;

blob.pszObjId = szOID_GostR3410_2001_CryptoPro_A_ParamSet;
blob.cValue = 0;
blob.rgValue = NULL;
if(!EncodeObject(
PKCS_ATTRIBUTE,
&blob,
&pbPKParam,
&cbEncoded
))return 0;
pklen = pbPKParam[OF_LEN]+2; // +tag+len

blob.pszObjId = hash_oid;
blob.cValue = 0;
blob.rgValue = NULL;
if(!EncodeObject(
PKCS_ATTRIBUTE,
&blob,
&pbDgParam,
&cbEncoded
))return 0;
dglen = pbDgParam[OF_LEN]+2; // +tag+len

cbkeyblob = sizeof(keyheader)+2+pklen+dglen+64;
pbkeyblob = (BYTE *)malloc(cbkeyblob);
ptr = pbkeyblob;
memcpy(ptr, &keyheader, sizeof(keyheader)); ptr += sizeof(keyheader);
ptr[0] = 0x30; // set of
ptr[1] = pklen+dglen; ptr += 2;
memcpy(ptr, pbPKParam+OF_TAG, pklen); ptr += pklen;
memcpy(ptr, pbDgParam+OF_TAG, dglen); ptr += dglen;
memcpy(ptr, pbKey, 64);
memcpy(pbPubKeyBlob,pbkeyblob,cbkeyblob);
*pcbPubKeyBlobLen=cbkeyblob;
if(pbkeyblob) free(pbkeyblob);
if(pbPKParam) free(pbPKParam);
if(pbDgParam) free(pbDgParam);

return 1;
}

int main(){

#ifdef USE_CSP_TEST_INC
#include "./csp_test.inc"
#else
unsigned char data[]={0x1B, 0xF4, 0x11, 0x33, 0x55, 0x77, 0x22, 0x88, 0x75, 0x47, 0x73, 0x06, 0x28, 0x02, 0x48, 0x98};
int data_len=16;
unsigned char pub_key[64]={0xED, 0x76, 0x01, 0xF4, 0x8B, 0xE6, 0xDA, 0xCE, 0x62, 0x7C, 0x59, 0x7A, 0x59, 0x37, 0xC8, 0x3E, 0x6B, 0x86, 0xB5, 0x96, 0xA8, 0x57, 0xE0, 0xCF, 0x78, 0x56, 0x47, 0x88, 0xC6, 0x71, 0x55, 0x64, 0xA3, 0xEC, 0x5A, 0x93, 0x81, 0xAD, 0xC2, 0x65, 0x8F, 0x98, 0x82, 0x00, 0x73, 0xA5, 0x78, 0x0F, 0xA7, 0x25, 0xE5, 0x6C, 0x43, 0xC9, 0xB2, 0x02, 0x16, 0xA9, 0xA2, 0x43, 0x84, 0xA5, 0x4A, 0x75};
unsigned char signature[64]={0xD6, 0xB7, 0x8F, 0x44, 0x19, 0xB9, 0x8B, 0x2C, 0x3E, 0x04, 0xB1, 0xBD, 0x86, 0xD3, 0x40, 0xCB, 0x57, 0x43, 0x35, 0xA6, 0x22, 0x0D, 0xD8, 0xB4, 0x2A, 0xCB, 0xC5, 0xA1, 0x85, 0xDD, 0xD4, 0x6F, 0xE2, 0x9A, 0xB8, 0x52, 0xE4, 0xCB, 0xB3, 0x41, 0x1D, 0x4A, 0xCA, 0xA0, 0xF1, 0x5C, 0x41, 0x2C, 0x91, 0x2E, 0x01, 0x77, 0x17, 0x28, 0x29, 0x14, 0x4E, 0x65, 0xDA, 0x1A, 0xF9, 0x74, 0x2D, 0xDF};
#endif

DWORD dwBufferLen;

BYTE pbSignature[64];
DWORD dwSigLen;
BYTE pbKeyBlob[2048];
DWORD dwBlobLen=2048;

// Получение дескриптора контекста криптографического провайдера
if(CryptAcquireContext(&hProv, CONTAINER_256, NULL, PROV_GOST_2012_256, 0)) {
printf("Container %s exists\n", CONTAINER_256);
CryptSetProvParam(hProv, PP_KEYEXCHANGE_PIN, PIN_TO_CONT, 0);
if(!CryptAcquireContext(&hProv, CONTAINER_256, NULL, PROV_GOST_2012_256, CRYPT_DELETEKEYSET)) {
HandleError("Can't delete Container",__LINE__);
}
printf("Container %s deleted\n", CONTAINER_256);
}
//создаем новый контейнер
if(!CryptAcquireContext(&hProv,CONTAINER_256, NULL, PROV_GOST_2012_256, CRYPT_NEWKEYSET)) {
HandleError("Could not create a new key container",__LINE__);
}
printf("A new key container has been created\n");

//установка ПИНа на контейнер
CryptSetProvParam(hProv, PP_KEYEXCHANGE_PIN, PIN_TO_CONT, 0);

if(!CryptSetProvParam(hProv, PP_SIGNATUREOID, (LPBYTE)szOID_GostR3410_2001_CryptoPro_A_ParamSet, 0)) {
HandleError("Could not set hash_oid",__LINE__);
}

// http://cpdn.cryptopro.ru...44f9e75b9888e0e4db3.html
//
// KP_HASHOID
// Идентификатор функции хэширования. Строка, заканчивающаяся нулем.
// Не допускается задавать для объектов типа
// ... CALG_GR3411_2012_256 / CALG_GR3411_2012_512
//
// if(!CryptSetProvParam(hProv, PP_HASHOID, (LPBYTE)szOID_CP_GOST_R3411_12_256, 0))
// HandleError("Could not set hash_oid",__LINE__);

if(!CryptSetProvParam(hProv, PP_CIPHEROID, (LPBYTE)szOID_Gost28147_89_TC26_Z_ParamSet, 0)) {
HandleError("Could not set cipher_oid",__LINE__);
}

// Формирование хеша по данным, полученным извне
dwBufferLen=data_len;
pbBuffer = (BYTE *)malloc(dwBufferLen);
if(!pbBuffer)
HandleError("Out of memory",__LINE__);

memcpy(pbBuffer,data,dwBufferLen);

if(CryptCreateHash(
hProv,
CALG_GR3411_2012_256,
0,
0,
&hHash)
) {
printf("Hash object created\n");
} else {
HandleError("Error during CryptCreateHash",__LINE__);
}

// if(!CryptSetHashParam(hHash, KP_HASHOID, (LPBYTE)szOID_CP_GOST_R3411_12_256, 0)) {
// HandleError("Could not set hash_oid",__LINE__);
// }

if(CryptHashData(
hHash,
pbBuffer,
dwBufferLen,
0)
) {
printf("The data buffer has been hashed\n");
} else {
HandleError("Error during CryptHashData",__LINE__);
}

#ifdef USE_OUR_OWN_IMPORT
//импорт паблика
if(!ImportPublicKey(pub_key, pbKeyBlob, &dwBlobLen))
HandleError("CryptGetHashParam failed",__LINE__);
#else
// Контекст с ключевым контейнером доступен,
// попытка получения дескриптора ключа подписи
if(CryptGetUserKey(
hProv,
AT_SIGNATURE,
&hKey)
)
{
printf("A signature key is available\n");
} else {
printf("No signature key is available\n");
// контейнер не содержит ключа подписи
if(!(GetLastError() == (DWORD)NTE_NO_KEY))
HandleError("An error other than NTE_NO_KEY getting signature key",__LINE__);

// Создание ключевой пары AT_SIGNATURE
printf("The signature key does not exist\n");
printf("Creating a signature key pair...\n");

if(!CryptGenKey(
hProv,
AT_SIGNATURE,
CRYPT_EXPORTABLE,
&hKey)
) {
HandleError("Error occurred creating a signature key",__LINE__);
}

printf("Signature key pair created\n");
}

printf("The signature key has been acquired\n");

if(CryptExportKey(
hKey,
0,
PUBLICKEYBLOB,
0,
NULL,
&dwBlobLen)
) {
printf("Size of the BLOB for the public key determined\n");
} else {
HandleError("Error computing BLOB length",__LINE__);
}

if(CryptExportKey(
hKey,
0,
PUBLICKEYBLOB,
0,
pbKeyBlob,
&dwBlobLen)
) {
printf("Contents have been written to the BLOB\n");
} else {
HandleError("Error during CryptExportKey",__LINE__);
}

memcpy((BYTE *)(pbKeyBlob+dwBlobLen-64),pub_key,64);

#endif

if(CryptImportKey(
hProv,
pbKeyBlob,
dwBlobLen,
0,
0,
&hPubKey)
) {
printf("The key has been imported\n");
} else {
HandleError("Public key import failed",__LINE__);
}

//проверка подписи
dwSigLen=64;
memcpy(pbSignature,signature,dwSigLen);

if(CryptVerifySignature(
hHash,
pbSignature,
dwSigLen,
hPubKey,
NULL,
0)
) {
printf("The signature has been verified\n");
} else {
HandleError("Signature not validated!",__LINE__);
}

CleanUp();

return 0;

}
#ifdef _WIN32
#pragma warning( pop )
#endif


Помогите понять, почему подпись из JCP не проверяется...

Отредактировано пользователем 9 октября 2019 г. 16:28:59(UTC)  | Причина: Не указана

Offline Санчир Момолдаев  
#3 Оставлено : 9 октября 2019 г. 17:11:43(UTC)
Санчир Момолдаев

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

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

Сказал(а) «Спасибо»: 88 раз
Поблагодарили: 226 раз в 213 постах
Добрый день!
не совсем понял в каком виде у вас byte[] data
в общем случае если хэшировать в JCP для получения raw подписи, можно сделать примерно так
Код:
        MessageDigest digest = MessageDigest.getInstance(JCP.GOST_DIGEST_2012_256_NAME,JCP.PROVIDER_NAME);
        digest.update(data);
        byte [] hash = digest.digest();
        System.out.println(digest.getDigestLength()); //должно выйти 32 байта
        Signature signature = Signature.getInstance(JCP.RAW_CRYPTOPRO_SIGN_2012_256_NAME,JCP.PROVIDER_NAME);
        /*
        JCP.RAW_CRYPTOPRO_SIGN_2012_256_NAME обратный порядок для совместимости с CSP
        JCP.RAW_GOST_SIGN_2012_256_NAME
         */
        signature.initSign(privateKey);
        signature.update(hash); //на вход 32 байта

в данном случае data это исходные данные в byte. соответственно если вам необходимо, вы можете получить хэш самостоятельно и передать его в код.
Техническую поддержку оказываем тут
Наша база знаний
thanks 1 пользователь поблагодарил Санчир Момолдаев за этот пост.
al оставлено 09.10.2019(UTC)
Offline al  
#4 Оставлено : 9 октября 2019 г. 19:05:05(UTC)
al

Статус: Активный участник

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

Сказал(а) «Спасибо»: 16 раз
Поблагодарили: 1 раз в 1 постах
Прошу прощения, всё заработало.
Удалил свой предыдущий пост.

На всякий случай (вдруг кому пригодится), итоговая версия java-скрипта (здесь формируем/и проверяем подпись):
Цитата:

package cryptopro.jcp.example;

import ru.CryptoPro.JCP.Key.GostPublicKey;
import ru.CryptoPro.JCP.Key.PublicKeySpec;
import ru.CryptoPro.JCP.Sign.GostElSign2012_256;
import ru.CryptoPro.JCP.JCP;

import javax.xml.bind.DatatypeConverter;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.MessageDigest;

import java.io.Console;
import java.nio.charset.Charset;
import java.io.BufferedWriter;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.Files;
import java.io.IOException;

public class CertificateService {

private void declare_byte_array(byte[] b, StringBuilder sb){
for(int i=0;i<b.length;++i) {
String bi=String.format("%02X", b[i]);
sb.append("0x");
sb.append(bi);
if(i==(b.length-1)) sb.append("};"); else sb.append(", ");
}
sb.append("\n");
}

public static void main(String[] args) throws Exception {

java.security.Security.addProvider(new JCP());

KeyPairGenerator kg = KeyPairGenerator.getInstance(JCP.GOST_EL_2012_256_NAME);
KeyPair keyPair = kg.genKeyPair();

String dataToSign = "The quick brown fox jumps over the lazy dog";

System.out.println("Data to Sign : " + dataToSign);
System.out.println("Data to Sign [hex]: " + DatatypeConverter.printHexBinary(dataToSign.getBytes()));
System.out.println();

System.out.println("Public Key CSP BLOB: " + DatatypeConverter.printHexBinary(keyPair.getPublic().getEncoded()));
System.out.println("Public Key RAW: " + DatatypeConverter.printHexBinary(((PublicKeySpec) ((GostPublicKey) keyPair.getPublic()).getSpec()).encode()));

CertificateService certificateService = new CertificateService();

System.out.println();
System.out.println("Signing...");
byte[] sign = certificateService.Sign(JCP.RAW_CRYPTOPRO_SIGN_2012_256_NAME, keyPair.getPrivate(), dataToSign.getBytes());

System.out.println("Signature: " + DatatypeConverter.printHexBinary(sign));

System.out.println();
System.out.println("Verifying Signature");
System.out.println("Verification Algorithm: " + JCP.RAW_CRYPTOPRO_SIGN_2012_256_NAME);

boolean isSignatureValid = certificateService.Verify(
JCP.RAW_CRYPTOPRO_SIGN_2012_256_NAME,
keyPair.getPublic(),
dataToSign.getBytes(),
sign);

System.out.println("Signature Valid? " + isSignatureValid);

//формирование инклуда для c-файла
Charset charset = Charset.forName("UTF-8");
StringBuilder sb = new StringBuilder();
sb.append("unsigned char data[]={");
byte[] b = dataToSign.getBytes();
certificateService.declare_byte_array(b,sb);
sb.append("int data_len="); sb.append(String.format("%d", b.length));sb.append(";\n");
sb.append("unsigned char pub_key[64]={");
b = ((PublicKeySpec) ((GostPublicKey) keyPair.getPublic()).getSpec()).encode();
certificateService.declare_byte_array(b,sb);
sb.append("unsigned char signature[64]={");
b = sign;
certificateService.declare_byte_array(b,sb);
String s=sb.toString();
BufferedWriter writer = null;
try {
Path path = Paths.get("./csp_test.inc");
writer = Files.newBufferedWriter(path, charset);
writer.write(s, 0, s.length());
} catch (IOException x) {
System.err.format("IOException: %s%n", x);
} finally {
if (writer != null) writer.close();
}

}

private byte[] Sign(String algorithmName, PrivateKey privateKey, byte[] data) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {

MessageDigest digest = MessageDigest.getInstance(JCP.GOST_DIGEST_2012_256_NAME);
digest.update(data);
byte [] hash = digest.digest();
System.out.println("Hash :" + DatatypeConverter.printHexBinary(hash));
Signature sig = Signature.getInstance(algorithmName);
sig.initSign(privateKey);
sig.update(hash);

System.out.println("Signature Algorithm: " + sig.getAlgorithm());
System.out.println("Signature Provider Name: " + sig.getProvider().getName());
System.out.println("Signature Provider Info: " + sig.getProvider().getInfo());
System.out.println("Signature Params: " + sig.toString());
return sig.sign();
}

private boolean Verify(String algorithmName, PublicKey publicKey, byte[] data, byte[] signature) throws Exception {
MessageDigest digest = MessageDigest.getInstance(JCP.GOST_DIGEST_2012_256_NAME);
digest.update(data);
byte [] hash = digest.digest();
Signature sig = Signature.getInstance(algorithmName);
sig.initVerify(publicKey);
sig.update(hash);
return sig.verify(signature);
}
}


и си-файла, где проверяем подпись на CSP:

Цитата:

//если нижеследующий дефайн определен, то исходные данные инклудятся из файла ./csp_test.inc
//если не определен, то берутся вшитые в код данные, на которых подпись проверяется
#define USE_CSP_TEST_INC

//если нижеследующий дефайн определен, то используются самописные функции импорта ключа
//ели не определен, то делается "хитро" - генерится пара, экспортируется паблик, на его место в блобе
//записывается новый паблик, на котором будем проверять подпись
#define USE_OUR_OWN_IMPORT

#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>
#include <WinCryptEx.h>

#ifdef _WIN32
#pragma warning( push )
#pragma warning( disable : 4996 )
#endif

#define CONTAINER_256 "\\\\.\\REGISTRY\\test_cont_"

unsigned char PIN_TO_CONT[]={'1','1','1','1','1','1','1','1','\0'};

HCRYPTPROV hProv = 0;
HCRYPTHASH hHash = 0;
HCRYPTKEY hKey = 0;
HCRYPTKEY hPubKey = 0;
BYTE *pbBuffer=NULL;

static void CleanUp(void)
{
if(pbBuffer)free(pbBuffer);
if(hHash) CryptDestroyHash(hHash);
if(hKey) CryptDestroyKey(hKey);
if(hPubKey) CryptDestroyKey(hPubKey);
if(hProv) CryptReleaseContext(hProv, 0);
}

static void HandleError(const char *s, long line)
{
DWORD err = GetLastError();
printf("Error number : 0x%x\n", err);
printf("[L:%ld] Error description: %s\n", line,s);
CleanUp();
if(!err) err = 1;
exit(err);
}

#ifndef CERT_ENCODING_TYPE
#define CERT_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
#endif

static int EncodeObject(LPCSTR lpszStructType, const void *pvStructInfo, LPBYTE *pbEncoded, LPDWORD pcbEncoded){

if(!CryptEncodeObject(
CERT_ENCODING_TYPE,
lpszStructType,
pvStructInfo,
NULL,
pcbEncoded))
{
HandleError("Can't EncodeObject",__LINE__);
}

*pbEncoded = (BYTE *)malloc(*pcbEncoded);

if(!CryptEncodeObject(
CERT_ENCODING_TYPE,
lpszStructType,
pvStructInfo,
*pbEncoded,
pcbEncoded))
{
HandleError("Can't EncodeObject",__LINE__);
}

return 1;
}

//импортировать открытый ключ
int ImportPublicKey(LPBYTE pbKey, LPBYTE pbPubKeyBlob, DWORD * pcbPubKeyBlobLen){

CRYPT_ATTRIBUTE blob;
LPBYTE pbPKParam = NULL;
LPBYTE pbDgParam = NULL;
DWORD cbEncoded = 0;
BYTE pklen;
BYTE dglen;
BYTE OF_TAG = 2;
BYTE OF_LEN = 3;
LPBYTE pbkeyblob = NULL;
DWORD cbkeyblob;
LPBYTE ptr = NULL;
CRYPT_PUBKEY_INFO_HEADER keyheader;
LPBYTE hash_oid=szOID_CP_GOST_R3411_12_256;

keyheader.BlobHeader.bType = PUBLICKEYBLOB;
keyheader.BlobHeader.bVersion = BLOB_VERSION;
keyheader.BlobHeader.reserved = 0;
keyheader.BlobHeader.aiKeyAlg = CALG_GR3410_12_256;

keyheader.KeyParam.Magic = GR3410_1_MAGIC;
keyheader.KeyParam.BitLen = 64*8;

blob.pszObjId = szOID_GostR3410_2001_CryptoPro_A_ParamSet;
blob.cValue = 0;
blob.rgValue = NULL;
if(!EncodeObject(
PKCS_ATTRIBUTE,
&blob,
&pbPKParam,
&cbEncoded
))return 0;
pklen = pbPKParam[OF_LEN]+2; // +tag+len

blob.pszObjId = hash_oid;
blob.cValue = 0;
blob.rgValue = NULL;
if(!EncodeObject(
PKCS_ATTRIBUTE,
&blob,
&pbDgParam,
&cbEncoded
))return 0;
dglen = pbDgParam[OF_LEN]+2; // +tag+len

cbkeyblob = sizeof(keyheader)+2+pklen+dglen+64;
pbkeyblob = (BYTE *)malloc(cbkeyblob);
ptr = pbkeyblob;
memcpy(ptr, &keyheader, sizeof(keyheader)); ptr += sizeof(keyheader);
ptr[0] = 0x30; // set of
ptr[1] = pklen+dglen; ptr += 2;
memcpy(ptr, pbPKParam+OF_TAG, pklen); ptr += pklen;
memcpy(ptr, pbDgParam+OF_TAG, dglen); ptr += dglen;
memcpy(ptr, pbKey, 64);
memcpy(pbPubKeyBlob,pbkeyblob,cbkeyblob);
*pcbPubKeyBlobLen=cbkeyblob;
if(pbkeyblob) free(pbkeyblob);
if(pbPKParam) free(pbPKParam);
if(pbDgParam) free(pbDgParam);

return 1;
}

#define GR3411LEN 32

int main(){

#ifdef USE_CSP_TEST_INC
#include "./csp_test.inc"
#else
unsigned char data[]={0x1B, 0xF4, 0x11, 0x33, 0x55, 0x77, 0x22, 0x88, 0x75, 0x47, 0x73, 0x06, 0x28, 0x02, 0x48, 0x98};
int data_len=16;
unsigned char pub_key[64]={0xED, 0x76, 0x01, 0xF4, 0x8B, 0xE6, 0xDA, 0xCE, 0x62, 0x7C, 0x59, 0x7A, 0x59, 0x37, 0xC8, 0x3E, 0x6B, 0x86, 0xB5, 0x96, 0xA8, 0x57, 0xE0, 0xCF, 0x78, 0x56, 0x47, 0x88, 0xC6, 0x71, 0x55, 0x64, 0xA3, 0xEC, 0x5A, 0x93, 0x81, 0xAD, 0xC2, 0x65, 0x8F, 0x98, 0x82, 0x00, 0x73, 0xA5, 0x78, 0x0F, 0xA7, 0x25, 0xE5, 0x6C, 0x43, 0xC9, 0xB2, 0x02, 0x16, 0xA9, 0xA2, 0x43, 0x84, 0xA5, 0x4A, 0x75};
unsigned char signature[64]={0xD6, 0xB7, 0x8F, 0x44, 0x19, 0xB9, 0x8B, 0x2C, 0x3E, 0x04, 0xB1, 0xBD, 0x86, 0xD3, 0x40, 0xCB, 0x57, 0x43, 0x35, 0xA6, 0x22, 0x0D, 0xD8, 0xB4, 0x2A, 0xCB, 0xC5, 0xA1, 0x85, 0xDD, 0xD4, 0x6F, 0xE2, 0x9A, 0xB8, 0x52, 0xE4, 0xCB, 0xB3, 0x41, 0x1D, 0x4A, 0xCA, 0xA0, 0xF1, 0x5C, 0x41, 0x2C, 0x91, 0x2E, 0x01, 0x77, 0x17, 0x28, 0x29, 0x14, 0x4E, 0x65, 0xDA, 0x1A, 0xF9, 0x74, 0x2D, 0xDF};
#endif

DWORD dwBufferLen;

BYTE pbSignature[64];
DWORD dwSigLen;
BYTE pbKeyBlob[2048];
DWORD dwBlobLen=2048;

BYTE rgbHash[GR3411LEN];
DWORD cbHash = 0;
unsigned i;

// Получение дескриптора контекста криптографического провайдера
if(CryptAcquireContext(&hProv, CONTAINER_256, NULL, PROV_GOST_2012_256, 0)) {
printf("Container %s exists\n", CONTAINER_256);
CryptSetProvParam(hProv, PP_KEYEXCHANGE_PIN, PIN_TO_CONT, 0);
if(!CryptAcquireContext(&hProv, CONTAINER_256, NULL, PROV_GOST_2012_256, CRYPT_DELETEKEYSET)) {
HandleError("Can't delete Container",__LINE__);
}
printf("Container %s deleted\n", CONTAINER_256);
}
//создаем новый контейнер
if(!CryptAcquireContext(&hProv,CONTAINER_256, NULL, PROV_GOST_2012_256, CRYPT_NEWKEYSET)) {
HandleError("Could not create a new key container",__LINE__);
}
printf("A new key container has been created\n");

//установка ПИНа на контейнер
CryptSetProvParam(hProv, PP_KEYEXCHANGE_PIN, PIN_TO_CONT, 0);

if(!CryptSetProvParam(hProv, PP_SIGNATUREOID, (LPBYTE)szOID_GostR3410_2001_CryptoPro_A_ParamSet, 0)) {
HandleError("Could not set hash_oid",__LINE__);
}

// http://cpdn.cryptopro.ru...44f9e75b9888e0e4db3.html
//
// KP_HASHOID
// Идентификатор функции хэширования. Строка, заканчивающаяся нулем.
// Не допускается задавать для объектов типа
// ... CALG_GR3411_2012_256 / CALG_GR3411_2012_512
//
// if(!CryptSetProvParam(hProv, PP_HASHOID, (LPBYTE)szOID_CP_GOST_R3411_12_256, 0))
// HandleError("Could not set hash_oid",__LINE__);

if(!CryptSetProvParam(hProv, PP_CIPHEROID, (LPBYTE)szOID_Gost28147_89_TC26_Z_ParamSet, 0)) {
HandleError("Could not set cipher_oid",__LINE__);
}

// Формирование хеша по данным, полученным извне
dwBufferLen=data_len;
pbBuffer = (BYTE *)malloc(dwBufferLen);
if(!pbBuffer)
HandleError("Out of memory",__LINE__);

memcpy(pbBuffer,data,dwBufferLen);

if(CryptCreateHash(
hProv,
CALG_GR3411_2012_256,
0,
0,
&hHash)
) {
printf("Hash object created\n");
} else {
HandleError("Error during CryptCreateHash",__LINE__);
}

// if(!CryptSetHashParam(hHash, KP_HASHOID, (LPBYTE)szOID_CP_GOST_R3411_12_256, 0)) {
// HandleError("Could not set hash_oid",__LINE__);
// }

if(CryptHashData(
hHash,
pbBuffer,
dwBufferLen,
0)
) {
printf("The data buffer has been hashed\n");
} else {
HandleError("Error during CryptHashData",__LINE__);
}

//извлечем хеш
cbHash = GR3411LEN;
if(!CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0)) {
HandleError("CryptGetHashParam failed",__LINE__);
}
printf("\nHash :");
for(i=0;i<cbHash;++i)printf("%02X",rgbHash[i]);
printf("\n");

//импорт паблика

#ifdef USE_OUR_OWN_IMPORT
if(!ImportPublicKey(pub_key, pbKeyBlob, &dwBlobLen))
HandleError("CryptGetHashParam failed",__LINE__);
#else
// Контекст с ключевым контейнером доступен,
// попытка получения дескриптора ключа подписи
if(CryptGetUserKey(
hProv,
AT_SIGNATURE,
&hKey)
)
{
printf("A signature key is available\n");
} else {
printf("No signature key is available\n");
// контейнер не содержит ключа подписи
if(!(GetLastError() == (DWORD)NTE_NO_KEY))
HandleError("An error other than NTE_NO_KEY getting signature key",__LINE__);

// Создание ключевой пары AT_SIGNATURE
printf("The signature key does not exist\n");
printf("Creating a signature key pair...\n");

if(!CryptGenKey(
hProv,
AT_SIGNATURE,
CRYPT_EXPORTABLE,
&hKey)
) {
HandleError("Error occurred creating a signature key",__LINE__);
}

printf("Signature key pair created\n");
}

printf("The signature key has been acquired\n");

if(CryptExportKey(
hKey,
0,
PUBLICKEYBLOB,
0,
NULL,
&dwBlobLen)
) {
printf("Size of the BLOB for the public key determined\n");
} else {
HandleError("Error computing BLOB length",__LINE__);
}

if(CryptExportKey(
hKey,
0,
PUBLICKEYBLOB,
0,
pbKeyBlob,
&dwBlobLen)
) {
printf("Contents have been written to the BLOB\n");
} else {
HandleError("Error during CryptExportKey",__LINE__);
}

memcpy((BYTE *)(pbKeyBlob+dwBlobLen-64),pub_key,64);

#endif

if(CryptImportKey(
hProv,
pbKeyBlob,
dwBlobLen,
0,
0,
&hPubKey)
) {
printf("The key has been imported\n");
} else {
HandleError("Public key import failed",__LINE__);
}

//проверка подписи
dwSigLen=64;
memcpy(pbSignature,signature,dwSigLen);

if(CryptVerifySignature(
hHash,
pbSignature,
dwSigLen,
hPubKey,
NULL,
0)
) {
printf("The signature has been verified\n");
} else {
HandleError("Signature not validated!",__LINE__);
}

CleanUp();

return 0;

}
#ifdef _WIN32
#pragma warning( pop )
#endif


Спасибо!

Вопрос можно закрывать.

Отредактировано пользователем 9 октября 2019 г. 20:34:59(UTC)  | Причина: Не указана

Offline al  
#5 Оставлено : 10 октября 2019 г. 8:11:38(UTC)
al

Статус: Активный участник

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

Сказал(а) «Спасибо»: 16 раз
Поблагодарили: 1 раз в 1 постах
Скажите, пожалуйста, а где можно посмотреть документацию на JCP - что-то наподобие cpdn.
Меня интересуют константы JCP, например (если я все правильно понял):

JCP.RAW_CRYPTOPRO_SIGN_2012_256_NAME - в функцию Signature.update подается готовый хеш, форматы данных совместимы с CSP

JCP.RAW_GOST_SIGN_2012_256_NAME - в функцию Signature.update подается готовый хеш, форматы данных не совместимы c CSP

JCP.GOST_SIGN_2012_256_NAME - в функцию Signature.update подаются данные для хеширования, функция производит хеширование сама, форматы данных не совместимы c CSP

наверняка есть еще что-то типа
JCP.CRYPTOPRO_SIGN_2012_256_NAME (где как и выше, функцию Signature.update подаются данные для хеширования, функция производит хеширование сама, форматы данных совместимы c CSP)

Что значит "форматы данных совместимы с CSP" я уже понял - проверил подпись из JCP в CSP.

А что означает "не совместимы" ? Что нужно сделать, чтобы такая подпись проверилась в CSP ?
Перевернуть данные ? (например, перевернуть половинки подписи, переведя из бигэндиан в литлэндиан).

Offline al  
#6 Оставлено : 10 октября 2019 г. 8:51:21(UTC)
al

Статус: Активный участник

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

Сказал(а) «Спасибо»: 16 раз
Поблагодарили: 1 раз в 1 постах
Про документацию вопрос снимается, я невнимательно смотрел - в дистрибутиве есть /javadoc.
Прошу прощения. Но вопрос по совместимости форматов данных (ключей, подписи) остается.
Offline Санчир Момолдаев  
#7 Оставлено : 10 октября 2019 г. 9:08:21(UTC)
Санчир Момолдаев

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

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

Сказал(а) «Спасибо»: 88 раз
Поблагодарили: 226 раз в 213 постах
Все верно.
Различаются только порядком байт.
можете подписать в RAW_GOST_SIGN_2012_256_NAME
И инвертировать порядок байт. Тогда подпись в csp проверится.
Техническую поддержку оказываем тут
Наша база знаний
thanks 1 пользователь поблагодарил Санчир Момолдаев за этот пост.
al оставлено 10.10.2019(UTC)
Offline Санчир Момолдаев  
#8 Оставлено : 10 октября 2019 г. 9:10:33(UTC)
Санчир Момолдаев

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

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

Сказал(а) «Спасибо»: 88 раз
Поблагодарили: 226 раз в 213 постах
Большие подписи в формате cms и cades с ними не надо этого делать
Техническую поддержку оказываем тут
Наша база знаний
Offline al  
#9 Оставлено : 10 октября 2019 г. 9:18:06(UTC)
al

Статус: Активный участник

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

Сказал(а) «Спасибо»: 16 раз
Поблагодарили: 1 раз в 1 постах
Спасибо, буду пробовать.
Offline al  
#10 Оставлено : 19 октября 2019 г. 11:50:04(UTC)
al

Статус: Активный участник

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

Сказал(а) «Спасибо»: 16 раз
Поблагодарили: 1 раз в 1 постах
Прошу прощения, попробовал в тот же день - всё работает ( со всеми вариантами, и в обе стороны JCP <--> CSP ).
Тему можно закрывать/архивировать.
Спасибо.
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.