【问题标题】:Encrypting/Decrypting a string using a Affine cipher using the original 128 ASCII table使用原始 128 ASCII 表使用仿射密码加密/解密字符串
【发布时间】:2019-02-07 22:46:24
【问题描述】:

所以我正在尝试使用仿射密码加密消息。我想使用所有 128 个 ASCII 字符来完成它。当涉及到特定字母 Q、R、S、T 和 U 时,我收到错误消息。它们没有正确转换回来并显示不正确的解密。有什么想法吗?

加密消息

RUX[^adgjmpsvy|

解密消息

ABCDEFGHIJKLMNOP/.-,+VWXYZ

我的代码;

public class EncryptionProject {

   public static void main(String[] args) {

        StringBuilder s = new StringBuilder("ABCDEFGHIJKLMNOPQRSTUVWXYZ");

        System.out.println("Encrypted Message");
        StringBuilder encryptedMessage = affineEncryption(s);
        System.out.print(encryptedMessage);

        System.out.println("\nDecrypted Message");
        StringBuilder decryptedMessage = affineDecryption(encryptedMessage);
        System.out.print(decryptedMessage);
    }

    /* use affine cipher to encrypt message */
    public static StringBuilder affineEncryption(StringBuilder s) {
        StringBuilder encryption = new StringBuilder();
        final int A = 3, B = 15, M = 128; // a * p + b (mod m)

        /* loop through string and compute affine cipher */
        for (int i = 0; i < s.length(); i++) {
            encryption.append((char)((A * s.charAt(i) + B) % M));
        }

        return encryption;
    }

    /* decryption method */
    public static StringBuilder affineDecryption(StringBuilder s) {
        final int A = 43, B = 15, M = 128;
        StringBuilder decryption = new StringBuilder();

        /* loop through and undo affine cipher using inverse of A */
        for (int i = 0; i < s.length(); i++) {
            decryption.append((char)((A * Math.abs((s.charAt(i) - B))) % M));
        }

        return decryption;
    }
}

【问题讨论】:

  • 您很幸运,因为您的函数在您感兴趣的 UTF-16 代码单元 (char) 值的子集上封闭,并且这些代码单元单独使用(相对于有序对, 例如 ????) 来表示该范围内的 Unicode 代码点 (C0 Controls and Basic Latin)。

标签: java encryption ascii stringbuilder


【解决方案1】:

问题的原因是对于负股息a 和/或除数nmodulo operation 的数学定义通常可能与相应编程语言中的定义不同。

模运算的结果在数学上定义为Euclidean division 的余数。该余数始终大于或等于零。对于正除数n,余数由下式给出:

a mod n = a - n * floor(a/n) 

其中floor(a/n)floor-function,它给出小于或等于其输入的最大整数作为输出(我不考虑负除数n,因为问题中的n = 128 &gt; 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 = 3B = 15M = 128)到

(3 * 81 + 15) % 128 = 2

解密(A = 43B = 15M = 128)是

(43 * (2 - 15)) % 128 = -559 % 128

根据模变量的不同,对称变量和数学变量的结果分别为-4781(见上文)。由于代码中使用了对称变体,因此您会得到“错误”结果-47

因此,解决方案是将代码中的模运算转换为数学定义。这可以通过以下公式来实现:

a mMod n  = ((a sMod n) + n) sMod n

其中mModsMod 分别表示数学和对称模运算符。为此,定义一个新方法:

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)

【讨论】:

  • 这样一个问题的好答案。
  • 好的,谢谢。非常彻底。感谢您抽出时间为我解释。
猜你喜欢
  • 1970-01-01
  • 2020-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-10
  • 2021-04-15
  • 2015-07-31
相关资源
最近更新 更多