2017-08-18 68 views
1

我有一个整数列表(emplyoee的ID) 他们是8位长(虽然几乎所有启动00,但它们是有效的8位数字)基于输入号码随机密钥

为每位员工我需要生成一个关键是:

- 5 chars including [A-Z][a-z][0-9] 
- Must include 1 of [A-Z] 
- Must include 1 of [0-9] 
- Generated key must be unique 
- If I know an employees ID I should not be able to determine their key 

我需要生成算法,将生成的密钥,但我想,以避免可能的话,记录键针对员工。我越想我遇到的问题就越多。

如果我能避免它,我不想生成所有的密钥,并将它们存储的地方 - 我宁愿他们是实时计算

允许我藏在我的系统中一个秘密,我可以除非你知道秘密,否则确保密钥不确定。

我想过使用标准哈希algroythms(含盐),但目标空间的限制和包括1 A-Z和1 0-9的限制似乎阻止了这一点。

的一种方式,我想我可能会用它来解决这个问题:

1. Build a deteremnistic function that maps integers starting from 1 [1, 2, 3, ...] to every possible result value 
2. Map integers [1, 2, ...] to random other integers in the desired range [324, 43565, ...] in a way that preserves uniqueness (based on a secret salt which if changed would result in a different order). 

这将保证唯一性,但第1步是棘手。结果集是不连续的,有些值可能会丢失大写字母,而其他值会丢失一个数字。

我可以通过开始每个代码与A1技术上可行,但减少结果空间从5个字符到3个字符。

任何人都可以建议一些简单的工作,并避免我必须记录所有生成的结果进行独特的检查吗?

+1

对于密码编码部分:取自[A-Z]的第一个字符,取自[0-9]的第二个字符和整个集合中剩下的三个字符。这给你26 * 10 * 62 * 62 * 62(= 61,965,280)的可能性。这并不完全覆盖8位数字,而是接近 - 所以你可能不需要改变[A-Z]和[0-9]的位置。有了一些数学,你可以在密码和[0-61,965,279]之间转换。 –

+0

如果您确实需要覆盖整个8位数范围,请将50,000,000以下的地图数字映射到[AZ] [0-9] [?] [?] [?]以及上面的[0-9] [AZ] [? ] [?] [?]。字符串模式不重叠。字符串生成和解析的决定很简单:数字低于50,000,000,而第一个字符是字母。 –

+0

我很高兴我在这里发布拉尔夫,那个答案是1号的路要走。从员工ID到密钥的确定性,唯一性和秘密映射函数的任何想法? – Robert3452

回答

1

正如Ralf所提到的,实现所需密钥变化的最简单方法是可能更改大写字母和数字的位置,从而为您提供2 * 26 * 10 * 62 * 62 * 62>120000000可能的组合。

为了使密钥不能直接从员工ID推导出来,我建议使用另一个秘密8位数的简单XOR。然后使用一个简单的模数,然后对每个字符进行除法。

char = x % 62 
x = (x - (x % 62))/62 

例如在javascript:

function ID2Key(id, secret) { 
    var table = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; 
    var key = new Array(5); // Initialize the key 
    // Changed XOR to a ROT10 
    // var scrambled = id^secret; // "Encrypt" the employee ID with a secret 
    var scrambled = 0; 
    while (id) { 
     var rotated = ((id % 10) + (secret % 10)) % 10; 
     scrambled = (scrambled * 10) + rotated; 
     id = Math.floor(id/10); 
     secret = Math.floor(secret/10) 
    } 

    var capital_index = scrambled % 2; // Determine if the Capital letter should be first 
    scrambled = (scrambled - capital_index)/2; 
    var capital = table[36 + (scrambled % 26)]; // Find the capital letter 
    key[capital_index] = capital; 
    scrambled = (scrambled - (scrambled % 26))/26; 

    var num = scrambled % 10; // Find the number 
    key[1-capital_index] = table[num]; // If the capital letter is first place the number second and visa versa 
    scrambled = (scrambled - (scrambled % 10))/10; 

    // Find the remaining 3 characters 
    key[2] = table[scrambled % 62]; 
    scrambled = (scrambled - (scrambled % 62))/62; 

    key[3] = table[scrambled % 62]; 
    scrambled = (scrambled - (scrambled % 62))/62; 

    key[4] = table[scrambled % 62]; 
    return key.join(""); 
} 

现场演示JS Bin

编辑解决XOR故障 - 为了解决故障的情况下在评论中长大的我改变加扰的方法ID转换为基于现在也可以是8位数字的秘密的旋转。

编辑澄清漏洞 - 由于我现在了解了一些更好的要求,主要是员工会知道他们的ID和密钥,我应该澄清一些密码学概念。鉴于相当小的输入范围和限制性输出,没有可能的方法来使密钥安全。即使使用像128位AES这样已经很好建立的加密算法,所产生的强度也不会比最多的暴力破解尝试更好,这对于计算来说是微不足道的。考虑到这一点,唯一具有某种安全外表的方法是秘密该算法保持秘密。在这种情况下,试图从ID和密钥派生密钥的人不知道他们是正确的,除非他们能够访问多个ID密钥对。

+0

两个“随机”8位数字的XOR可能会导致9位数字(最多134,217,727),这比我们的编码方案可以覆盖的2 * 61,965,280范围略高。因此,我们可以添加第三个编码范围[A-Z] [A-Z] [0-9] [?] [?],给出另外26 * 26 * 10 * 62 * 62的可能性,但不与前两个范围重叠。 –

+0

@RalfKleberhoff不错的一点是,不幸的是,做出这样的改变会将所得密钥的加密“强度”从“308873088”降低到“179345664”,所以对于有效机密的范围可能更好,因为这在理论上是更好的[一次性填充](https://en.wikipedia.org/wiki/One-time_pad),因此秘密即使非常短也不可破解。如果我找不到更好的方法 – Joel

+0

另外每个员工都会知道他们的ID和他们的密钥,所以如果我明白你说的话可以计算出这个秘密 – Robert3452