如何生成一个独特,小巧,随机且用户友好的密钥?

时间:2021-09-10 08:28:30

A few months back I was tasked with implementing a unique and random code for our web application. The code would have to be user friendly and as small as possible, but still be essentially random (so users couldn't easily predict the next code in the sequence).

几个月前,我的任务是为我们的Web应用程序实现一个独特的随机代码。代码必须是用户友好的并且尽可能小,但仍然基本上是随机的(因此用户无法轻易预测序列中的下一个代码)。

It ended up generating values that looked something like this:

它最终生成的值看起来像这样:

Af3nT5Xf2

Unfortunately, I was never satisfied with the implementation. Guid's were out of the question, they were simply too big and difficult for users to type in. I was hoping for something more along the lines of 4 or 5 characters/digits, but our particular implementation would generate noticeably patterned sequences if we encoded to less than 9 characters.

不幸的是,我对实施从未满意。 Guid是不可能的,它们对于用户来说太大而且难以输入。我希望更多的东西可以是4或5个字符/数字,但是如果编码为我们的特定实现会生成明显的图案序列少于9个字符。

Here's what we ended up doing:

这是我们最终做的事情:

We pulled a unique sequential 32bit id from the database. We then inserted it into the center bits of a 64bit RANDOM integer. We created a lookup table of easily typed and recognized characters (A-Z, a-z, 2-9 skipping easily confused characters such as L,l,1,O,0, etc.). Finally, we used that lookup table to base-54 encode the 64-bit integer. The high bits were random, the low bits were random, but the center bits were sequential.

我们从数据库中提取了一个唯一的顺序32位id。然后我们将它插入64位RANDOM整数的中心位。我们创建了一个易于输入和识别的字符的查找表(A-Z,a-z,2-9跳过容易混淆的字符,如L,l,1,O,0等)。最后,我们使用该查找表对64位整数进行base-54编码。高位是随机的,低位是随机的,但中心位是顺序的。

The final result was a code that was much smaller than a guid and looked random, even though it absolutely wasn't.

最后的结果是一个比guid小得多的代码并且看起来是随机的,即使它绝对不是。

I was never satisfied with this particular implementation. What would you guys have done?

我对此特定实现从未满意。你们会做什么的?

5 个解决方案

#1


7  

Here's how I would do it.

这是我怎么做的。

I'd obtain a list of common English words with usage frequency and some grammatical information (like is it a noun or a verb?). I think you can look around the intertubes for some copy. Firefox is open-source and it has a spellchecker... so it must be obtainable somehow.

我会得到一个常用英语单词列表,其中包含使用频率和一些语法信息(如名词或动词?)。我想你可以在intertubes周围查看一些副本。 Firefox是开源的,它有一个拼写检查程序......所以它必须以某种方式获得。

Then I'd run a filter on it so obscure words are removed and that words which are too long are excluded.

然后我会在它上面运行一个过滤器,这样就可以删除模糊的单词并排除那些太长的单词。

Then my generation algorithm would pick 2 words from the list and concatenate them and add a random 3 digits number.

然后我的生成算法将从列表中选择2个单词并连接它们并添加一个随机的3位数字。

I can also randomize word selection pattern between verb/nouns like

我也可以在动词/名词之间随机化单词选择模式

eatCake778
pickBasket524
rideFlyer113 etc..

eatCake778 pickBasket524 rideFlyer113等。

the case needn't be camel casing, you can randomize that as well. You can also randomize the placement of the number and the verb/noun.

案件不一定是驼峰套管,你也可以随机化。您还可以随机化数字和动词/名词的位置。

And since that's a lot of randomizing, Jeff's The Danger of Naïveté is a must-read. Also make sure to study dictionary attacks well in advance.

而且由于这是很多随机化,杰夫的Naïveté的危险是必读的。还要确保提前学习字典攻击。

And after I'd implemented it, I'd run a test to make sure that my algorithms should never collide. If the collision rate was high, then I'd play with the parameters (amount of nouns used, amount of verbs used, length of random number, total number of words, different kinds of casings etc.)

在我实现之后,我会进行测试以确保我的算法永远不会发生碰撞。如果碰撞率很高,那么我会玩参数(使用的名词数量,使用的动词数量,随机数的长度,单词总数,不同类型的外壳等)

#2


3  

In C#, I have used the 'System.IO.Path.GetRandomFileName() : String' method... but I was generating salt for debug file names. This method returns stuff that looks like your first example, except with a random '.xyz' file extension too.

在C#中,我使用了'System.IO.Path.GetRandomFileName():String'方法......但我正在为调试文件名生成salt。此方法返回的内容看起来像您的第一个示例,除了随机的“.xyz”文件扩展名。

If you're in .NET and just want a simpler (but not 'nicer' looking) solution, I would say this is it... you could remove the random file extension if you like.

如果你在.NET中并且只想要一个更简单(但不是'更好看')的解决方案,我会说这就是它......如果你愿意,可以删除随机文件扩展名。

#3


3  

In .NET you can use the RNGCryptoServiceProvider method GetBytes() which will "fill an array of bytes with a cryptographically strong sequence of random values" (from ms documentation).

在.NET中,您可以使用RNGCryptoServiceProvider方法GetBytes(),它将“使用加密强大的随机值序列填充字节数组”(来自ms文档)。

byte[] randomBytes = new byte[4];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(randomBytes);

You can increase the lengh of the byte array and pluck out the character values you want to allow.

您可以增加字节数组的长度并选择要允许的字符值。

#4


0  

If by user friendly, you mean that a user could type the answer in then I think you would want to look in a different direction. I've seen and done implementations for initial random passwords that pick random words and numbers as an easier and less error prone string.

如果用户友好,你的意思是用户可以输入答案,那么我想你会想要看一个不同的方向。我已经看到并完成了初始随机密码的实现,这些密码选择随机单词和数字作为一个更容易且不易出错的字符串。

If though you're looking for a way to encode a random code in the URL string which is an issue I've dealt with for awhile then I what I have done is use 64-bit encoded GUIDs.

如果你正在寻找一种方法来编码URL字符串中的随机代码,这是我已经处理了一段时间的问题,那么我所做的就是使用64位编码的GUID。

#5


0  

You could load your list of words as chakrit suggested into a data table or xml file with a unique sequential key. When getting your random word, use a random number generator to determine what words to fetch by their key. If you concatenate 2 of them, I don't think you need to include the numbers in the string unless "true randomness" is part of the goal.

您可以将chakrit建议的单词列表加载到具有唯一顺序键的数据表或xml文件中。获取随机单词时,使用随机数生成器确定要通过其键获取的单词。如果你连接其中的2个,我认为你不需要在字符串中包含数字,除非“真正的随机性”是目标的一部分。

#1


7  

Here's how I would do it.

这是我怎么做的。

I'd obtain a list of common English words with usage frequency and some grammatical information (like is it a noun or a verb?). I think you can look around the intertubes for some copy. Firefox is open-source and it has a spellchecker... so it must be obtainable somehow.

我会得到一个常用英语单词列表,其中包含使用频率和一些语法信息(如名词或动词?)。我想你可以在intertubes周围查看一些副本。 Firefox是开源的,它有一个拼写检查程序......所以它必须以某种方式获得。

Then I'd run a filter on it so obscure words are removed and that words which are too long are excluded.

然后我会在它上面运行一个过滤器,这样就可以删除模糊的单词并排除那些太长的单词。

Then my generation algorithm would pick 2 words from the list and concatenate them and add a random 3 digits number.

然后我的生成算法将从列表中选择2个单词并连接它们并添加一个随机的3位数字。

I can also randomize word selection pattern between verb/nouns like

我也可以在动词/名词之间随机化单词选择模式

eatCake778
pickBasket524
rideFlyer113 etc..

eatCake778 pickBasket524 rideFlyer113等。

the case needn't be camel casing, you can randomize that as well. You can also randomize the placement of the number and the verb/noun.

案件不一定是驼峰套管,你也可以随机化。您还可以随机化数字和动词/名词的位置。

And since that's a lot of randomizing, Jeff's The Danger of Naïveté is a must-read. Also make sure to study dictionary attacks well in advance.

而且由于这是很多随机化,杰夫的Naïveté的危险是必读的。还要确保提前学习字典攻击。

And after I'd implemented it, I'd run a test to make sure that my algorithms should never collide. If the collision rate was high, then I'd play with the parameters (amount of nouns used, amount of verbs used, length of random number, total number of words, different kinds of casings etc.)

在我实现之后,我会进行测试以确保我的算法永远不会发生碰撞。如果碰撞率很高,那么我会玩参数(使用的名词数量,使用的动词数量,随机数的长度,单词总数,不同类型的外壳等)

#2


3  

In C#, I have used the 'System.IO.Path.GetRandomFileName() : String' method... but I was generating salt for debug file names. This method returns stuff that looks like your first example, except with a random '.xyz' file extension too.

在C#中,我使用了'System.IO.Path.GetRandomFileName():String'方法......但我正在为调试文件名生成salt。此方法返回的内容看起来像您的第一个示例,除了随机的“.xyz”文件扩展名。

If you're in .NET and just want a simpler (but not 'nicer' looking) solution, I would say this is it... you could remove the random file extension if you like.

如果你在.NET中并且只想要一个更简单(但不是'更好看')的解决方案,我会说这就是它......如果你愿意,可以删除随机文件扩展名。

#3


3  

In .NET you can use the RNGCryptoServiceProvider method GetBytes() which will "fill an array of bytes with a cryptographically strong sequence of random values" (from ms documentation).

在.NET中,您可以使用RNGCryptoServiceProvider方法GetBytes(),它将“使用加密强大的随机值序列填充字节数组”(来自ms文档)。

byte[] randomBytes = new byte[4];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(randomBytes);

You can increase the lengh of the byte array and pluck out the character values you want to allow.

您可以增加字节数组的长度并选择要允许的字符值。

#4


0  

If by user friendly, you mean that a user could type the answer in then I think you would want to look in a different direction. I've seen and done implementations for initial random passwords that pick random words and numbers as an easier and less error prone string.

如果用户友好,你的意思是用户可以输入答案,那么我想你会想要看一个不同的方向。我已经看到并完成了初始随机密码的实现,这些密码选择随机单词和数字作为一个更容易且不易出错的字符串。

If though you're looking for a way to encode a random code in the URL string which is an issue I've dealt with for awhile then I what I have done is use 64-bit encoded GUIDs.

如果你正在寻找一种方法来编码URL字符串中的随机代码,这是我已经处理了一段时间的问题,那么我所做的就是使用64位编码的GUID。

#5


0  

You could load your list of words as chakrit suggested into a data table or xml file with a unique sequential key. When getting your random word, use a random number generator to determine what words to fetch by their key. If you concatenate 2 of them, I don't think you need to include the numbers in the string unless "true randomness" is part of the goal.

您可以将chakrit建议的单词列表加载到具有唯一顺序键的数据表或xml文件中。获取随机单词时,使用随机数生成器确定要通过其键获取的单词。如果你连接其中的2个,我认为你不需要在字符串中包含数字,除非“真正的随机性”是目标的一部分。