如果我要加密26个符号的字母集,那么山密码中使用的密钥与加密35个字母集的密钥有什么不同?
答案 0 :(得分:2)
这个想法并没有改变,只是计算略有不同。我记得你在Hill Cipher上的最后一个问题,你真的想为它实现一个CBC模式。而不是计算mod 26,我建议你选择计算mod 256 - 这样你就可以很容易地来回映射密钥,IV和结果密文的字节表示。此外,它允许您使用空格和其他标点符号,您甚至可以使用UTF-8或类似的编码为您的消息。
密钥的概念不会改变mod 256,但它的计算方式会略有不同。不是选择在Z ^ n / 26中可逆的n×n矩阵,而是必须选择在Z ^ n / 256中可逆的矩阵。假设你选择一个3 x 3矩阵,它仍然可以很容易地反转,那么你可以检查你选择的密钥(矩阵)是否是可逆的,检查模数为256的非零行列式,如Wikipedia article中所述。 。键的字节数组表示将只是一个长度为9的数组,从矩阵到数组的直接映射:element(1,2)(假设从零开始索引)将是数组的第五个元素( 1 * 3 + 2)等。
然后,您可以将消息拆分为3字节块(如果最后一个块未对齐到三个字节,则使用某种形式的填充),表示要与键矩阵相乘的向量,从而再次产生3字节输出块。
正如你所看到的,使用mod 256表示非常简洁,因为加密/解密这种方式可以使用相同的接口,也可以用于最先进的块密码,如AES,即你通过将基于字节数组键的加密/解密函数应用于分成适当大小的块/块的消息来加密消息。
生成加密矩阵只需要创建一个随机3x3矩阵,其中包含Z256中的元素,直到找到一个具有非零行列式(mod 256)和模块化逆元素mod 256(我们将使用扩展欧几里得算法计算) )。然后,计算逆矩阵遵循与计算常规3x3矩阵逆相同的规则,除了所有计算都需要在Z256中进行的事实。有一个用于计算3x3矩阵求逆的闭合公式,如here所示。我们可以使用Z256中的模运算来计算完全相同的东西,以得到Z ^ n / 256的逆。
这里有一些生成密钥矩阵的Ruby代码及其逆序:
require 'matrix'
class Integer
def modinv(modulus)
a, b = modulus, self
q, r = a / b, a % b
t0, t1 = 0, 1
while r > 0
t0, t1 = t1, (t0 - q * t1) % modulus
a, b = b, r
q, r = a / b, a % b
end
raise RuntimeError.new("#{self} has no inverse modulo #{modulus}") unless b == 1
t1
end
end
while true
m = Matrix.build(3) { rand(0..256) }
mod_det = m.determinant % 256
next if mod_det == 0
begin
det_inv = mod_det.modinv(256)
break
rescue RuntimeError => e
next
end
end
inv = Matrix[
[ (m[2,2]*m[1,1] - m[2,1]*m[1,2]), -(m[2,2]*m[0,1] - m[2,1]*m[0,2]), (m[1,2]*m[0,1] - m[1,1]*m[0,2])],
[-(m[2,2]*m[1,0] - m[2,0]*m[1,2]), (m[2,2]*m[0,0] - m[2,0]*m[0,2]), -(m[1,2]*m[0,0] - m[1,0]*m[0,2])],
[ (m[2,1]*m[1,0] - m[2,0]*m[1,1]), -(m[2,1]*m[0,0] - m[2,0]*m[0,1]), (m[1,1]*m[0,0] - m[1,0]*m[0,1])]
].map { |e| e * det_inv % 256 }
p m #=> encryption matrix
p inv #=> decryption matrix
identity = (inv * m).map { |e| e % 256 }
p identity #=> living proof that m * inv is the identity matrix
示例输出:
m = Matrix[[167, 8, 48], [54, 107, 25], [170, 184, 107]]
inv = Matrix[[119, 152, 136], [184, 235, 231], [174, 120, 59]]