Уменьшите MD5 — используя другую базу

Мой клиент генерирует промо-коды купонов, которые являются не более чем 32-мя символами MD5-хешей.

Моя задача состоит в том, чтобы уменьшить строку MD5 с 32 до менее чем 10 символов таким образом, чтобы хеш можно было воссоздать из уменьшенной строки.

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

Например: 719bedacf2e560b27f39d80accc67ffd => ZjKa1Gh (не математически верно)

Я сталкивался с этим: Как уменьшить длину хеш-значения?

Это предполагает: Используя другую базу

Я не знаю, как сделать это в PHP, можем ли мы декодировать строку в ее ASCII и перекодировать ее?

Есть ли в PHP встроенные функции, которые я могу использовать в этом случае?

Обновление с помощью https://packagist.org/packages/aza/math

$original = '719bedacf2e560b27f39d80accc67ffd';
$long1 = NumeralSystem::convert($original, 16, 10);
$short = NumeralSystem::convertTo($long1, 62);
$long2 = NumeralSystem::convertFrom($short, 62);
$recovered = NumeralSystem::convert($long2, 10, 16);

var_dump($long1);
var_dump($short);
var_dump($long2);
var_dump($recovered);

// output
string(39) "151012390170261082849236619706853916669"string(22) "3SNOKWefotgnnCmWnYkTOf"string(39) "151012390170261082849236619706853916669"string(32) "719bedacf2e560b27f39d80accc67ffd"

Кажется, самое низкое, что я могу достичь из 32 символов MD5 — это 22 символа таким образом. Я все еще ищу способы, которыми я мог бы еще уменьшить его до 10 символов.

Обновление: использование первой половины MD5

$original = '719bedacf2e560b';
$coupon = NumeralSystem::convert($original, 16, 62);
$recovered = NumeralSystem::convert($coupon, 62, 16);

var_dump($coupon);
var_dump($recovered);

// output
string(10) "bnMR3RjZil"string(15) "719bedacf2e560b"

Если пользователь предоставляет bnMR3RjZil Я могу использовать это, чтобы воссоздать 719bedacf2e560b а затем сделать MySQL LIKE поиск, чтобы получить полный MD5. Если он возвращает строку, я могу продолжить рекламную деятельность.

1

Решение

Криптографический хэш на самом деле представляет собой последовательность битов, но его можно интерпретировать как число. Таким образом, вы можете теоретически использовать старый добрый base_convert () Выразить в большой базе. К сожалению, эта функция работает только до основания 36 и ограничена действительными числами (то есть короткими целыми числами, которые вписываются в PHP_INT_MAX) — иначе происходит потеря данных.

Здесь на помощь приходят сторонние библиотеки. Единственная проблема заключается в том, что их, как правило, трудно найти, потому что они обычно предназначены для очень конкретных случаев использования (биткойн, обфускация идентификаторов и т. Д.).

Я нашел, например, аза / математика, что, вероятно, излишне, но должно сделать работу. У меня не было возможности протестировать его, но все должно получиться так:

$original = '719bedacf2e560b27f39d80accc67ffd';
$short = NumeralSystem::convert($original, 16, 62);
$recovered = NumeralSystem::convert($short, 62, 16);
1

Другие решения

Моя задача состоит в том, чтобы уменьшить строку MD5 с 32 до менее чем 10 символов таким образом, чтобы хеш можно было воссоздать из уменьшенной строки.

Это невозможно Хеш MD5 составляет 128 бит; символ ASCII составляет 7 бит. Невозможно сохранить хеш MD5 в количестве менее 128 ÷ 7 = 18,2 (округление до 19) символов ASCII, и даже это будет включать непечатные управляющие символы.

2

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

Идея состоит в том, что вы интерпретируете свою входную строку как последовательность из 128 битов. Теперь, если вы укажете, что ваш новый алфавит (символы новой базовой системы) A-Za-z0-9+-, у вас есть 64 символа, что означает, что вам нужно 6 бит для кодирования каждого из них. Поэтому вы можете сначала преобразовать свою входную строку в двоичное представление, разделить это представление на куски по 6 битов и выразить каждый кусок в указанном наборе символов A-Za-z0-9+-:

<?php

$s = "719bedacf2e560b27f39d80accc67ffd";

function conv($s){
$ret = base_convert($s, 16, 2);
return str_repeat("0", 8 - strlen($ret)) . $ret;
}

$binary_repr = implode(array_map(conv, str_split($s, 2)), '');

$items = str_split($binary_repr, 6);

function item2char($str){
$code = base_convert($str, 2, 10);
$alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-';
return $alphabet[$code];
}

$result = implode(array_map(item2char, $items), '');
echo $result;

?>

Как отмечено в комментариях, это в основном идея:

<?php
$s = "719bedacf2e560b27f39d80accc67ffd";

echo base64_encode(hex2bin($s));
//cZvtrPLlYLJ/OdgKzMZ//Q==

echo bin2hex(base64_decode("cZvtrPLlYLJ/OdgKzMZ//Q=="));
//719bedacf2e560b27f39d80accc67ffd

?>
0
По вопросам рекламы [email protected]