乘法密码

乘法密码技术:
属于替换密码技术的一种



乘法密码技术的加密变换: Ek(Ai)=Aj j=ik(mod n) ,gcd(k,n)=1
(1)0
(2)k与n互素,即要满足gcd(k, n)=1,否则不存在模逆元,不能正确解密


设明文消息为M,消息元素为m 元素下标为 i;
则密文消息为C,密文元素为c 元素下标为 j;  c=i*k mod n;


乘法密码的密码空间大小是φ(n),φ(n)是欧拉函数。
当n为26字母,则与26互素的数是1、3、5、7、9、11、15、17、19、21、23、25,即φ(n)=12 因此乘法密码的密钥空间为12。
注意:k=1时 加密变换为恒等变换(即无变化)



乘法密码也称采样密码,因为密文字母表是将明文字母按照下标每隔k位取出一个字母排列而成。
例如对26个字母生成密码表(下标由0开始,0-25)
取k=9 
明文字母  a b c d e f g h i j k  l  m  n  o  p  q  r  s  t  u  v  w  x  y  z
数组下标  0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25


密文字母  a j s  b k  t  c  l  u  d  m  v  e  n  w  f  o  x  g  p  y  h  q  z  i  r
数组下标  0 9 18 1 10 19 2  11 20 3  12 21 4  13 22 5  14 23 6  15 24 7  16 25 8  17


正如上所述,从下标0开始, 明文a:  0X9%26=0 -->[0]=a  明文b:  1X9%26=9 -->[9]=j 


其实即是通过公式算出密文密码表,其意义与明文表相一一对应。  


乘法密码技术的解密变换: Dk(Aj)=Ai ,i=jX(mod n)  X为k的逆元(最小正整数)
对于正整数 k和n,如果有kX≡1(mod m),那么把这个同余方程中X的最小正整数解叫做k模n的逆元。

由于k的取值是从φ(n) 密码空间中获得,则必定k


关于求k逆元 方法多样,
一、欧拉定理(费马小定理)


欧拉定理:若a与m互质,那么有a^φ(m)≡1(mod m)
则a^-1 =a^(φ(m)-1) mod m


二、扩展的欧几里得算法


对于不完全为 0 的非负整数 a,b,gcd(a,b)表示 a,b 的最大公约数,
必然存在整数对 x,y ,使得 gcd(a,b)=ax+by。


public static int ex_gcd(int a,int b){
if(b==0){
     x=1;y=0;
     return a;
   }
   int q=ex_gcd(b,a%b);
   int t=x;x=y;y=t-a/b*y;
   return q;
}


q即为a与b 的最大公约数,此处与原先算法相同
--------------------------------------------------------
由于本问题中k与n互素,gcd(k,n)=1 即上述q恒为1

对于可利用(X+n)%n   来获得正整数逆元。


测试代码如下:


public class ex_Eulid {
public static int x=0,y=0;
public static int ex_gcd(int a,int b){
if(b==0)
   {
       x=1;y=0;
       return a;
   }
   int q=ex_gcd(b,a%b);
   int t=x;x=y;y=t-a/b*y;
   return q;
}
public static void main(String[] args) {
int k=9,n=26;
int a=k,b=n;
ex_gcd(a, b);
int out=(x+n)%n;
System.out.println(out);
}
}
上述所得out输出即为所需逆元
通过  Dk(Aj)=Ai ,i=jX(mod n)   将out代入X 即可恢复明文



完整测试例子如下:


import java.util.ArrayList;
import java.util.Scanner;


public class 乘法密码技术 {
public static int x=0,y=0;
public static ArrayList SecretPlace=new ArrayList();
public static int gcd(int a,int b){
return b>0?gcd(b,a%b):a;
}
public static int ex_gcd(int a,int b){
if(b==0){
   x=1;y=0;
   return a;
}
   int q=ex_gcd(b,a%b);
   int t=x;x=y;y=t-a/b*y;
   return q;
}
public static void CountSecretPlace(int n){
SecretPlace.add(1);
for(int i=2;i
if(gcd(i, n)==1)
SecretPlace.add(i);
}
}
public static void main(String[] args) {
int k;
Scanner scan=new Scanner(System.in);
System.out.println("第一行输入密码表总数n\n第二行输入各明文字符\n第三行输入待加密明文");
int n=scan.nextInt();
char CharArrays[]=new char[n];
CharArrays=scan.next().toCharArray();
scan.nextLine();
String normalStr=scan.nextLine();
CountSecretPlace(n);
System.out.println("密钥空间如下,您可选择其中一个值作为密钥");
System.out.println(SecretPlace);
k=scan.nextInt();
while(!SecretPlace.contains(k)){
System.out.println("只能选择密钥空间中的密钥值!请重新选择");
k=scan.nextInt();
}
ex_gcd(k, n);
int out=(x+n)%n;
System.out.println("您选择的密钥模逆元为:"+out);
String splitStrs[]=normalStr.split(" ");
ArrayList templist=new ArrayList<>();
System.out.println("加密后如下:");
for (int j = 0; j < splitStrs.length; j++) {
char normalChars[]=splitStrs[j].toCharArray();
for (int p = 0; p < normalChars.length; p++) {
int t=(normalChars[p]-'a')*k%n;
normalChars[p]=CharArrays[t];//加密
System.out.print(normalChars[p]);
normalChars[p]=CharArrays[t*out%n];//解密
templist.add(normalChars[p]);
}
System.out.print(" ");
templist.add(' ');
}
System.out.println("\n解密后如下:");
for(Character o:templist){
System.out.print(o);
}
}
}
运行结果如下:


第一行输入密码表总数n
第二行输入各密文字符
第三行输入待加密明文
26
abcdefghijklmnopqrstuvwxyz
a man liberal in his views
密钥空间如下,您可选择其中一个值作为密钥
[1, 3, 5, 7, 9, 11, 15, 17, 19, 21, 23, 25]
9
您选择的密钥模逆元为:3
加密后如下:
a ean vujkxav un lug hukqg 
解密后如下:
a man liberal in his views 

你可能感兴趣的:(古典密码)