我想生成一个个人ID。由于Moodle的插件,我有以下限制:
ID不应该是随机数。如果可能的话,我希望能够通过该人的一些基本信息重新创建它。
我的方法:
目前,我执行以下步骤来生成ID。
1)我接受主键,firstname和lastname并执行MD5哈希。
USE `bpmspace_coms_v1`;
DELIMITER //
DROP PROCEDURE IF EXISTS demo_data;
//
CREATE PROCEDURE demo_data()
begin
DECLARE x SMALLINT DEFAULT 0;
while x < 100
do
SET @lastname = generate_lname();
SET @firstname = generate_fname();
INSERT INTO .`coms_participant` (`coms_participant_lastname`, `coms_participant_firstname`, `coms_participant_public`, `coms_participant_placeofbirth`, `coms_participant_birthcountry`) VALUES (@lastname, @firstname, '0', str_random('Cccc(4)'), str_random('Cccc(7)'));
SET @lastid = LAST_INSERT_ID();
INSERT INTO `coms_participant_identifier` (`coms_participant_id`, `coms_participant_matriculation`, `coms_participant_md5`) VALUES (@lastid, @lastid, md5(concat(@lastid,@firstname,@lastname)));
set x = x+1;
end while;
END;
//
DELIMITER ;
call demo_data()
2)然后我剪切了前7个十六进制值(fffffff = 268.435.455)并将它们转换为数字
UPDATE `coms_participant_identifier` set `coms_participant_matriculation` = CONV(SUBSTRING(coms_participant_md5,1,7),16,10) where true;
有更好的方法吗?你什么时候想碰撞?
感谢您的帮助,
罗布
以下是涉及的2个表的创建语句
CREATE TABLE `coms_participant` (
`coms_participant_id` int(11) NOT NULL AUTO_INCREMENT,
`coms_participant_lastname` varchar(60) DEFAULT NULL,
`coms_participant_firstname` varchar(60) DEFAULT NULL,
`coms_participant_public` tinyint(4) DEFAULT '0',
`coms_participant_placeofbirth` varchar(60) DEFAULT NULL,
`coms_participant_birthcountry` varchar(60) DEFAULT NULL,
`coms_participant_dateofbirth` date DEFAULT NULL,
`coms_participant_LIAM_id` int(11) NOT NULL,
PRIMARY KEY (`coms_participant_id`)
) ENGINE=InnoDB AUTO_INCREMENT=52807563 DEFAULT CHARSET=utf8;
CREATE TABLE `coms_participant_identifier` (
`coms_participant_identifier_id` int(11) NOT NULL AUTO_INCREMENT,
`coms_participant_id` int(11) NOT NULL,
`coms_participant_matriculation` double NOT NULL,
`coms_participant_md5` varchar(32) DEFAULT NULL,
PRIMARY KEY (`coms_participant_identifier_id`),
UNIQUE KEY `coms_participant_identifier_id_UNIQUE` (`coms_participant_identifier_id`)
) ENGINE=InnoDB AUTO_INCREMENT=229583147 DEFAULT CHARSET=utf8;
我使用来自https://thecodecave.com/tag/mysql/的generate_lname()generate_fname() 和http://moinne.com/blog/ronald/mysql/howto-generate-meaningful-test-data-using-a-mysql-function
中的str_random()答案 0 :(得分:1)
1)我接受主键,firstname和lastname并执行MD5哈希。
如果您不必使用MD5,请不要这样做。它完全坏了。 SHA-1也在摇摇欲坠。使用SHA-256。虽然因为下一部分而有点没有实际意义......
我想生成一个个人ID。由于Moodle的插件,我有以下限制:
- ID不得超过9
- 该ID必须仅包含数字[0-9]
这很糟糕。这意味着只有10亿个可能的ID可能看起来很多,但它非常小,大约30位。使用小的密钥空间将发生哈希冲突。您的实现仅使用其中28个位,使其更小。别担心,这2位不重要。
当两个字符串具有相同的哈希值时,会发生哈希冲突。通常这不是一个问题,因为哈希空间太大,但你的非常小。例如,SHA-1比160位大40个数量级。 40 orders of magnitude is the difference between the size of a virus and the size of a planet.只有10亿种可能性,你很可能会发生碰撞,这比你想象的要大得多。
您可能会认为&#34;如果我有10亿个ID并且我有100万用户,那么只有1/1000的碰撞机会&#34;但它并没有这样做。这称为the Birthday Problem,其漏洞被称为the Birthday Attack。简而言之,在大约10,000到20,000个用户中,你有50/50的碰撞几率。
我使用/usr/share/dict/words
进行了短暂的模拟,并在11371个单词后发生了碰撞。
require "digest"
hashes = {}
count = 0
File.new("/usr/share/dict/words").each { |line|
line.chomp!
count += 1
hash = Digest::MD5.hexdigest(line)[0..6]
if hashes[hash]
puts "#{line} collides with #{hashes[hash]} after #{count} words: #{hash}"
end
hashes[hash] = line
}
aplasia collides with antefurcal after 11371 words: 7417bf5
circumvolant collides with angelicalness after 36704 words: d8ae33c
debord collides with Actinopteri after 49183 words: c43674a
dichromasy collides with acetolytic after 53190 words: 102ef7d
diplosphene collides with aruke after 54247 words: cdce4ec
divaricate collides with chemurgic after 56200 words: b7d936c
draftily collides with backvelder after 57533 words: dcb75a2
firefall collides with Cytophaga after 70180 words: ae25f13
...
这意味着您需要resolving that collision的某种方式。这意味着无法预测给定用户获得的哈希值,因为它们被散列的顺序很重要。
有了这么小的键空间,人们通过蛮力制作有效的密钥会相对简单。
考虑到这么小的密钥空间,我会问一些基本的问题。