Статус: Участник
Группы: Участники
Зарегистрирован: 27.09.2016(UTC) Сообщений: 16 Откуда: Краснодар Поблагодарили: 4 раз в 1 постах
|
Не победил тему, выкладываю код плюс последовательность действий 1. Инициализируем крипто-провайдер Код:
Win32Check(CryptAcquireContext(@hProv, 'MyContainer', '', PROV_GOST_2001_DH, 0));
2. Шифруем данные и ключ
Код:
begin
memStream := TMemoryStream.Create;
memStream.LoadFromFile('d:\fss.cer');
// получение сертификата
FCertContext := CertCreateCertificateContext(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, memStream.Memory, memStream.Size);
// импорт информации по открытому ключу
Win32Check(CryptImportPublicKeyInfoEx(
hProv,
X509_ASN_ENCODING or PKCS_7_ASN_ENCODING,
@FCertContext.pCertInfo.SubjectPublicKeyInfo,
CALG_GR3410EL,
0,
nil,
@FPublicKey));
// экспорт открытого ключа получателя в BLOB
// экспорт открытого ключа получателя в BLOB
Win32Check(CryptExportKey(FPublicKey, 0, PUBLICKEYBLOB, 0, nil, @FKeyLenNeed));
SetLength(FRecipientPublicKeyBlob, FKeyLenNeed);
Win32Check(CryptExportKey(FPublicKey, 0, PUBLICKEYBLOB, 0, @FRecipientPublicKeyBlob[0], @FKeyLenNeed));
Win32Check(CryptGetUserKey(hProv, AT_KEYEXCHANGE, @FPrivateKey));
Win32Check(CryptExportKey(FPrivateKey, 0, PUBLICKEYBLOB, 0, nil, @FKeyLenNeed));
SetLength(FSenderPublicKeyBlob, FKeyLenNeed);
Win32Check(CryptExportKey(FPrivateKey, 0, PUBLICKEYBLOB, 0, @FSenderPublicKeyBlob[0], @FKeyLenNeed));
// получаем значение открытого ключа отправителя из PUBLICKEYBLOB
publicKey := Copy(FSenderPublicKeyBlob, Length(FSenderPublicKeyBlob) - 64, 64);
// получение ключа согласования импортом открытого ключа получателя
// на эфемерном ключе
Win32Check(CryptImportKey(hProv, @FRecipientPublicKeyBlob[0], Length(FRecipientPublicKeyBlob), FPrivateKey, 0, @FAgreeKey));
// установление PRO_EXPORT алгоритма ключа согласования
algProExport := CALG_PRO_EXPORT;
Win32Check(CryptSetKeyParam(FAgreeKey, KP_ALGID, @algProExport, 0));
// создание случайного сессионного ключа
Win32Check(CryptGenKey(hProv, CALG_G28147, CRYPT_EXPORTABLE, @FSessionKey));
// экспорт сессионного ключа в BLOB
Win32Check(CryptExportKey(FSessionKey, FAgreeKey, SIMPLEBLOB, 0, nil, @FKeyLenNeed));
SetLength(FSessionKeyBlob, FKeyLenNeed);
Win32Check(CryptExportKey(FSessionKey, FAgreeKey, SIMPLEBLOB, 0, @FSessionKeyBlob[0], @FKeyLenNeed));
sessionSV := Copy(FSessionKeyBlob, 16, 8);
sessionKey := Copy(FSessionKeyBlob, 24, 32);
sessionMAC := Copy(FSessionKeyBlob, 56, 4);
transport :=
[
$30, $81, $A4, $30, $28, $04, $20,
$5E, $70, $73, $5F, $36, $98, $B4, $35, $5B, $45, $03, $7F, $A7, $CE, $00, $97, // шифрованный (7,32
$11, $5E, $45, $C6, $58, $59, $94, $72, $66, $42, $06, $3F, $72, $3A, $B4, $9E, // ключ
$04, $04,
$8C, $86, $08, $84, // MAC (41,4)
$A0, $78, $06, $07, $2A, $85, $03, $02, $02, $1F, $01, $A0, $63, $30, $1C, $06,
$06, $2A, $85, $03, $02, $02, $13, $30, $12, $06, $07, $2A, $85, $03, $02, $02,
$24, $00, $06, $07, $2A, $85, $03, $02, $02, $1E, $01, $03, $43, $00, $04, $40,
$2D, $C3, $FD, $F6, $9C, $91, $3D, $CC, $B6, $53, $26, $8E, $51, $2F, $5E, $DD, // (93, 64) публичный ключ
$E4, $1A, $5D, $B3, $58, $3C, $DF, $60, $68, $F2, $48, $A2, $B0, $B8, $DE, $7B,
$C9, $AA, $20, $E3, $CF, $63, $DF, $5F, $39, $55, $21, $E0, $A0, $DD, $85, $3E,
$0A, $AF, $44, $FA, $49, $3C, $D5, $4C, $A8, $04, $8D, $1D, $9C, $41, $85, $FB,
$04, $08,
$76, $EE, $B4, $6B, $1B, $10, $36, $EB // UKM (159,8)
];
for i := 0 to 31 do
transport[i + 7] := Byte(sessionKey[i]);
for i := 0 to 3 do
transport[i + 41] := Byte(sessionMAC[i]);
for i := 0 to 63 do
transport[i + 93] := Byte(publicKey[i]);
for i := 0 to 7 do
transport[i + 159] := Byte(sessionSV[i]);
// получение вектора инициализации
Win32Check(CryptGetKeyParam(FSessionKey, KP_IV, nil, @FKeyLenNeed, 0));
SetLength(initVector, FKeyLenNeed);
Win32Check(CryptGetKeyParam(FSessionKey, KP_IV, @initVector[0], @FKeyLenNeed, 0));
keyMode := CRYPT_MODE_CBC;
Win32Check(CryptSetKeyParam(FSessionKey, KP_MODE, @keyMode, 0));
encryptData := TEncoding.Default.GetBytes(ASourceData);
FSourceDataLen := Length(encryptData);
FEncryptDataLen := FSourceDataLen;
CryptEncrypt(FSessionKey, 0, true, 0, nil, @FEncryptDataLen, 0);
SetLength(encryptData, FEncryptDataLen);
CryptEncrypt(FSessionKey, 0, true, 0, @encryptData[0], @FSourceDataLen, FEncryptDataLen);
AEncryptData := TEncoding.Utf8.GetString(TNetEncoding.Base64.Encode(initVector + encryptData)); <-- Зашифрованные данные
AEncryptKey := TEncoding.Utf8.GetString(TNetEncoding.Base64.Encode(transport)); <-- Зашифрованный ключ
end;
2. Готовим запрос xml-envelope, отсылаем его в ФСС, получаем ответ шифрованный 3 Из ответа ФСС берем ASN и вырезаем из него: APublicKey, ASessionSV, ASessionKey, ASessionMAC 4 Полученные APublicKey, ASessionSV, ASessionKey, ASessionMAC передаем в код дешифровки
Код:
Win32Check(CryptGetUserKey(hProv, AT_KEYEXCHANGE, @FPrivateKey));
// сборка PublicKey BLOB из статической части и открытого ключа
abPublicKeyBlob :=
[
$06, // bType = PUBLICKEYBLOB
$20, // bVersion = 0x20
$00, $00,
$23, $2E, $00, $00, // KeyAlg = ALG_SID_GR3410EL
$4D, $41, $47, $31, //Magic = GR3410_1_MAGIC
$00, $02, $00, $00, // BitLen = 512
// bASN1GostR3410_94_PublicKeyParameters
$30, $12,
$06, $07 ,
$2A, $85, $03, $02, $02, $24, $00,
$06, $07,
$2A, $85, $03, $02, $02, $1E, $01
] + APublicKey;
// получение ключа согласования импортом открытого ключа отправителя
// на закрытом ключе
Win32Check(CryptImportKey(hProv, @abPublicKeyBlob[0], Length(abPublicKeyBlob), FPrivateKey, 0, @FAgreeKey));
// установление PRO_EXPORT алгоритма ключа согласования
algProExport := CALG_PRO_EXPORT;
Win32Check(CryptSetKeyParam(FAgreeKey, KP_ALGID, @algProExport, 0));
// сборка SessionKey BLOB из статической части и параметров сессионного ключа
abSessionKeyBlob :=
[
$01, // bType = SIMPLEBLOB
$20, // bVersion = 0x20
$00,$00 ,
$1E,$66 ,$00 ,$00, // KeyAlg = CALG_G28147
$FD,$51 ,$4A ,$37, // Magic = G28147_MAGIC
$1E,$66 ,$00 ,$00] // EncryptKeyAlgId = CALG_G28147
+ ASessionSV + ASessionKey + ASessionMAC +
[// ASN.1 Sequence + OID Header
$30 ,$09 ,$06 ,$07,
// OID_GOST_R28147_89_CryptoPro_A_ParamSet 1.2.643.2.2.31.1
$2A ,$85 ,$03 ,$02 ,$02 ,$1F ,$01
];
// получение сессионного ключа импортом зашифрованного сессионного ключа
// на ключе согласования
Win32Check(CryptImportKey(hProv, @abSessionKeyBlob[0], Length(abSessionKeyBlob), FAgreeKey, 0, @FSessionKey)); <-- ПЛОХИЕ ДАННЫЕ!!!!!!!
С ошибкой на последнем вызове - ПЛОХИЕ ДАННЫЕ - ничего не могу пока сделать. Где может быть собака зарыта? То ли вручную неверно собираю, то ли что-то недоустанавливаю из параметров, то ли из ответа достаю неверные APublicKey, ASessionSV, ASessionKey, ASessionMAC.. Для начала просто правильность кода проверьте, пожалуйста. Отредактировано пользователем 4 июля 2018 г. 19:32:24(UTC)
| Причина: Не указана
|