Я не имел дел с шифрованием, а тут для связи сайта с банком понадобилось сделать две с виду несложных вещи. Прошу помощи: 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.
Дали пример почему-то на javascripte. На php сказали, что нет пока у них. Это, конечно, очень странно слышать от банка... Но моё дело программистское, надо так надо На javascript код вообще огромный какой-то. Я так понимаю, это из-за того, что в этом языке нет предопределенных функций шифрования и приходится шифровать как-бы с нуля, вручную.
Код (PHP): function genHex($length=8,$register='') { if(0<$length) { $array=array(); if(!function_exists('combineArrays')) { function combineArrays($array) { $combineArray=array(); foreach($array as $value) { if(is_array($value)) { $combineArray=array_merge($combineArray,combineArrays($value)); } else { $combineArray[]=$value; } } return $combineArray; } } if(is_string($register)) { $register=!$register?'number|ru|RU|en|EN':$register; $register=explode('|',$register,5); $numberRegister=array( 'number'=>'48,58', 'ru'=>'224,256', 'RU'=>'192,224', 'en'=>'97,123', 'EN'=>'65,91', ); $successRegister=$return=array(); foreach($register as $value) { if(in_array($value,array_keys($numberRegister))) { $successRegister[$value]=$value; } } if(0<sizeof($successRegister)) { if(!function_exists('isRegister')) { function isRegister($key,$array) { return is_array($array) && !empty($array[$key]) && $array[$key]===$key; } } foreach($numberRegister as $key => $value) { $value=explode(',',$value,2); if(2==sizeof($value)) { $one=$value[0]; $two=$value[1]; if(isRegister($key,$successRegister)) { for($i=$one;$two>$i;++$i) { $array[$key][]='ru'===strtolower($key)?iconv('windows-1251','utf-8',chr($i)):chr($i); } if('ru'==$key) { $array[$key][]='ё'; } else if('RU'==$key) { $array[$key][]='Ё'; } } } } } } else if(is_array($register)) { $array=$register; } $array=combineArrays($array); if(!empty($array)) { for($i=0;$i<$length;$i++) { $return[]=$array[rand(0,sizeof($array)-1)]; } } return join('',$return); } return null; } Код (PHP): echo genHex(rand(8,32),array(0,1,2,'d','g','s')); //112g11s2g0sggs22sgs2gg12gs Код (PHP): echo genHex(rand(8,32)); // тпё1ч1bнUзЁyшлXкkс Код (PHP): echo genHex(8); //ЫОяFkНМв Код (PHP): echo genHex(rand(8,32),'number|en'); //ui1nhd1ct2xm4fp14t Код (PHP): echo genHex(rand(8,32),'en'); //vukicxrunchgsbnfvbgokuuvombzvv Код (PHP): echo genHex(rand(8,32),'EN'); //QFRBESDDMIQWKZSYHE Код (PHP): echo genHex(rand(8,32),'en|RU'); //ШЮЁuЪДdqmneЙdЬ LOL! Код (PHP): function enc($enc) { return base64_encode(pack('H*',sha1(utf8_encode($enc)))); } Код (PHP): echo enc(genHex(rand(8,32),'number|en|EN')); // a/fcI+w7p/2538/f3cr/ZISFBNM=
Выглядит очень по-суперски но мне кажется как-то проще должно быть. Если сделать вот так: Код (Text): bin2hex(pack('H*', str_shuffle('0123456789ABCDEF'))) это будет похоже на правду?
На js мне дали только формирование подписи, т.е. это относится ко второму вопросу. По первому вопросу мне в банке ничем помочь не смогли Your, ты сам придумал скрипт? Насколько формируемое значение более засекреченно-безопасно-неугадываемое, чем uniqid()? Добавлено спустя 42 минуты 54 секунды: Если я правильно помню, хекс-формат может состоять только из чисел и букв от A до F. Тогда скрипт от Your можно вызывать так: Код (Text): $nonce = genHex(16, array(0,1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F')); Если это более серьезно, чем uniqid, то так и буду делать. Просто есть уверенность, что проще должно быть. Например, по второму вопросу я наткнулся на решение в виде целого класса, хотя как оказалось обойтись можно всего одной строкой: Код (Text): hash_hmac('sha1', $str, pack('H*', $key)) или Код (Text): bin2hex(mhash(MHASH_SHA1, $str, pack('H*', $key))) Добавлено спустя 5 минут 54 секунды: Не, фигню написал я... уже и сам понял. Хорошо, что не распугал ею всех форумчан
Генерация-это одно, а хеш другое. Генерация происходит с каждым разом новая, а хеш-это сохраняется для сравнения данных. Так, как например пользователь, создал пароль и мы его зашифровали enc('пароль');, собственно при сравнении данных мы будем тоже использовать enc('пароль')==$db['password']. И если все хорошо вернет успех. Аналог на js тоже сделать можно. Тут вы только по указанным символам будете генерировать, чтобы только все цифры и заглавные англ. буквы, то лучше так: Код (PHP): $nonce=genHex(16,'number|EN'); Пере-заменил функцию, поправил слегка.
По задаче требуется именно хекс-формат. А в нём не может быть букв, которые идут в алфавите после буквы F. Т.е. должны быть только цифры и буквы в диапазоне A-F.
почему фигню то? ) тебе же надо просто набор из 8 - 32 байт получить? тогда делай Код (Text): str_shuffle('0123456789ABCDEF').str_shuffle('0123456789ABCDEF') получишь 32 случайных байта, дальше можешь резать строку если нуно. а вобще забавно видеть такие вопросы от того кто пишет софт для банка. Или может я не уловил глубинной сути ) по второму вопросу читайте доку http://php.net/hash_hmac
Задача буквально так и стоит - получить от 8 до 32 случайным образом сформированных байтов в hex формате. Фигню - потому что Код (Text): bin2hex(pack('H*', str_shuffle('0123456789ABCDEF'))) это то же самое, что и просто Код (Text): str_shuffle('0123456789ABCDEF') Проблема в том, что я понятия особого не имею о глубинной сути хекс-формата. Поэтому и пытался использовать именно хексовую функцию bin2hex, надеясь, что если хекс - это не просто любой набор из 0-9А-F, а особым образом упорядоченный, то bin2hex сделает своё дело. Но по-моему никакой особой упорядоченности в этих символах нет. Я прав? Если да, то действительно, твой вариант подходит: Код (Text): str_shuffle('0123456789ABCDEF').str_shuffle('0123456789ABCDEF') Хотя ещё проще тогда использовать предложение от Your: Код (Text): uniqid(); Но что-то мне подсказывает, что это у меня какой-то подгон под ответ будет, т.е. отмаз какой-то несерьезный Да ну, ты что... Конечно, это был бы нонсенс. Я просто веб-мастер сайта, заказчик которого хочет сделать у себя на сайте прием оплаты через банковские карточки, для чего и привлек банк. Банк выдал мне описание процесса, в котором мне всё по силам, кроме вот этих двух вопросов, в которых у меня нулевой опыт, и по которым банк не смог мне дать никаких готовых решений, кроме какого-то не-пришей-кобыле-хвост js-кода
Путём нехитрых умозаключений пришёл к следующему коду. Вроде и правильно, и просто: Код (Text): $nonce = ''; for($i = 0; $i < 8; $i ++) $nonce .= substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 1); $nonce = bin2hex($nonce); echo $nonce;
Гугль выдал решение: http://pastie.org/2283344 ну вообще NONE это Number Used Once, т.е. нужен генератор + проверка что это число выдавалось (при этом ключ становится невалидным):- wiki. не знаю насколько это важно в твоем контексте. просто генератор неповторяющихся фигней есть: uniqid(), без параметров он выдает строку из 13 шестнадцатиричных цифр. в условия задачи попадает а нужна ли проверка - это ты нам скажешь. вот есть пример с базой: https://github.com/greatwitenorth/php-nonce/blob/master/nonce.php
Проверять на уникальность не обязательно. Это просто "соль", если я правильно понимаю, что такое "соль" Короче, с данными о заказе (сумма, номер заказа, описание...) и мёрчанте (id мёрчанта, название, сайт...) и еще разными post-данными передается и этот NONCE, который участвует в формировании еще одной post-переменной - P_SIGN - подпись. NONCE должен быть в hex-формате. Если я правильно уже успел разобраться, то hex должен состоять из четного количества символов, т.к. каждая пара символов хекса соответствует одному байту исходной строки. В uniqid 13 символов. В принципе, не проблема добрать еще 1 символ. Наверное можно и так, но меня немного смущает, будет ли в итоге hex. Я не уверен, что hex - это вообще любая комбинация символов 1-9A-F. Добавлено спустя 2 минуты 42 секунды: Я уже чуть выше написал, что нашел решение: Код (Text): hash_hmac('sha1', $str, pack('H*', $key)) Код (Text): bin2hex(mhash(MHASH_SHA1, $str, pack('H*', $key))) По твоей ссылке как раз на этом и строится класс.
ну если нужен просто генератор, то Код (PHP): $nonce = substr(sha1(microtime(true)), 0, mt_rand(4, 16)*2); // от 8 до 32 символов, четное количество
artoodetoo, спасибо! отличное решение, и работает быстро. Точно ли оно подходит под определение "от 8 до 32 случайным образом сформированных байтов в hex формате"?
есть еще один способ на всяк-всяк есть функция перевода системы счисления. можно заюзать ее генеря рандомное число от 8*16 до 32*16 и переводя соотв в шестнадцатеричную