zoukankan      html  css  js  c++  java
  • 古典密码算法的实现

    1、古典密码可以分为代替密码和置换密码两种,这里实现了代替密码中的仿射变换和置换密码中的换位变换。

    2、仿射变换:

    加密过程:e(x) = ax + b (mod m)

    解密过程:d(e(x)) = a^(-1)*(e(x) - b) mod m

    参数要求:a,m互质;a,b互质;m是集合中元素的个数。(例如当前取1~9和a~z中的所有元素作为集合,m为36)

    加密实现:

     1 import java.util.Scanner;
     2 
     3 public class Main {
     4     public static void main(String []args) {
     5         int m = 36, thisNum, index = 0; // m是集合中元素的个数(例如当前取1~9和a~z中的所有元素作为集合,m为36)
     6         Scanner s = new Scanner(System.in);
     7         // 将输入的字符串转化为字符数组
     8         char[] buff = s.nextLine().toCharArray();
     9         // 参数a、b手动输入
    10         int a = s.nextInt();
    11         int b = s.nextInt();
    12         // 参数要求:a,m互质;a,b互质
    13         while (fun1(m, a) != 1 || fun1(Math.max(a, b), Math.min(a, b)) != 1) {
    14             System.out.println("参数不符合要求,请重新输入");
    15             a = s.nextInt();
    16             b = s.nextInt();
    17         }
    18         for (char i : buff) {
    19             // 由字符转换为数字
    20             if (i > '9') thisNum = (int)i - 87;
    21             else thisNum = (int)i - 48;
    22             // 对该数字加密
    23             thisNum = (thisNum*a+b)%m;
    24             // 加密后再将数字转换为字符
    25             if (thisNum < 10) buff[index++] = (char)(thisNum+48);
    26             else buff[index++] = (char)(thisNum+87);
    27         }
    28         System.out.println(buff);
    29         s.close();
    30     }
    31 
    32     // 欧几里得算法求两个数的最大公因数
    33     public static int fun1(int a, int b) {
    34         return b == 0 ? a : fun1(b, a%b);
    35     }
    36 }

    解密实现:

     1 import java.util.Scanner;
     2 
     3 public class Main {
     4     public static void main(String []args) {
     5         int m = 36, thisNum, index = 0, k;
     6         Scanner s = new Scanner(System.in);
     7         char[] buff = s.nextLine().toCharArray();
     8         int a = s.nextInt();
     9         int b = s.nextInt();
    10         while (fun1(m, a) != 1 || fun1(Math.max(a, b), Math.min(a, b)) != 1) {
    11             System.out.println("参数不符合要求,请重新输入");
    12             a = s.nextInt();
    13             b = s.nextInt();
    14         }
    15         // k为a模m的逆元
    16         k = fun2(a, m);
    17         for (char i : buff) {
    18             // 将加密后的字符转换为数字
    19             if (i > '9') thisNum = (int)i - 87;
    20             else thisNum = (int)i - 48;
    21             // 解密过程 D(E(x)) = a^(-1)*(E(x)-b) mod m
    22             thisNum = ((thisNum-b)*k)%m;
    23             // 如果结果是负数,则转换为正数,原理为 a % b = (a % b + b) % b
    24             if(thisNum < 0) thisNum += m;
    25             // 最后将解密后的数字转换为字符
    26             if (thisNum < 10) buff[index++] = (char)(thisNum+48);
    27             else buff[index++] = (char)(thisNum+87);
    28         }
    29         System.out.println(buff);
    30     }
    31 
    32     public static int fun1(int a, int b) {
    33         return b == 0 ? a : fun1(b, a%b);
    34     }
    35 
    36     // 循环求a模m的逆元
    37     public static int fun2(int a, int m) {
    38         for (int i = 0; i < m; i++) {
    39             if (a*i%m == 1) {
    40                 a = i;
    41                 break;
    42             }
    43         }
    44         return a;
    45     }
    46 }

    3、换位密码

    加密过程:保持明文的所有字符不变,根据一定的规则重新排列明文。

    解密过程:加密过程的逆过程。

    注解:加密过程和解密过程都是创建索引的过程,即用数组存储哪个位置放哪个字符,最后再通过索引重新组合成密文或明文。

    示例:

    明文矩阵:
    a s d f g
    h j k l m
    n b v c

    密文矩阵:
    d a g s f
    k h m j l
    v n b c

    (计算结果中n和b之间有一个空格,但输出时将空格去掉了)

    明文:asdfghjklmnbvc
    密钥:31524

    加密实现:

     1 import java.util.Scanner;
     2 
     3 public class Main {
     4     public static void main(String []args) {
     5         Scanner s = new Scanner(System.in);
     6         char[] mingwen = s.nextLine().toCharArray();
     7         char[] miyao = s.nextLine().toCharArray();
     8         StringBuffer miwen = new StringBuffer();
     9         int[] poi = new int[miyao.length];
    10         int index = 0, thisRow = 0, realPoi;
    11 
    12         // 计算出明文矩阵的列数和行数
    13         int col = miyao.length;
    14         int row = (mingwen.length / col) + (mingwen.length % col == 0? 0 : 1);  // 处理明文矩阵最后一行可能不满的情况
    15         
    16         // 密钥位置格式化(密钥中的所有字符都大于等于'1'所以最后减1方便后续计算)
    17         for (int i = 0; i < poi.length; i++) poi[i] = miyao[i] - 48 - 1;
    18 
    19 
    20         for (int i = 0; i < row * col; i++) {
    21             // 计算出当前位置i的真正字符(例如加密后第0位为2,即字符d),如果该字符在明文中存在,则将其添加到密文中
    22             if ((realPoi = poi[index++] + thisRow * col) < mingwen.length) miwen.append(mingwen[realPoi]);
    23             // 如果当前位置无字符则用空格代替
    24             else miwen.append(' ');
    25             
    26             if (index >= col) {
    27                 index = index % col;
    28                 thisRow++;
    29             }
    30         }
    31 
    32         // 密文去空格(解密时密文中的空格需要保留)
    33         for (int i = 0; i < miwen.length(); i++) {
    34             if (miwen.charAt(i) == ' ') miwen.deleteCharAt(i);
    35         }
    36 
    37         // 输出加密后的密文
    38         System.out.println(miwen);
    39     }
    40 }

    解密实现:

     1 import java.util.Scanner;
     2 
     3 public class Main {
     4     public static void main(String []args) {
     5         Scanner s = new Scanner(System.in);
     6         char[] miwen = s.nextLine().toCharArray();
     7         char[] miyao = s.nextLine().toCharArray();
     8         StringBuffer mingwen = new StringBuffer();
     9         int []poi = new int[miyao.length];
    10         int index = 0, thisRow = 0, realPoi;
    11 
    12         // 获取解密密钥并将密钥的位置格式化(最后减一),即加密的逆过程
    13         for (char c : miyao) {
    14             poi[(int)c - 48 - 1] = index++;
    15         }
    16         index = 0;
    17 
    18         // 密文矩阵的列数和行数
    19         int col = miyao.length;
    20         int row = (miwen.length / col) + (miwen.length % col == 0? 0 : 1);
    21 
    22         for (int i = 0; i < row * col; i++) {
    23             // 计算出当前位置i的真正字符并将该字符添加到明文字符串中
    24             if ((realPoi = poi[index++] + thisRow * col) < miwen.length) mingwen.append(miwen[realPoi]);
    25             
    26             if (index >= col) {
    27                 index = index % col;
    28                 thisRow++;
    29             }
    30         }
    31 
    32         // 输出解密后的明文
    33         System.out.println(mingwen);
    34     }
    35 }

    4、希尔密码(Hill密码)- 属于古典密码中的多表代换密码,运用了基本的矩阵论原理

    注解:

    1)每个字母当作 26 进制数字:a=0, b=1, c=2... 一串字母当成n维向量,跟一个n×n的矩阵相乘,再将得出的结果模 26。用作加密的矩阵(即密匙)必须是可逆的,否则就不可能译码。只有矩阵的行列式和 26 互质,才是可逆的。

    2)明文和密文的长度必须是给定的矩阵的列数的整数倍。(矩阵相乘的前提)

    加密过程:将明文转化为n维向量(字符转数字)与n×n的矩阵相乘,再将得出的结果模 26 后转化为字符。

    解密过程:将明文转化为n维向量(字符转数字)与n×n的矩阵相乘,再将得出的结果模 26 后转化为字符。

    加密实现:

     1 import java.util.Scanner;
     2 
     3 public class Main {
     4     public static void main(String[] args) {
     5         // 三阶可逆矩阵A
     6         int[][] A = { { 1, 2, 3 }, { 1, 1, 2 }, { 0, 1, 2 } };
     7 
     8         Scanner s = new Scanner(System.in);
     9         char[] mingwen = s.nextLine().toCharArray();
    10         char[] miwen = new char[mingwen.length];
    11         int row = 3, col = mingwen.length / 3, index = 0;
    12 
    13         while (index < col) {
    14             int sum;
    15             for (int i = 0; i < row; i++) {
    16                 sum = 0;
    17                 for (int j = 0; j < row; j++) {
    18                     sum += A[i][j] * (int) (mingwen[j+index*row] - 97);
    19                 }
    20                 sum %= 26;
    21                 if (sum < 0) sum += 26;
    22                 miwen[i + index*row] = (char) (sum + 97);
    23             }
    24             index++;
    25         }
    26 
    27         for (char c : miwen) {
    28             System.out.print(c);
    29         }
    30     }
    31 }

    解密实现:

     1 import java.util.Scanner;
     2 
     3 public class Main {
     4     public static void main(String[] args) {
     5         // A的逆矩阵
     6         int[][] A_1 = {{0, 1, -1}, {2, -2, -1}, {-1, 1, 1}};
     7 
     8         Scanner s = new Scanner(System.in);
     9         char[] miwen = s.nextLine().toCharArray();
    10         char[] mingwen = new char[miwen.length];
    11         int row = 3, col = mingwen.length / 3, index = 0;
    12 
    13         while (index < col) {
    14             int sum;
    15             for (int i = 0; i < 3; i++) {
    16                 sum = 0;
    17                 for (int j = 0; j < 3; j++) {
    18                     sum += A_1[i][j] * (int)(miwen[j+index*row] - 97);
    19                 }
    20                 sum %= 26;
    21                 if (sum < 0) sum += 26;
    22                 mingwen[i+index*row] = (char)(sum+97);
    23             }
    24             index++;
    25         }
    26 
    27         for(char c : mingwen) {
    28             System.out.print(c);
    29         }
    30     }
    31 }
  • 相关阅读:
    随笔—邀请赛前训— Codeforces Round #330 (Div. 2) B题
    随笔—邀请赛前训— Codeforces Round #330 (Div. 2) Vitaly and Night
    General Problem Solving Techniques [Examples]~C
    General Problem Solving Techniques [Examples]~A
    General Problem Solving Techniques [Beginner-1]~B
    General Problem Solving Techniques [Beginner-1]~A
    General Problem Solving Techniques [Beginner-1]~E
    General Problem Solving Techniques [Beginner-1]~F
    2015 HUAS Summer Contest#5~C
    2015 HUAS Summer Contest#5~B
  • 原文地址:https://www.cnblogs.com/GjqDream/p/11540961.html
Copyright © 2011-2022 走看看