通过算法从用户ID生成唯一的随机朋友代码

问题描述 投票:0回答:1

我正在寻找一种通过顺序用户ID为用户生成随机,唯一的9位朋友代码的方法。其背后的想法是,人们无法通过逐一搜索朋友代码来枚举用户。如果有1000个可能的密码和100个注册用户,则搜索随机密码应该有10%的机会找到用户。

一种可能的方法是随机生成代码,检查代码是否已在使用中,如果已在使用,请重试。我正在寻找一种方法(通常出于好奇),该方法通过算法生成朋友代码,并确保首先尝试使用该用户ID唯一。

具体来说,给定一个数字范围(1到999,999,999),对此数字运行该函数应返回相同范围内的另一个数字,该数字是成对的,并且与输入数字唯一。仅当范围更改和/或随机性的输入种子更改时,此配对才应不同。

理想情况下,一个人应该不知道种子和算法就不能轻易地从朋友ID反向工程用户ID(或拥有大量样本和大量时间-不需要密码保护) ,因此仅从最大范围中减去用户ID是无效的解决方案。

这是一些c#代码,通过生成整个范围的数字,对列表进行混排,然后通过将用户ID视为列表索引来检索朋友ID,来完成我的工作:

int start = 1; // Starting number (inclusive)
int end = 999999999; // End number (inclusive)
Random random = new Random(23094823); // Random with a given seed

var friendCodeList = new List<int>();
friendCodeList.AddRange(Enumerable.Range(start, end + 1)); // Populate list

int n = friendCodeList.Count;

// Shuffle the list, this should be the same for a given start, end and seed
while (n > 1)
{
    n--;
    int k = random.Next(n + 1);
    int value = friendCodeList[k];
    friendCodeList[k] = friendCodeList[n];
    friendCodeList[n] = value;
}

// Retrieve friend codes from the list
var userId = 1;
Console.WriteLine($"User ID {userId}: {friendCodeList[userId]:000,000,000}");

userId = 99999999;
Console.WriteLine($"User ID {userId}: {friendCodeList[userId]:000,000,000}");

userId = 123456;
Console.WriteLine($"User ID {userId}: {friendCodeList[userId]:000,000,000}");

User ID 1: 054,677,867 User ID 99999999: 237,969,637 User ID 123456: 822,632,399

[不幸的是,这不适合大范围使用-该程序需要8GB的RAM才能运行,并使用10位或12位数字的朋友代码,因此无法在内存或数据库中预先生成列表。我正在寻找不需要此预生成步骤的解决方案。

我对可能使用种子随机数生成器或按位欺骗的解决方案感兴趣。上面的功能是可逆的(通过搜索列表的值),但是解决方案不必是。

c# algorithm random guid
1个回答
2
投票

快速数学课程!

[您正在考虑开发一种方法,将一个整数值(原始的“秘密” UserId值)映射到另一个(加密的“公共”值),然后再次返回。这正是分组密码的功能(除了每个“分组”通常为16字节大,而不是单个字符或整数值)。因此,换句话说,您想创建自己的密码系统。

string)。

也是最大的"dQw4w9WgXcQ"!。

顺便说一句...

提供安全不是头等大事...

...您只关心防止泄露递增的整数Id值(例如,这样您的访问者和用户就看不到您真正拥有多少数据库记录),然后使用Hashids库:hence the "illegal primes" problem back in the late-1990s

对于.NET,请使用此NuGet包:most important take-away from any undergraduate-level computer-science class on cryptography is never create your own cryptosystem

  • [在您的代码中,构造一个https://hashids.org/net/对象(我将使用公共https://github.com/ullmark/hashids.net字段或属性,或者更好的是:一个单例可注入服务),然后使用Hashids方法转换任何整数static readonly / .Encode值转换为int值。
  • 要将Int32值转换回原始的string / string,请使用int方法。

    [顺便说一句,我不喜欢在散列本来是单向函数的情况下将该库称为“ Hashids”-因为该值仍然可逆-尽管使用了秘密的“ salt”值(为什么它不是真正的哈希吗,imo。

  • 如果安全真的很重要...


    然后,您需要将每个整数值视为块密码中的离散块(而不是流密码,因为每个值需要自己单独进行加密和解密)。

    出于实用目的,您需要使用具有较小块大小的

    对称块密码。不幸的是,许多具有小块大小的块密码并不是很好(TripleDES的块大小为64位-但是今天很薄),所以让我们继续使用AES。

    AES具有128位(16字节)的块大小-与彼此串联的两个Int32整数相同。假设您对16个字节的值使用.Decode编码,那么您的输出将为22个字符长(因为Base64每个字符使用6位)。如果您对这样长的字符串感到满意,那么就万事俱备了。 Int64因为Base-73是您可以在所有现代URL传输系统中幸免的URL中可以安全使用的最多(在处理纯文本时,永远不会自动假定在任何地方都支持Unicode)。

    可以调整AES以生成较小的输出块大小,但是在这种情况下base64url无效。

    这里是代码:

    非常重要的注意事项

    这使用CBC模式-这意味着相同的输入将产生相同的输出(这是设计要求!)。当独立加密块时,CBC很有用。

  • because using techniques like CTR Mode mean that the generated output needs to include extra state information (IV, counter, etc) which will end-up taking up the same amount of space as was gained
  • © www.soinside.com 2019 - 2024. All rights reserved.