За последние 24 часа нас посетили 18620 программистов и 1657 роботов. Сейчас ищут 940 программистов ...

Шифрование, Подпись

Тема в разделе "Прочие вопросы по PHP", создана пользователем webymax, 14 июл 2013.

  1. webymax

    webymax Активный пользователь

    С нами с:
    14 июл 2013
    Сообщения:
    9
    Симпатии:
    0
    Я не имел дел с шифрованием, а тут для связи сайта с банком понадобилось сделать две с виду несложных вещи. Прошу помощи:

    1.
    Сформировать переменную NONCE – от 8 до 32 случайным образом сформированных байтов в hex формате.

    2.
    Есть строка:
    $str = '511.483USD677144616IT Books. Qty: 217Books Online Inc.14www.sample.com 1512345678901234589999999919pgw@mail.sample.com11--1420030105153021 16F2B2DD7E603A7ADA33https://www.sample.com/shop/reply';

    и есть ключ:
    $key = '00112233445566778899AABBCCDDEEFF';

    Нужно из них сделать подпись с помощью шифрования алгоритмом HMAC_SHA1.
    Я сделал вот так:
    hash_hmac('sha1', $str, $key);
    Выдаёт: 857d471f3660de69a106ad6e214edec38bfc41a7
    Но в примере сказано, что должно получиться: FACC882CA67E109E409E3974DDEDA8AAB13A5E48

    Вот выдержка из примера:
    The default MAC algorithm is HMAC_SHA1. Standard options include Triple DES ABA/ABC CBC MAC, AES 128 CBC MAC and RSA/SHA1 signature.
    For our MAC source string example and HMAC_SHA1 algorithm with hexadecimal secret key “00112233445566778899AABBCCDDEEFF”, the result MAC (“P_SIGN”) field must be equal to: “FACC882CA67E109E409E3974DDEDA8AAB13A5E48”. MAC field value can be either an upper case or lower case hexadecimal string.
     
  2. smitt

    smitt Старожил

    С нами с:
    3 янв 2012
    Сообщения:
    3.166
    Симпатии:
    65
    тебе не дали примеры скриптов?
     
  3. webymax

    webymax Активный пользователь

    С нами с:
    14 июл 2013
    Сообщения:
    9
    Симпатии:
    0
    Дали пример почему-то на javascripte. На php сказали, что нет пока у них. Это, конечно, очень странно слышать от банка... Но моё дело программистское, надо так надо :)
    На javascript код вообще огромный какой-то. Я так понимаю, это из-за того, что в этом языке нет предопределенных функций шифрования и приходится шифровать как-бы с нуля, вручную.
     
  4. Your

    Your Старожил

    С нами с:
    2 июл 2011
    Сообщения:
    4.074
    Симпатии:
    7
    Код (PHP):
    1. function genHex($length=8,$register='') {
    2.     if(0<$length) {
    3.         $array=array();
    4.         if(!function_exists('combineArrays')) {
    5.             function combineArrays($array) {
    6.                 $combineArray=array();
    7.                 foreach($array as $value) { 
    8.                     if(is_array($value)) { 
    9.                         $combineArray=array_merge($combineArray,combineArrays($value)); 
    10.                     } else { 
    11.                         $combineArray[]=$value; 
    12.                     } 
    13.                 } 
    14.                 return $combineArray;
    15.             }
    16.         }
    17.         if(is_string($register)) {
    18.             $register=!$register?'number|ru|RU|en|EN':$register;
    19.             $register=explode('|',$register,5);
    20.             $numberRegister=array(
    21.                                 'number'=>'48,58',
    22.                                 'ru'=>'224,256',
    23.                                 'RU'=>'192,224',
    24.                                 'en'=>'97,123',
    25.                                 'EN'=>'65,91',
    26.                             );
    27.             $successRegister=$return=array();
    28.             foreach($register as $value) {
    29.                 if(in_array($value,array_keys($numberRegister))) {
    30.                     $successRegister[$value]=$value;
    31.                 }
    32.             }
    33.             if(0<sizeof($successRegister)) {
    34.                 if(!function_exists('isRegister')) {
    35.                     function isRegister($key,$array) {
    36.                         return is_array($array) && !empty($array[$key]) && $array[$key]===$key;
    37.                     }
    38.                 }
    39.                 foreach($numberRegister as $key => $value) {
    40.                     $value=explode(',',$value,2);
    41.                     if(2==sizeof($value)) {
    42.                         $one=$value[0];
    43.                         $two=$value[1];
    44.                         if(isRegister($key,$successRegister)) {
    45.                             for($i=$one;$two>$i;++$i) {
    46.                                 $array[$key][]='ru'===strtolower($key)?iconv('windows-1251','utf-8',chr($i)):chr($i);
    47.                             }
    48.                             if('ru'==$key) {
    49.                                 $array[$key][]='ё';
    50.                             } else if('RU'==$key) {
    51.                                 $array[$key][]='Ё';
    52.                             }
    53.                         }
    54.                     }
    55.                 }
    56.             }
    57.         } else if(is_array($register)) {
    58.             $array=$register;
    59.         }
    60.         $array=combineArrays($array);
    61.         if(!empty($array)) {
    62.             for($i=0;$i<$length;$i++) {
    63.                 $return[]=$array[rand(0,sizeof($array)-1)];
    64.             }
    65.         }
    66.     return join('',$return);
    67.     }
    68. return null;
    69. } 
    Код (PHP):
    1. echo genHex(rand(8,32),array(0,1,2,'d','g','s')); //112g11s2g0sggs22sgs2gg12gs    
    Код (PHP):
    1. echo genHex(rand(8,32)); // тпё1ч1bнUзЁyшлXкkс     
    Код (PHP):
    1. echo genHex(8); //ЫОяFkНМв     
    Код (PHP):
    1. echo genHex(rand(8,32),'number|en'); //ui1nhd1ct2xm4fp14t     
    Код (PHP):
    1. echo genHex(rand(8,32),'en'); //vukicxrunchgsbnfvbgokuuvombzvv     
    Код (PHP):
    1. echo genHex(rand(8,32),'EN'); //QFRBESDDMIQWKZSYHE     
    Код (PHP):
    1. echo genHex(rand(8,32),'en|RU'); //ШЮЁuЪДdqmneЙdЬ     
    LOL!

    Код (PHP):
    1. function enc($enc) {
    2.     return base64_encode(pack('H*',sha1(utf8_encode($enc))));
    3. } 
    Код (PHP):
    1. echo enc(genHex(rand(8,32),'number|en|EN')); // a/fcI+w7p/2538/f3cr/ZISFBNM=     
     
  5. webymax

    webymax Активный пользователь

    С нами с:
    14 июл 2013
    Сообщения:
    9
    Симпатии:
    0
    Выглядит очень по-суперски :) но мне кажется как-то проще должно быть.
    Если сделать вот так:
    Код (Text):
    1. bin2hex(pack('H*', str_shuffle('0123456789ABCDEF')))
    это будет похоже на правду? :)
     
  6. smitt

    smitt Старожил

    С нами с:
    3 янв 2012
    Сообщения:
    3.166
    Симпатии:
    65
    это оплата по 3dsecure:)

    Покажи что там за js будет время взгляну.
     
  7. Your

    Your Старожил

    С нами с:
    2 июл 2011
    Сообщения:
    4.074
    Симпатии:
    7
    Код (PHP):
    1. echo uniqid(); 
     
  8. webymax

    webymax Активный пользователь

    С нами с:
    14 июл 2013
    Сообщения:
    9
    Симпатии:
    0
    На js мне дали только формирование подписи, т.е. это относится ко второму вопросу. По первому вопросу мне в банке ничем помочь не смогли :(
    Your, ты сам придумал скрипт? Насколько формируемое значение более засекреченно-безопасно-неугадываемое, чем uniqid()? :)

    Добавлено спустя 42 минуты 54 секунды:
    Если я правильно помню, хекс-формат может состоять только из чисел и букв от A до F. Тогда скрипт от Your можно вызывать так:
    Код (Text):
    1. $nonce = genHex(16, array(0,1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F'));
    Если это более серьезно, чем uniqid, то так и буду делать. Просто есть уверенность, что проще должно быть. Например, по второму вопросу я наткнулся на решение в виде целого класса, хотя как оказалось обойтись можно всего одной строкой:
    Код (Text):
    1. hash_hmac('sha1', $str, pack('H*', $key))
    или
    Код (Text):
    1. bin2hex(mhash(MHASH_SHA1, $str, pack('H*', $key)))
    Добавлено спустя 5 минут 54 секунды:
    Не, фигню написал я... уже и сам понял. Хорошо, что не распугал ею всех форумчан :)
     
  9. Your

    Your Старожил

    С нами с:
    2 июл 2011
    Сообщения:
    4.074
    Симпатии:
    7
    Генерация-это одно, а хеш другое.
    Генерация происходит с каждым разом новая, а хеш-это сохраняется для сравнения данных.
    Так, как например пользователь, создал пароль и мы его зашифровали enc('пароль');, собственно при сравнении данных мы будем тоже использовать enc('пароль')==$db['password']. И если все хорошо вернет успех.

    Аналог на js тоже сделать можно.
    Тут вы только по указанным символам будете генерировать, чтобы только все цифры и заглавные англ. буквы, то лучше так:
    Код (PHP):
    1. $nonce=genHex(16,'number|EN'); 
    Пере-заменил функцию, поправил слегка.
     
  10. webymax

    webymax Активный пользователь

    С нами с:
    14 июл 2013
    Сообщения:
    9
    Симпатии:
    0
    По задаче требуется именно хекс-формат. А в нём не может быть букв, которые идут в алфавите после буквы F. Т.е. должны быть только цифры и буквы в диапазоне A-F.
     
  11. Mr.M.I.T.

    Mr.M.I.T. Старожил

    С нами с:
    28 янв 2008
    Сообщения:
    4.586
    Симпатии:
    1
    Адрес:
    у тебя канфетка?
    почему фигню то? ) тебе же надо просто набор из 8 - 32 байт получить?
    тогда делай
    Код (Text):
    1. str_shuffle('0123456789ABCDEF').str_shuffle('0123456789ABCDEF')
    получишь 32 случайных байта, дальше можешь резать строку если нуно.

    а вобще забавно видеть такие вопросы от того кто пишет софт для банка. Или может я не уловил глубинной сути )

    по второму вопросу читайте доку http://php.net/hash_hmac
     
  12. webymax

    webymax Активный пользователь

    С нами с:
    14 июл 2013
    Сообщения:
    9
    Симпатии:
    0
    Задача буквально так и стоит - получить от 8 до 32 случайным образом сформированных байтов в hex формате. Фигню - потому что
    Код (Text):
    1. bin2hex(pack('H*', str_shuffle('0123456789ABCDEF')))
    это то же самое, что и просто
    Код (Text):
    1. str_shuffle('0123456789ABCDEF')
    Проблема в том, что я понятия особого не имею о глубинной сути хекс-формата. Поэтому и пытался использовать именно хексовую функцию bin2hex, надеясь, что если хекс - это не просто любой набор из 0-9А-F, а особым образом упорядоченный, то bin2hex сделает своё дело. Но по-моему никакой особой упорядоченности в этих символах нет. Я прав? Если да, то действительно, твой вариант подходит:
    Код (Text):
    1. str_shuffle('0123456789ABCDEF').str_shuffle('0123456789ABCDEF')
    Хотя ещё проще тогда использовать предложение от Your:
    Код (Text):
    1. uniqid();
    Но что-то мне подсказывает, что это у меня какой-то подгон под ответ будет, т.е. отмаз какой-то несерьезный :)
    Да ну, ты что... Конечно, это был бы нонсенс. Я просто веб-мастер сайта, заказчик которого хочет сделать у себя на сайте прием оплаты через банковские карточки, для чего и привлек банк. Банк выдал мне описание процесса, в котором мне всё по силам, кроме вот этих двух вопросов, в которых у меня нулевой опыт, и по которым банк не смог мне дать никаких готовых решений, кроме какого-то не-пришей-кобыле-хвост js-кода :(
     
  13. webymax

    webymax Активный пользователь

    С нами с:
    14 июл 2013
    Сообщения:
    9
    Симпатии:
    0
    Путём нехитрых умозаключений пришёл к следующему коду. Вроде и правильно, и просто:
    Код (Text):
    1. $nonce = '';
    2. for($i = 0; $i < 8; $i ++)
    3.     $nonce .= substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 1);
    4. $nonce = bin2hex($nonce);
    5. echo $nonce;
     
  14. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.251
    Адрес:
    там-сям
    Гугль выдал решение:
    http://pastie.org/2283344

    ну вообще NONE это Number Used Once, т.е. нужен генератор + проверка что это число выдавалось (при этом ключ становится невалидным):- wiki. не знаю насколько это важно в твоем контексте. просто генератор неповторяющихся фигней есть: uniqid(), без параметров он выдает строку из 13 шестнадцатиричных цифр. в условия задачи попадает :) а нужна ли проверка - это ты нам скажешь.

    вот есть пример с базой: https://github.com/greatwitenorth/php-nonce/blob/master/nonce.php
     
  15. webymax

    webymax Активный пользователь

    С нами с:
    14 июл 2013
    Сообщения:
    9
    Симпатии:
    0
    Проверять на уникальность не обязательно. Это просто "соль", если я правильно понимаю, что такое "соль" :) Короче, с данными о заказе (сумма, номер заказа, описание...) и мёрчанте (id мёрчанта, название, сайт...) и еще разными post-данными передается и этот NONCE, который участвует в формировании еще одной post-переменной - P_SIGN - подпись.
    NONCE должен быть в hex-формате. Если я правильно уже успел разобраться, то hex должен состоять из четного количества символов, т.к. каждая пара символов хекса соответствует одному байту исходной строки. В uniqid 13 символов. В принципе, не проблема добрать еще 1 символ. Наверное можно и так, но меня немного смущает, будет ли в итоге hex. Я не уверен, что hex - это вообще любая комбинация символов 1-9A-F.

    Добавлено спустя 2 минуты 42 секунды:
    Я уже чуть выше написал, что нашел решение:
    Код (Text):
    1. hash_hmac('sha1', $str, pack('H*', $key))
    Код (Text):
    1. bin2hex(mhash(MHASH_SHA1, $str, pack('H*', $key)))
    По твоей ссылке как раз на этом и строится класс.
     
  16. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.251
    Адрес:
    там-сям
    ну если нужен просто генератор, то
    Код (PHP):
    1. $nonce = substr(sha1(microtime(true)), 0, mt_rand(4, 16)*2); 
    // от 8 до 32 символов, четное количество
     
  17. webymax

    webymax Активный пользователь

    С нами с:
    14 июл 2013
    Сообщения:
    9
    Симпатии:
    0
    artoodetoo, спасибо! отличное решение, и работает быстро.
    Точно ли оно подходит под определение "от 8 до 32 случайным образом сформированных байтов в hex формате"?
     
  18. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    есть еще один способ на всяк-всяк
    есть функция перевода системы счисления. можно заюзать ее генеря рандомное число от 8*16 до 32*16 и переводя соотв в шестнадцатеричную