我即将推出一项新的在线服务的测试版。测试版订阅者将收到一个唯一的“访问代码”,允许他们注册该服务。
而不是存储访问代码列表,我想我会根据他们的电子邮件生成一个代码,因为这本身是独一无二的。
我最初的想法是将电子邮件与唯一的字符串结合起来,然后进行Base64编码。但是,我一直在寻找更短的代码,比如 5 位数长。
我即将推出一项新的在线服务的测试版。测试版订阅者将收到一个唯一的“访问代码”,允许他们注册该服务。
而不是存储访问代码列表,我想我会根据他们的电子邮件生成一个代码,因为这本身是独一无二的。
我最初的想法是将电子邮件与唯一的字符串结合起来,然后进行Base64编码。但是,我一直在寻找更短的代码,比如 5 位数长。
如果访问代码本身需要唯一,则很难确保不会发生冲突。如果您可以容忍两个用户可能会巧合地共享相同的访问代码的情况,那么这将变得更加容易。
如提议的那样,采用与已知字符串连接的电子邮件地址的 base-64 编码可能会引入安全漏洞。如果您使用与已知单词连接的电子邮件地址的 base64 输出,则用户只需对访问代码进行解密并推导出用于生成代码的算法。
一种选择是采用已知密钥的电子邮件地址的 SHA-1-HMAC 哈希 (System.Cryptography.HMACSHA1)。哈希的输出是一个 20 字节的序列。然后,您可以确定性地截断散列。例如,在下面,GetCodeForEmail("test@example.org")
给出一个代码 'PE2WEG' :
// define characters allowed in passcode. set length so divisible into 256
static char[] ValidChars = {'2','3','4','5','6','7','8','9',
'A','B','C','D','E','F','G','H',
'J','K','L','M','N','P','Q',
'R','S','T','U','V','W','X','Y','Z'}; // len=32
const string hashkey = "password"; //key for HMAC function -- change!
const int codelength = 6; // lenth of passcode
string GetCodeForEmail(string address)
{
byte[] hash;
using (HMACSHA1 sha1 = new HMACSHA1(ASCIIEncoding.ASCII.GetBytes(hashkey)))
hash = sha1.ComputeHash(UTF8Encoding.UTF8.GetBytes(address));
int startpos = hash[hash.Length -1] % (hash.Length - codelength);
StringBuilder passbuilder = new StringBuilder();
for (int i = startpos; i < startpos + codelength; i++)
passbuilder.Append(ValidChars[hash[i] % ValidChars.Length]);
return passbuilder.ToString();
}
您可以从他们的电子邮件中创建一个小于 6 个字符的特殊哈希,但它不会真正使那个“独特”,在这么小的空间里总会有冲突。我宁愿使用更长的密钥,或者无论如何将预先生成的代码存储在表中。
因此,正如@can poyragzoglu 指出的那样,听起来您在这里要做的是专门为电子邮件创建一个哈希函数。一个非常简单的可能看起来像这样:
(伪代码) foreach char c in email: running total += [large prime] * [unicode value]
然后运行总 % 大 5 位数字
正如他指出的那样,除非您拥有出色的哈希函数,否则这不会是唯一的。你很可能会发生碰撞。不确定这是否重要。
对我来说似乎更容易的是,如果您已经知道有效的电子邮件,只需在注册时根据您的有效电子邮件列表检查用户的电子邮件?为什么要打扰代码呢?
如果你真的想要一个唯一的标识符,最简单的方法可能就是使用所谓的 GUID。C# 本机支持此. 您可以将其存储在您的用户表中。虽然,用户记住/输入的时间太长了,但如果这是你想要做的,几乎可以肯定每个人都是独一无二的。