对数字密码进行排名的算法?

Algorithm to rank numeric passcode?

我正在研究需要获取用户 PIN 码的(移动)应用程序: 6/8 密码的数字 "passcode",输入类似 UI:

因此,在注册步骤中,用户配置他的一个密码(因为这将是一个密码)。

假设密码必须具有固定大小(比如 8 个密码:********)

我的问题与 verify/check 用户选择的数字的可能算法有关,在重复密码或标准密码模式(1234567800001111 的情况下给出不好的排名), 很容易被恶意破解者预测...

对这种算法有什么想法吗?

乍一看,该算法可能会阻止(排名不佳)包含重复密码的密码,类似于:

00117788
88886611 

或"usual" ascending/descending 模式为:

12345678
98765432

或与个人相关的数字模式,以我为例,我出生于 1963 年 9 月 2 日,因此使用密码可能是个坏主意:

02091963

相反,在我看来 "good" 的序列可能是以下一个:

18745098 
90574808
07629301

附带问题:您认为假设 8 个密码的数字密码可以作为 "password" 验证支付交易的可接受解决方案吗?

顺便说一句,我在 Ruby.

中编码

感谢您的耐心等待!

乔治

对于您的前 2 个案例:

字符串中重复的连续字符数:

str = "00117788"
str.chars.each_cons(2).select {|a,b| a == b}.count
#=> 4

或者正如@CarySwoveland 指出的那样,这将产生相同的结果

str.size - str.squeeze.size
#=> 4

增加的字符数

str = "12345678"
str.chars.map(&:to_i).each_slice(2).select {|a,b| (a + 1) == b || (a - 1) == b }.count
#=> 4
#note this will also return 4 for "12563478"
# you could also use str.chars.map(&:to_i).each_cons(2).select {|a,b| (a + 1) == b || (a - 1) == b }.count
# This will return 7 for "12345678" and still return 4 for "12563478"

你也可以把上面的两个结合起来

str = "00117788"
str.chars.map(&:to_i).each_cons(2).select {|a,b| (a + 1) == b || (a - 1) == b || a == b }.count
#=> 6

至于 "personal" 问题,如果您有生日,那么像这样简单的事情应该可行:

require 'date'
birth_day = Date.new(1963,9,2)
str = "02091963"
str == birth_day.strftime("%d%m%Y")
#=> true

尽管对于最后一个,我建议比较多种格式,例如%Y%m%d%m%d%Y 等你甚至可以做类似

str.chars.sort == birth_day.strftime("%d%m%Y").chars.sort
#=> true

确保他们不只是以某种混乱的格式使用这些数字。

希望这能帮助您入门,因为我不知道您对 "good" 和 "bad" 的阈值是多少,这些只是检查值的建议。尽管 "good" 的定义似乎不应该是 "bad"。有点像有效性检查。

如果我使用方法 1 和 2(或组合方法)建议分数 < 4 && 而不是 birth_day 数字的分类可能就足够了,例如

def tester(str,birth_date)
  return false if ![6,8].include?(str.size)
  b_day = birth_date.strftime("%Y%m%d").chars.sort
  str.chars.map(&:to_i).each_cons(2).select  do |a,b| 
    (a + 1) == b || 
    (a - 1) == b || 
    a == b 
  end.count < 4 && b_day != str.chars.sort
end
tester("00112233",Date.new(1963,9,2))
#=> false
tester("18745098",Date.new(1963,9,2))
#=> true

似乎适用于您的示例

arry = ["00117788","88886611","12345678","98765432","02091963","18745098","90574808","07629301"]
Hash[arry.map{|v| [v,tester(v,Date.new(1963,9,2))]}]
#=>=> {"00117788"=>false, "88886611"=>false, 
       "12345678"=>false, "98765432"=>false, 
       "02091963"=>false, "18745098"=>true, 
       "90574808"=>true, "07629301"=>true}