因此,我正在尝试使用仿射密码对邮件进行加密。我想使用所有128个ASCII字符来做到这一点。关于特定字母Q,R,S,T和U,我遇到错误。它们无法正确转换回原位并显示不正确的解密。有什么想法吗?
加密的邮件
Sub ProtectSheetCheckSpellCheck()
'Update by Extendoffice 2018/11/2
Dim xRg As Range
On Error Resume Next
Application.ScreenUpdating = False
With ActiveSheet
.Unprotect ("Password123")
Set xRg = .UsedRange
xRg.CheckSpelling
.Protect Password:="Password123", AllowInsertingRows:=True, AllowInsertingColumns:=True
End With
Application.ScreenUpdating = True
End Sub
解密的邮件
RUX[^adgjmpsvy|
我的代码;
ABCDEFGHIJKLMNOP/.-,+VWXYZ
答案 0 :(得分:3)
问题的原因是,对于负分红a
和/或除数n
,modulo operation的数学定义通常可能与相应编程语言中的定义不同。
模运算的结果在数学上定义为Euclidean division的其余部分。该余数始终大于或等于零。对于正除数n
,余数由下式给出:
a mod n = a - n * floor(a/n)
其中floor(a/n)
是floor
-function,它给出的最大整数小于或等于其输入(我不认为负除数n
是因为n = 128 > 0
在问题)。
正除数n = 128
(正分红a = 559
(上)和负除数a = -559
(下)的示例:
559 mod 128 = 559 - 128 * floor(559/128) = 559 - 128 * floor(4.37) = 559 -128 * 4 = 47
-559 mod 128 = -559 - 128 * floor(-559/128) = -559 - 128 * floor(-4.37) = -559 -128 * (-5) = 81
但是,在许多编程语言(包括Java)中,对模运算使用不同的定义(有时称为对称变量):
a mod n = a - n * trunc(a/n)
此处,trunc(a/n)
表示商a/n
朝四舍五入的舍位除法。
正除数n = 128
(正股息为a = 559
(上)和负股息为a = -559
(如下)的示例:
559 mod 128 = 559 - 128 * trunc(559/128) = 559 - 128 * trunc(4.37) = 559 -128 * 4 = 47
-559 mod 128 = -559 - 128 * trunc(-559/128) = -559 - 128 * trunc(-4.37) = -559 -128 * (-4) = -47
正如人们所看到的,无论是数学定义还是对称定义,都为负红利提供了不同的结果。
此问题的直接原因是,仿射密码的公式中是 mathematical 定义,而在代码中使用了 symmetrical 变体(因为Java使用对称变体)。可以通过字母Q
的示例很好地证明这一点:在您的代码中,字母Q
(= 81 dec
)是加密的(A = 3
,B = 15
, M = 128
到
(3 * 81 + 15) % 128 = 2
解密(A = 43
,B = 15
,M = 128
)是
(43 * (2 - 15)) % 128 = -559 % 128
取决于模变量,对称变量和数学变量的结果分别为-47
和81
(请参见上文)。由于代码中使用了对称变体,因此您会得到“错误”结果-47
。
因此,解决方案是将代码中的模运算转换为数学定义。这可以通过以下公式实现:
a mMod n = ((a sMod n) + n) sMod n
其中mMod
和sMod
分别表示数学和对称模运算符。为此,定义一个新方法:
private static int mathematicalMod(int a, int n) {
return ((a % n) + n) % n;
}
并替换为affineEncryption
方法
encryption.append((char)((A * s.charAt(i) + B) % M));
使用
encryption.append((char)mathematicalMod(A * s.charAt(i) + B, M));
以及affineDecryption
方法
decryption.append((char)((A * Math.abs((s.charAt(i) - B))) % M));
使用
decryption.append((char)mathematicalMod(A * (s.charAt(i) - B), M));
请注意,在后一种替换中,Math.abs
方法也被删除,因为它不属于affine-cipher-decrypt-algorithm。
进行了这些更改,然后输入以下内容
StringBuilder s = new StringBuilder("AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0=1!2\"34$5%6&7/8(9)^`+*#'-_.:,;<>\\[]~{}|@");
控制台中的输出变为:
在Java中,还有一个对称变体的实现:int Math.floorMod(int a, int n)
,当然也可以代替自定义实现int mathematicalMod(int a, int n)
使用。