仿射密码(Affine Cipher)
转载请著明出处
仿射密码是代换密码的一种特殊情况。
在学习仿射密码之前我们首先需要了解几个定理
定理
同余方程唯一解定理
设a ∈ Zm,对任意的b∈Zm,同余方程ax ≡ b (mod m)有唯一解x∈Zm的充分必要条件是gcd(a, m) = 1*.*
证明:假设gcd(a,m)=d>1,则同余方程ax=0(modm)至少有两个解,分别是x=0和x=m/d。这种情况下e(x)=(ax+b)modm不是一个单射函数,因此不能用了作为一个有效的加密函数。
有了如上的定理我们就很快能判断一个函数是否是有效的加密函数,比如gcd(26,2)=2那么4x+7不是一个有效的加密函数。因为对任意的x∈Z26,x和x+13将被加密成相同的密文。
接下来我们看一下仿射密码的秘钥空间,因为26=2×13,所以所有与26互素的数为a= 1 3 5 7 9 11 15 17 19 21 23 25而b可能是Z26中的任何数,因此仿射密码的秘钥空间为12×26=312.由此也可以看出仿射密码是很不安全的。
欧拉函数和欧拉定理
设 a ≥ 1*,* m ≥ 2. 如果 gcd(a, m) = 1, 则称a与m互素。Zm中所有域m互素元素个数用φ(m)来表示(函数φ也称为欧拉函数)
以一个通俗的式子来说明欧拉定理:
φ(72)=φ(23×32)=23-1(2-1)×32-1(3-1)=22×1×3×2=24
乘法逆
设a∈ Zm,若存在a’∈Zm,使得aa’≡1(mod m),则称a模m可逆,a’为a的(乘法)逆元,a’可记为a-1 mod m,在m固定的情形下,简记为a-1
由之前的结论可知,a在Zm上存在乘法逆,当且仅当gcd(a,m)=1,并且其逆如果存在,则必唯一。
在Z26的情形下,与26互素的乘法逆如下表所示:
原数 | 1 | 3 | 5 | 7 | 11 | 17 | 25 |
---|---|---|---|---|---|---|---|
逆 | 1 | 9 | 21 | 15 | 19 | 23 | 25 |
仿射密码
令P=C=Z26,且K={(a,b)∈Z26×Z26 :gcd(a,26)=1}对任意的k=(a,b)∈K, x,y属于Z26,定义ek(x)=(ax+b)mod26和dk(y)=a-1(y-b)mod 26
代码实现
package com.slp.cryptography;
import java.util.HashMap;
import java.util.Map;
/**
* @ClassName AffineCipher
* @Description 仿射密码
* @Author sanglp
* @Date 2020/11/30 14:43
* @Version 1.0
**/
public class AffineCipher {
static Map<Integer,Integer> reverseMap = new HashMap<Integer,Integer>();
static{
reverseMap.put(1,1);
reverseMap.put(3,9);
reverseMap.put(9,3);
reverseMap.put(5,21);
reverseMap.put(21,5);
reverseMap.put(7,15);
reverseMap.put(15,7);
reverseMap.put(11,19);
reverseMap.put(19,11);
reverseMap.put(17,23);
reverseMap.put(23,17);
reverseMap.put(25,25);
}
public static void main(String[] args) {
encrypt("hot",7,3);
decrypt("AXG",7,3);
}
/**
* (ax+b)mod26 是加密函数
* @param resource
* @param a
* @param b
*/
public static void encrypt(String resource,int a,int b){
if(!reverseMap.containsKey(a)|| b<0||b>26){
throw new RuntimeException("参数有误,请重新输入");
}
char[] arr = resource.toUpperCase().toCharArray();
StringBuilder result = new StringBuilder();
for(int i=0;i<arr.length;i++){
int temp = (a*(arr[i]-'A')+b)%26<0?(a*(arr[i]-'A')+b)%26+26:(a*(arr[i]-'A')+b)%26;
result.append((char)(temp+'A'));
}
System.out.println(result);
}
/**
* 解密函数为a逆(y-b)mod26
* @param resource
* @param a
* @param b
*/
public static void decrypt(String resource,int a,int b){
int re =reverseMap.get(a);//求得逆 后续会整理求逆的方法
char[] arr = resource.toUpperCase().toCharArray();
StringBuilder result = new StringBuilder();
for(int i=0;i<arr.length;i++){
int temp = (re*(arr[i]-'A'-b))%26<0?(re*(arr[i]-'A'-b))%26+26:(re*(arr[i]-'A'-b))%26;
result.append((char)(temp+'A'));
}
System.out.println(result);
}
}