Модераторы: skyboy, MoLeX, Aliance, ksnk
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Функция openssl_verify, проверка подписи 
V
    Опции темы
Prontit
Дата 13.12.2011, 14:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 87
Регистрация: 19.10.2011

Репутация: 1
Всего: 1



Здравствуйте!

GETом приходит строка запроса, необходимо ее проверить на подлинность

строка, например, такая

action=check&number=100001&amount=10.50&type=1&sign=5EB7E68A5140BC62FB1A50EAF1A589FD8B40B239B31B6AEE799C9DA1F396144F79DDC2D4332E655D3D0DE60E9BE3BF5EB62E026766554AAF7A0B7201E0BACA1A68E12FD12F32016CD48E452D76D3136078AB53BD878B23D88BCB705C5C9406184E0D6264D3D3709ECBDDA994EB5CAE8F81C2A64FC015C20572598B56DD58F689

нужно использовать rsa+sha1, делаю так:

Код

//исходная строка GET запроса   
$get_str = $_SERVER['QUERY_STRING']; 
    
//позиция параметра SIGN
$sign_place = strpos($get_str, "sign");

//строка без параметра SIGN
$string_wthout_sign = substr($get_str, 0, $sign_place - 1);

//Хеш строки запроса без SIGN
$string_hash = sha1($string_wthout_sign);

//строка SIGN
$string_sign = $_GET['sign']; 

//Открытый ключ для проверки
$public_key = <<<EOD
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDEPpPvdefdg/NpfoENZgem4rxE
JWJFX6pOP3fCyMuBAt7F5ieqnYLhREN9loR56ACJhA17lK3A6tt1bROxLGtFwv4L
hrXI+qjQiQHZIsJKW2waE2KQdI9jiSE+9vg+iIoAYHSFx029wvJQRQH9qHifDXfa
VWdYr5icleV7My9jiwIDAQAB
-----END PUBLIC KEY-----
EOD;

$ok = openssl_verify($string_wthout_sign, $string_hash, $public_key, OPENSSL_ALGO_SHA1);
echo "check #1: ";
if ($ok == 1) {
    echo "signature ok (as it should be)\n";    
} elseif ($ok == 0) {
    echo "bad (there's something wrong)\n";    
} else {
    echo "ugly, error checking signature\n";
}


Наверняка делаю какую-то глупость, первый раз с этим сталкиваюсь.

Есть пример реализации на Perl

Код

#Проверка подписи.
#!/usr/bin/perl
use strict;
use Crypt::OpenSSL::RSA;

#Строка с запросом
my $cmessage =
'action=check&number=22840&amount=1.26&type=0&sign=5B2360C1C867C63370EED02EC6F79F03F0709E2CF6A6054102444B5FB57662361BB212DF586E06113F44C908FC911137AAC9C726A98EC6C96370617FAE2F6F4325ED4894B4AE5D4760ED735CD284CB5861C6B092904B102C874A847B0972523222FAF4AA30188E52892AF31832C44213DEFC8187CB11563081CDDCCAA413264D';

#Разделим сообщение и подпись
my $message=$cmessage;
my $signature_hex=$cmessage;
undef $cmessage;
$message=~s/\&sign.*?$//;
$signature_hex=~s/^.*?\&sign\=(.*?)$/$1/sg;

#Преобразуем подпись из шестнадцатиричного представления в бинарный my $signature_bin=pack ("H*",$signature_hex);

#Прочтем открытый ключ
my $pub_key_string=`cat c_pub.pem`;

my $rsa_pub = Crypt::OpenSSL::RSA->new_public_key($pub_key_string);

if (!$rsa_pub->verify($message, $signature_bin)) {
        #ошибка проверки подписи
}
else
{
        #успешная проверка подписи
}


вот собственно и проблема. необходимо реализовать такую штуку на PHP.
делал по примеру http://www.php.net/manual/en/function.openssl-sign.php, но почему то не выходит ничего.

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

Заранее благодарю за помощь!
PM MAIL ICQ Skype   Вверх
Prontit
Дата 14.12.2011, 11:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 87
Регистрация: 19.10.2011

Репутация: 1
Всего: 1



вопрос настолько сложный/легкий или я что-то совсем не так делаю?  smile 

Это сообщение отредактировал(а) Prontit - 14.12.2011, 11:54
PM MAIL ICQ Skype   Вверх
ksnk
Дата 14.12.2011, 12:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прохожий
****


Профиль
Группа: Комодератор
Сообщений: 6855
Регистрация: 13.4.2007
Где: СПб

Репутация: 96
Всего: 386



не работал с opensll настолько.

Мне кажется, что public_key обязан быть бинарной строкой, а он текстовый. Вероятно, его для передачи упаковали base64. Нужно декодировать.

В Перловом примере public key берется из сертификата специальной функцией. Так что перевод на другой язык произведен не совсем корректно 


--------------------
Человеку свойственно ошибаться, программисту свойственно ошибаться профессионально ! user posted image
PM MAIL WWW Skype   Вверх
Prontit
Дата 14.12.2011, 12:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 87
Регистрация: 19.10.2011

Репутация: 1
Всего: 1



Цитата(ksnk @ 14.12.2011,  12:15)
не работал с opensll настолько.

Мне кажется, что public_key обязан быть бинарной строкой, а он текстовый. Вероятно, его для передачи упаковали base64. Нужно декодировать.

В Перловом примере public key берется из сертификата специальной функцией. Так что перевод на другой язык произведен не совсем корректно

попробовал base64_decode, получилась белеберда из ключа "@зAP9уСCр4mэ}Aи"

даже не знаю в какую сторону копать  smile очень странно, но вообще нет примеров по теме ключей, проверки и подписи
PM MAIL ICQ Skype   Вверх
bars80080
Дата 14.12.2011, 13:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прапор творюет
****
Награды: 1



Профиль
Группа: Завсегдатай
Сообщений: 12022
Регистрация: 5.12.2007
Где: Königsberg

Репутация: 71
Всего: 315



вообще, из документации
http://ru2.php.net/manual/ru/function.openssl-verify.php
int openssl_verify ( string $data , string $signature , mixed $pub_key_id [, int $signature_alg = OPENSSL_ALGO_SHA1 ] )
по аналогии с функциями с private ключом, видно, что должен передаваться всё-таки некий id

ниже пример:
Код

// fetch public key from certificate and ready it
$fp = fopen("/src/openssl-0.9.6/demos/sign/cert.pem", "r");
$cert = fread($fp, 8192);
fclose($fp);
$pubkeyid = openssl_get_publickey($cert);

// state whether signature is okay or not
$ok = openssl_verify($data, $signature, $pubkeyid);
if ($ok == 1) {
    echo "good";
} elseif ($ok == 0) {
    echo "bad";
} else {
    echo "ugly, error checking signature";
}
// free the key from memory
openssl_free_key($pubkeyid);


судя по документации http://ru2.php.net/manual/ru/function.open...-get-public.php (синоним openssl_get_publickey) id можно получить тремя способами:
Цитата

certificate can be one of the following:
1. an X.509 certificate resource
2. a string having the format file://path/to/file.pem. The named file must contain a PEM encoded certificate/private key (it may contain both).
3. A PEM formatted private key.

хотя в конце явно опечатка. стопудово там должен быть public key. впрочем проверить стоит оба

однако, меня удручает один комментарий ниже:

Цитата

Note this will read public keys from PEM formatted public keys as well: 

Код

<?php 
$key = <<<EOF 
-----BEGIN PUBLIC KEY----- 
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDXX/MsKEBLcLeKA1d/i7ufG1qs 
qS97xFkIRSeX3TwmHic843AfVrzoh2pZUeOvK9ZLZQpHSM7DoHMYDGD1273+FvZX 
Ypf5LiFtecfxko/Cku16zy6WAeCYVFjjlveBhwPmPCIk+qDRYeiIW05QE2XK+CuD 
nJ7sxxXIJSSgD3Jo5wIDAQAB 
-----END PUBLIC KEY----- 
EOF; 

print $key; 
$res = openssl_pkey_get_public($key); 
print_r(openssl_pkey_get_details($res)); 
?> 


Note that contrary to the documentation, openssl_pkey_get_details() will *not* read PEM directly, and you have to go through this step.


так что мне будет интересно, какие результаты получит топикстартер

Это сообщение отредактировал(а) bars80080 - 14.12.2011, 13:50
PM MAIL WWW   Вверх
Prontit
Дата 17.12.2011, 10:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 87
Регистрация: 19.10.2011

Репутация: 1
Всего: 1



Что-то пока никаких движений...даже не знаю в какую сторону копать. Вообще нет материалов на эту тему...
PM MAIL ICQ Skype   Вверх
Prontit
Дата 20.12.2011, 07:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 87
Регистрация: 19.10.2011

Репутация: 1
Всего: 1



взял за основу вот этот пример 

Код

<?php

$data = "Beeeeer is really good.. hic...";

// You can get a simple private/public key pair using:
// openssl genrsa 512 >private_key.txt
// openssl rsa -pubout <private_key.txt >public_key.txt

// IMPORTANT: The key pair below is provided for testing only.
// For security reasons you must get a new key pair
// for production use, obviously.

$private_key = <<<EOD
-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBANDiE2+Xi/WnO+s120NiiJhNyIButVu6zxqlVzz0wy2j4kQVUC4Z
RZD80IY+4wIiX2YxKBZKGnd2TtPkcJ/ljkUCAwEAAQJAL151ZeMKHEU2c1qdRKS9
sTxCcc2pVwoAGVzRccNX16tfmCf8FjxuM3WmLdsPxYoHrwb1LFNxiNk1MXrxjH3R
6QIhAPB7edmcjH4bhMaJBztcbNE1VRCEi/bisAwiPPMq9/2nAiEA3lyc5+f6DEIJ
h1y6BWkdVULDSM+jpi1XiV/DevxuijMCIQCAEPGqHsF+4v7Jj+3HAgh9PU6otj2n
Y79nJtCYmvhoHwIgNDePaS4inApN7omp7WdXyhPZhBmulnGDYvEoGJN66d0CIHra
I2SvDkQ5CmrzkW5qPaE2oO7BSqAhRZxiYpZFb5CI
-----END RSA PRIVATE KEY-----
EOD;
$public_key = <<<EOD
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANDiE2+Xi/WnO+s120NiiJhNyIButVu6
zxqlVzz0wy2j4kQVUC4ZRZD80IY+4wIiX2YxKBZKGnd2TtPkcJ/ljkUCAwEAAQ==
-----END PUBLIC KEY-----
EOD;

$binary_signature = "";

// At least with PHP 5.2.2 / OpenSSL 0.9.8b (Fedora 7)
// there seems to be no need to call openssl_get_privatekey or similar.
// Just pass the key as defined above
openssl_sign($data, $binary_signature, $private_key, OPENSSL_ALGO_SHA1);

// Check signature
$ok = openssl_verify($data, $binary_signature, $public_key, OPENSSL_ALGO_SHA1);
echo "check #1: ";
if ($ok == 1) {
    echo "signature ok (as it should be)\n";
} elseif ($ok == 0) {
    echo "bad (there's something wrong)\n";
} else {
    echo "ugly, error checking signature\n";
}

$ok = openssl_verify('tampered'.$data, $binary_signature, $public_key, OPENSSL_ALGO_SHA1);
echo "check #2: ";
if ($ok == 1) {
    echo "ERROR: Data has been tampered, but signature is still valid! Argh!\n";
} elseif ($ok == 0) {
    echo "bad signature (as it should be, since data has beent tampered)\n";
} else {
    echo "ugly, error checking signature\n";
}

?>


Вроде бы рабочий пример. Вставил туда свои ключи, и все работать перестало...
Все тоже самое, только длина ключа отличная (1024), но я не вижу в этом проблемы, так как ни где не вижу привязки именно к длине...
PM MAIL ICQ Skype   Вверх
Prontit
Дата 20.12.2011, 13:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 87
Регистрация: 19.10.2011

Репутация: 1
Всего: 1



все работает с моими ключами, косяк глупый был в коде.

мне кажется что проблема в сигнатуре. Они мне ее передают в виде 
Код

5EB7E68A5140BC62FB1A50EAF1A589FD8B40B239B31B6AEE799C9DA1F396144F79DDC2D4332E655D3D0DE60E9BE3BF5EB62E026766554AAF7A0B7201E0BACA1A68E12FD12F32016CD48E452D76D3136078AB53BD878B23D88BCB705C5C9406184E0D6264D3D3709ECBDDA994EB5CAE8F81C2A64FC015C20572598B56DD58F689
, а когда я шифрую строку у меня получается 
Код

■≥ ▓:xюMю├3УпV░_╖▄жвфхi╛юQЛ╟┐B▀Т┘б╙╛х╕\7╜l├╡л?еl=р▓тв;П╫\64F)H▌ VЪ╢б┴∙~╝NщB°ае║,Щ ТС╟P╖tXn√÷Ыe╨фГMжфK©NBХR═УGKLящ═я Ю┌iN╔1Р╘#СCд█LСИшЯ"аЕKх╝e┤ ^яъ y] )H╕
, видимо перед проверкой надо перекодировать.
PM MAIL ICQ Skype   Вверх
Prontit
  Дата 21.12.2011, 08:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 87
Регистрация: 19.10.2011

Репутация: 1
Всего: 1



Не получается перекодировать строку из шестнадцатеричной в бинарную. Делаю так:

Код

$sign = "5EB7E68A5140BC62FB1A50EAF1A589FD8B40B239B31B6AEE799C9DA1F396144F79DDC2D4332E655D3D0DE60E9BE3BF5EB62E026766554AAF7A0B7201E0BACA1A68E12FD12F32016CD48E452D76D3136078AB53BD878B23D88BCB705C5C9406184E0D6264D3D3709ECBDDA994EB5CAE8F81C2A64FC015C20572598B56DD58F689";

$binary_signature = base_convert($sign,16,2);


в ответ получаю

Код

0000000000000000000000000000000000000000000000000000000000000000


получается перекодировать только 16 символов. 

Код

$sign = "5EB7E68A5140BC62";
$binary_signature = base_convert($sign,16,2);


ответ

Код

101111010110111111001101000101001010001010000001011110000000000


что я делаю не так?
PM MAIL ICQ Skype   Вверх
bars80080
Дата 21.12.2011, 09:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прапор творюет
****
Награды: 1



Профиль
Группа: Завсегдатай
Сообщений: 12022
Регистрация: 5.12.2007
Где: Königsberg

Репутация: 71
Всего: 315



потому что это не число, а строка. сами подумайте, какая может быть разрядность у числа с таким числом знаков
PM MAIL WWW   Вверх
Prontit
Дата 21.12.2011, 09:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 87
Регистрация: 19.10.2011

Репутация: 1
Всего: 1



Цитата(bars80080 @ 21.12.2011,  09:42)
потому что это не число, а строка. сами подумайте, какая может быть разрядность у числа с таким числом знаков

верно. а каким образом перекодировать строку?
PM MAIL ICQ Skype   Вверх
bars80080
Дата 21.12.2011, 12:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прапор творюет
****
Награды: 1



Профиль
Группа: Завсегдатай
Сообщений: 12022
Регистрация: 5.12.2007
Где: Königsberg

Репутация: 71
Всего: 315



а что вы хотите получить?

если набор байтов, то посмотрите функцию pack(), модификатор a* по-моему
PM MAIL WWW   Вверх
Prontit
Дата 21.12.2011, 14:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 87
Регистрация: 19.10.2011

Репутация: 1
Всего: 1



Цитата(bars80080 @ 21.12.2011,  12:27)
а что вы хотите получить?

если набор байтов, то посмотрите функцию pack(), модификатор a* по-моему

Большое спасибо! Разобрался! Все работает!

Если кому-то интересно, могу выложить код с подробными комментариями, может пригодится. 

Всем спасибо за помощь!!! Тему можно закрывать!
PM MAIL ICQ Skype   Вверх
bars80080
Дата 21.12.2011, 16:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прапор творюет
****
Награды: 1



Профиль
Группа: Завсегдатай
Сообщений: 12022
Регистрация: 5.12.2007
Где: Königsberg

Репутация: 71
Всего: 315



Цитата(Prontit @  21.12.2011,  14:25 Найти цитируемый пост)
Если кому-то интересно, могу выложить код с подробными комментариями, может пригодится. 

да, очень интересно узнать решение


Цитата(Prontit @  21.12.2011,  14:25 Найти цитируемый пост)
Тему можно закрывать! 

это можешь сделать только ты и модераторы: галочка "пометить вопрос решённым" или кнопка сверху темы
PM MAIL WWW   Вверх
Prontit
Дата 22.12.2011, 06:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 87
Регистрация: 19.10.2011

Репутация: 1
Всего: 1



В общем задача была такая: приходит GET запрос  с различными параметрами, последний из которых sign, в нем передается сама подпись. Используется алгоритм RSA + SHA1. Необходимо вытащить строку и проверить ее открытым ключом. 

Код

<?php

//исходная строка GET запроса   
$get_str = $_SERVER['QUERY_STRING']; 
    
//позиция параметра SIGN
$sign_place = strpos($get_str, "sign");

//строка без параметра SIGN
$string_wthout_sign = substr($get_str, 0, $sign_place - 1);

//строка SIGN
$string_sign = $_GET['sign']; 

//Открытый ключ
$public_key = <<<EOD
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDEPpPvdefdg/NpfoENZgem4rxE
JWJFX6pOP3fCyMuBAt7F5ieqnYLhREN9loR56ACJhA17lK3A6tt1bROxLGtFwv4L
hrXI+qjQiQHZIsJKW2waE2KQdI9jiSE+9vg+iIoAYHSFx029wvJQRQH9qHifDXfa
VWdYr5icleV7My9jiwIDAQAB
-----END PUBLIC KEY-----
EOD;

//Преобразование в бинарный вид
$binarySign = pack("H*", $string_sign);

//Проверка
$ok = openssl_verify($string_wthout_sign, $binarySign, $public_key, OPENSSL_ALGO_SHA1);
if ($ok == 1) {
    echo "signature ok (as it should be)\n";
} elseif ($ok == 0) {
    echo "bad (there's something wrong)\n";
} else {
    echo "ugly, error checking signature\n";
}

?>


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

Еще раз спасибо за помощь!
PM MAIL ICQ Skype   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "PHP"
Aliance
IZ@TOP
skyboy
SamDark
MoLeX

Новичкам:

  • PHP редакторы собираются и обсуждаются здесь
  • Электронные книги по PHP, документацию можно найти здесь
  • Интерпретатор PHP, полную документацию можно скачать на PHP.NET

Важно:

  • Не брезгуйте пользоваться тегами [code=php]КОД[/code] для повышения читабельности текста/кода.
  • Перед созданием новой темы воспользуйтесь поиском и загляните в FAQ
  • Действия модераторов можно обсудить здесь

Внимание:

  • Темы "ищу скрипт", "подскажите скрипт" и т.п. будут переноситься в форум "Web-технологии"
  • Темы с именами: "Срочно", "помогите", "не знаю как делать" будут УДАЛЯТЬСЯ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, IZ@TOP, skyboy, SamDark, MoLeX, awers.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | PHP: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1311 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.