использование Crypt_RSA phpseclib для шифрования кода подтверждения для банка

Мне необходимо отправить запрос в банк, который содержит код подтверждения $vk_mac в указанном строковом формате. Код должен быть хэшем SHA1 и RSA, зашифрованным с помощью моего открытого ключа и представленным в формате base64. К сожалению, пока безуспешно - банк мне выдает "Неверная подпись" и что всю инфу я получаю.

У меня есть это:

$rsa = new Crypt_RSA();
$rsa->loadKey(file_get_contents("private_key.pem"));
$rsa->loadKey($rsa->getPublicKey());
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$encrypted = $rsa->encrypt(sha1($vk_mac));
$vk_mac = base64_encode($encrypted);

private_key.pem здесь мой закрытый ключ в виде простого текста. Я безуспешно пытался установить режим шифрования CRYPT_RSA_ENCRYPTION_OAEP. Я на 99,9% уверен, что начальная строка $vk_mac отформатирована правильно и содержит все необходимые данные.

Кто-нибудь знает, что я могу делать неправильно? Спасибо.


Изменить:

Я изменил код на этот (где vk_mac — начальная отформатированная строка, которую необходимо подписать, а private_key.pem — мой декодированный закрытый ключ):

$rsa = new Crypt_RSA();
$rsa->loadKey(file_get_contents("private_key.pem"));
$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
$hashed = $rsa->hash->hash($vk_mac);
$encrypted = $rsa->sign($hashed);
$signature = base64_encode($encrypted);

Я могу сказать, что сгенерированная подпись верна, поскольку, когда я это делаю:

$rsa->loadKey($rsa->getPublicKey());
$verified = $rsa->verify($hashed, base64_decode($signature));

$verified возвращает ИСТИНА.

Однако банк отвечает: «Неверная подпись». Есть еще идеи?

Изменить:

Технические характеристики

Расчет управляющего кода VK_MAC

VK_MAC, для электронной подписи, используемой в запросе, для проверки и подтверждения используемой версии алгоритма, указанной в параметре VK_VERSION. На этот раз используется версия 008. VK_MAC представлен как параметр запроса в кодировке BASE64.

Версия 008

Значение функции MAC008 вычисляется с использованием алгоритма открытого ключа RSA. Также учитываются значения пустых полей – «000».

MAC008(x1,x2,…,xn) := RSA(SHA-1(p(x1)|| x1|| p(x2 )|| x2 || … ||p(xn)||xn),d, н)

Где: || — операция добавления строки x1, x2, …, xn — параметры запроса p — функция длины параметра. Длина — это число в виде трехзначной строки, d — секретный показатель RSA, n — модуль RSA. Подпись рассчитывается в соответствии со стандартом PKCS1 (RFC 2437).


person donk    schedule 20.05.2011    source источник
comment
Crypt_RSA — мертвый проект. Вместо этого вам следует переключиться на mcrypt или openssl.   -  person Marc B    schedule 20.05.2011
comment
Я посмотрю на них. Но все же - нужный результат должен быть достигнут, не так ли? Стандарт шифрования тот же.   -  person donk    schedule 21.05.2011
comment
Марк Б путает Crypt_RSA PEAR с Crypt_RSA phpseclib. Crypt_RSA в phpseclib очень даже жив. Новый релиз был сделан всего две недели назад, фактически 9 мая. mcrypt не поддерживает RSA, а расширение openssl просто тупое. Я бы придерживался phpseclib.   -  person    schedule 21.05.2011
comment
@donkapone: Ваше описание требований очень неточное. Вы, кажется, смешиваете подпись и шифрование. Что вам действительно нужно сделать, так это запросить подробные спецификации вместе с тестовыми векторами.   -  person Accipitridae    schedule 22.05.2011
comment
Теперь вы подписываете хэш. Подписи RSA также используют хэш. Следовательно, вы эффективно хешируете дважды, что мне кажется очень странным. Серьезно, я не могу понять, почему вы не спрашиваете характеристики. При таком методе проб и ошибок у вас нет абсолютно никаких гарантий безопасной реализации.   -  person Accipitridae    schedule 23.05.2011
comment
У меня есть спецификации, но они очень расплывчаты. Я добавил их.   -  person donk    schedule 23.05.2011


Ответы (3)


Что, если вы попробуете $rsa->sign()? PKCS#1 не подписывает, просто шифруя хэш, и если ваш банк использует совместимое решение RSA, они, вероятно, тоже этого не делают.

person Community    schedule 21.05.2011
comment
Вы пытались выполнить $rsa-›setSignatureMode(CRYPT_RSA_ENCRYPTION_PKCS1)? По умолчанию Crypt_RSA делает подписи PSS. Они обеспечивают лучшую безопасность, но не так широко используются, как подписи PKCS1. - person ; 21.05.2011
comment
$rsa-›encrypt(sha1($vk_mac, true)). Попробуй это. sha1() по умолчанию возвращает версию хеша в шестнадцатеричном коде. - person ; 21.05.2011
comment
Спасибо за все ваши ответы и помощь. Однако это не сработало. На данный момент я пытался зашифровать строку, используя свой закрытый ключ или открытый ключ банка. Однако ни один из вариантов не сработал. - person donk; 21.05.2011
comment
Я действительно не понимаю, как я могу реализовать показанное решение в своем коде. - person donk; 22.05.2011
comment
Вам нужно было бы изменить Crypt/RSA.php в соответствии с этим сообщением. Найдите строку, которую он просит вас найти, и замените ее той, на которую он просит вас заменить ее. Я думаю, это спорный вопрос, поскольку проблема была решена, но это была идея, стоящая за моей публикацией ссылки. - person ; 23.05.2011

Код был почти правильным, хотя мне не нужно было его снова хэшировать (спасибо @Accipitridae).

Решение заключалось в том, что идентификатор продавца должен был быть в верхнем, а не в нижнем регистре, как предусмотрено. В спецификации нигде не сказано, что он должен быть также в верхнем регистре. Хороший.

person donk    schedule 23.05.2011

Как упоминалось выше, вы можете легко сделать это с помощью openssl. Ниже показано, как я бы это сделал.

$hashed = sha1($vk_mac);
openssl_public_encrypt($vk_mac, $encrypted, ($pubkey));
$vk_mac = base6$_encode($encrypted);

Прочтите документацию по openssl_public_encrypt, чтобы узнать больше.

person Steven W    schedule 20.05.2011
comment
Итак, вы должны сначала зашифровать vk_mac (что включает в себя рандомизацию), а затем вычислить хэш зашифрованного текста. Теперь вы можете сказать нам, что приемник делает с этим? - person Accipitridae; 22.05.2011
comment
@accipitridae Я вижу ошибку, которую я сделал, и отредактировал код, чтобы отразить ее. Я должен был перепроверить, спасибо, что поймали мою ошибку. Кажется, что проблема авторов заключается в том, что сервер не шифрует и не кодирует код подтверждения. - person Steven W; 23.05.2011
comment
Все еще не имеет большого смысла для меня. Вы должны либо зашифровать с помощью открытого ключа получателя, либо подписать с помощью закрытого ключа отправителя. Но вы, кажется, шифруете закрытым ключом. Конечно, пока ОП не знает, что он должен реализовать, ему трудно помочь. - person Accipitridae; 23.05.2011
comment
ох... как обидно. Я использовал код автора и нарезал его. В результате я не обращал внимания на частные или публичные. Ты прав. Автор, кажется, думает, что должен использоваться его открытый ключ. Усвоенный урок, помогая людям вычитывать. - person Steven W; 23.05.2011