整数算法/方法的对称密码

时间:2019-06-18 21:56:26

标签: python algorithm encryption shuffle

我正在寻找一种双射变换,可以将不用于加密,但可以将其用于混淆。这个想法是采用整数1, 2, 3, 4并将它们投影到另一个轴上。主要思想是在投影到域A中时确保与域B相邻的两个整数之间的最大距离。

我用Python编写了以下内容,但目标语言将是PHP。我不在乎实现,仅算法/方法很重要。

n = 8的示例:

A     B
0 <-> 4
1 <-> 5
2 <-> 6
3 <-> 0
4 <-> 2
5 <-> 7
6 <-> 3
7 <-> 1

一种简单的实现方式是建立一个随机的一对一对应表,然后将其用作 O(1)转换函数。

a = func(0) # a = 4
b = func(a) # b = 0

最有效的算法

最有效的算法包括构建一个哈希表,该哈希表需要 O(n)内存并在 O(1)中执行。

class Shuffle:
    def __init__(self, n, seed=42):        
        self._table = list(range(n))
        random.seed(seed)
        random.shuffle(self._table)

    def enc(self, n):
        return self._table[n]

    def dec(self, n):
        return self._table.index(n)

不幸的是,我正在寻找一种更轻或更简单的算法。

哑巴尝试

这是有趣的部分,因为我尝试使用一次性键盘(OTP)和一些对称加密算法(河豚)而没有成功。最终,我尝试使用一种愚蠢而有趣的天真实现:

def enigma(input): # Because why not?
    a = deque([1, 3, 0, 4, 2])
    b = deque([3, 0, 4, 2, 1])
    u = [0 for i in range(len(input))]
    for i, c in enumerate(input):
        u[i] = a.index(b.index([4, 3, 2, 1, 0][b[a[c]]]))
        a.rotate(1)
        b.rotate(3)    
    return u

def shuffle(n, seed=81293): # Because enigma is not enough
    random.seed(seed)
    serie = list(range(len(n)))
    random.shuffle(serie)
    for i, j in enumerate(serie):
        n = n.copy()
        n[i], n[j] = n[j], n[i]
        return n

def int2five(decimal): # Base 10 -> Base 5
    radix = 5
    s = [0 for i in range(9)]
    i = 0
    while (decimal):
        s[i] = decimal % radix
        decimal = decimal // radix
        i += 1
    return list(reversed(s))

def five2int(five): # Base 5 -> Base 10
    return int(''.join([str(x) for x in five]), 5)

def enc(n):
    return five2int(enigma(shuffle(int2five(n))))

def dec(s):
    return five2int(shuffle(enigma(int2five(s))))

结果:

>>> ['%d <-> %d' % (i, enc(i)) for i in range(7)]
['0 <-> 1729928',
 '1 <-> 558053',
 '2 <-> 1339303',
 '3 <-> 948678',
 '4 <-> 167428',
 '5 <-> 1729943',
 '6 <-> 558068']

我为什么选择基数5?我将工作范围选择为[0..2e6[,因此,通过寻找可以最大覆盖范围的最佳基础(是的,下面的代码很难看):

>>> [(d, l, s, 100 - round(s/n*100,1)) for (d, l, s) in sorted([(k, round(math.log(n, k), 3), n - k**(math.floor(math.log(n, k))) - 1)
        for k in range(2, 100)], key=lambda k: k[2])[0:10]]

[(5, 9.015, 46873, 97.7),
 (18, 5.02, 110430, 94.5),
 (37, 4.018, 125837, 93.7),
 (11, 6.051, 228437, 88.6),
 (6, 8.097, 320382, 84.0),...]

我注意到可以以9位数字表示5的基数,覆盖范围为我范围的97%。第二好的人选是18分,覆盖率达到94%。

1 个答案:

答案 0 :(得分:0)

就像您要在这里使用Format-Preserving Encryption一样,Mihir Bellare的FFX是很好的选择(白皮书here)。

您注意到,您不会找到任何基于旋转的简单算法,该算法可以将this.的输入域X映射到Y,而{{ 1}}和Y = X在任意范围f: X->Y中。

使用这种保留格式的格式,您需要将范围指定为:

X

在您的情况下,您选择了基数5和9。

使用FFX加密

对于实现,您可以使用pyffx,这是基于Feistel的加密(FFX)的实现。

[x0..xn]

然后

range = radix ** exponent - 1

在任意域上加密

如前所述,FFF仅对class Five(pyffx.String): def __init__(self, ffx, length, **kwargs): super(Five, self).__init__(ffx, '01234', length, **kwargs) def pack(self, v): return super(Five, self).pack(str(v).zfill(self.length)) def unpack(self, v, t): return int(super(Five, self).unpack(v, t)) 指定的域中的数据进行加密。如果您希望在任意域上加密,则可以使用名为 Cycle Walking 的方法,描述为:

>>> import pyffx
>>> radix, exponent = 5, 9
>>> e = Five(b'secret', exponent)
>>> e.encrypt(123)
321301321

为此,您需要使用严格大于目标域M的域N。