Я работаю над приложением, в котором пользователям нужно вызвать и ввести проверочный номер с клавиатуры своего телефона.
Я хотел бы иметь возможность определить, правильный ли номер, который они вводят, или нет. Телефонная система не имеет доступа к списку действительных номеров, но вместо этого она проверяет номер на соответствие алгоритму (например, номеру кредитной карты).
Вот некоторые из требований:
Как бы вы сгенерировали такое число, учитывая эти требования?
РЕДАКТИРОВАТЬ :
@Haaked: код должен быть числовым, потому что пользователь набирает его на своем телефоне.
@matt b: на первом этапе код отображается на веб-странице, на втором этапе необходимо вызвать и ввести код. Я не знаю телефонного номера пользователя.
Продолжение: я нашел несколько алгоритмов проверить для проверки действительности чисел (см. Этот интересный проект Google Code: checkDigits).





Для 1M комбинаций вам понадобится 6 цифр. Чтобы убедиться, что нет никаких случайно действительных кодов, я предлагаю 9 цифр с вероятностью 1/1000, что случайный код работает. Я также предлагаю использовать другую цифру (всего 10) для выполнения проверка целостности. Что касается шаблонов распределения, случайного будет достаточно, а контрольная цифра гарантирует, что единственная ошибка не приведет к правильному коду.
Редактировать: Видимо я не полностью прочитал ваш запрос. Используя номер кредитной карты, вы можете выполнить хеширование (MD5 или SHA1 или что-то подобное). Затем вы обрезаете в соответствующем месте (например, 9 символов) и конвертируете в основание 10. Затем вы добавляете контрольную цифру (а), и это должно более или менее работать для ваших целей.
- I must have a reasonnable number of possible combinations (let's say 1M)
- The code must be as short as possible, to avoid errors from the user
Что ж, если вы хотите, чтобы в нем был хотя бы один миллион комбинаций, вам нужно как минимум шесть цифр. Достаточно ли коротко?
У вас есть доступ к номеру телефона звонящего при создании кода подтверждения?
Если это так, я бы использовал номер телефона вызывающего абонента и пропустил его через какую-то функцию хеширования, чтобы вы могли гарантировать, что проверочный код, который вы дали вызывающему абоненту на шаге 1, совпадает с кодом, который они вводят на шаге 2 (чтобы убедиться, что они не используют проверочный код друга или просто сделали очень удачное предположение).
Что касается хеширования, я не уверен, можно ли взять 10-значное число и получить результат хеширования, который будет <10 цифр (я думаю, вам придется жить с определенным количеством коллизий), но я думаю это поможет гарантировать, что пользователь будет тем, кем он себя называет.
Конечно, это не сработает, если номер телефона, использованный на шаге 1, отличается от того, с которого они звонят на шаге 2.
Это должны быть только цифры? Вы можете создать случайное число от 1 до 1M (я бы предложил даже больше), а затем Base32 кодирует это. Следующее, что вам нужно сделать, это хешировать это значение (используя секретное значение соли) и base32 закодировать хеш. Затем соедините две строки вместе, возможно, разделив их тире.
Таким образом, вы можете алгоритмически проверять входящий код. Вы просто берете левую часть кода, хешируете ее с помощью секретной соли и сравниваете это значение с правой частью кода.
Предполагая, что вы уже знаете, как определить, какой ключ нажимает пользователь, это должно быть достаточно легко выполнимо. В мире безопасности существует понятие «одноразового» пароля. Иногда это называют «одноразовым паролем». Обычно они ограничиваются (легко вводимыми) значениями ASCII. Итак, [a-zA-z0-9] и куча легко вводимых символов. например запятая, точка, точка с запятой и круглые скобки. Однако в вашем случае вы, вероятно, захотите ограничить диапазон до [0-9] и, возможно, включить * и #.
Я не могу объяснить все технические детали того, как эти одноразовые коды генерируются (или работают) должным образом. За этим стоит некоторая промежуточная математика, которую я бы разделал, не просматривая ее сначала. Достаточно сказать, что вы используете алгоритм для генерации потока одноразовых паролей. Сколько бы вы ни знали предыдущих кодов, угадать последующий будет невозможно! В вашем случае вы просто будете использовать каждый пароль в списке как случайный код пользователя.
Вместо того, чтобы самому объяснять детали реализации, я направлю вас к статье на 9 страницах, где вы можете прочитать об этом сами: https://www.grc.com/ppp.htm
Похоже, у вас есть негласное требование, чтобы с помощью алгоритма было быстро определено, что код действителен. Это исключит возможность просто раздачи списка номеров одноразового блокнота.
В прошлом люди делали это несколькими способами.
Есть множество других вариантов, но они распространены и их легко реализовать.
-Адам
Вы связались с проектом проверить цифры, и использование функции "encode" кажется хорошим решением. Он говорит:
encode may throw an exception if 'bad' data (e.g. non-numeric) is passed to it, while verify only returns true or false. The idea here is that encode normally gets it's data from 'trusted' internal sources (a database key for instance), so it should be pretty usual, in fact, exceptional that bad data is being passed in.
Похоже, вы можете передать функции кодирования ключ базы данных (например, 5 цифр) и получить число, которое будет соответствовать вашим требованиям.
После некоторого исследования, думаю, я воспользуюсь формулой ISO 7064 Мод 97,10. Это кажется довольно надежным, поскольку он используется для проверки IBAN (международного номера банковского счета).
Формула очень проста:
123456mod(98 - mod(number * 100, 97), 97) => 76mod(code, 97) == 1Тест :
mod(12345676, 97) = 1 => ХОРОШОmod(21345676, 97) = 50 => ПЛОХО!mod(12345678, 97) = 10 => ПЛОХО!Судя по всему, этот алгоритм вылавливает большинство ошибок.
Еще один интересный вариант - Алгоритм Верхоффа. Он имеет только одну контрольную цифру и его сложнее реализовать (по сравнению с простой формулой, приведенной выше).
Если ожидаются враждебные пользователи (что, кажется, подразумевается в вопросе), пользователю будет очень легко сгенерировать действительный идентификатор с помощью этого алгоритма.
Враждебные пользователи не были проблемой в этом приложении. Тем не менее, я добавил некоторую логику для «смешивания» и «расщепления» битов, чтобы упростить угадывание следующих чисел.
При вычислении контрольной суммы с длиной, подобной IBAN, имейте в виду, что промежуточная сумма часто не помещается в 32-битное целое число со знаком.
checksum может состоять из 1 цифры. Итак, в этом случае вы должны префикс cero. например для 256 код будет 25609. не путайте с 2569
@nick Johnson: я не думаю, что в вопросе подразумеваются враждебные пользователи. Кроме того, контрольные цифры предназначены не для предотвращения враждебных пользователей, а для уменьшения количества ошибок при вводе данных.
@Sprague OP спросил о «проверочном коде», что означает для меня, что они не хотят, чтобы пользователи могли придумать его, не получив его.
Я нашел эту ссылку с алгоритмом Верхоффа en.wikibooks.org/wiki/Algorithm_Implementation/Checksums/…
Вы хотите сегментировать свой код. Часть его должна быть 16-битной CRC остальной части кода.
Если вам нужен только проверочный номер, просто используйте порядковый номер (при условии, что у вас есть единственная точка генерации). Таким образом, вы будете знать, что не получите дубликатов.
Затем вы добавляете к последовательности префикс CRC-16 этого порядкового номера И некоторого закрытого ключа. Вы можете использовать что угодно в качестве закрытого ключа, если вы сохраняете его конфиденциальность. Сделайте что-нибудь большое, по крайней мере, GUID, но это может быть текст Война и мир из проекта Gutenberg. Просто нужно быть тайным и постоянным. Наличие закрытого ключа не позволяет людям подделать ключ, но использование 16-битного CR упрощает взлом.
Для проверки вы просто разделите номер на две части, а затем возьмете CRC-16 порядкового номера и закрытого ключа.
Если вы хотите больше скрыть последовательную часть, разделите CRC на две части. Поместите 3 цифры в начале и 2 в конце последовательности (заполните нулями, чтобы длина CRC была согласованной).
Этот метод позволяет вам также начать с меньших ключей. Первые 10 ключей будут 6-значными.
Алгоритм в телефоне можно легко реконструировать. Поэтому его нельзя использовать в качестве меры по борьбе с мошенничеством или спамом.