凯撒密码原理
凯撒密码的加密代换和解密代换分别为
c
=
E
k
(
m
)
=
m
+
3
(
m
o
d
26
)
c=E_{k}(m)=m + 3(mod 26)
c=Ek(m)=m+3(mod26)
0
<
=
m
<
=
25
0<= m <= 25
0<=m<=25
m
=
D
k
(
c
)
=
c
−
3
(
m
o
d
26
)
m=D_{k}(c)=c - 3(mod 26)
m=Dk(c)=c−3(mod26)
0
<
=
c
<
=
25
0<=c<=25
0<=c<=25
其中,3是加解密使用的密钥,即
k
=
3
k=3
k=3,加密时,每个字母向后移3位(循环移位,字母
x
x
x移到
a
a
a,
y
y
y移到
b
b
b,
z
z
z移到
c
c
c)。解密时,每个字母向前移3位(循环移位)
移位变换
移位变换的加解密分别是
c
=
E
k
(
m
)
=
m
+
k
(
m
o
d
26
)
c=E_{k}(m)=m+k(mod 26)
c=Ek(m)=m+k(mod26)
0
<
=
m
,
k
<
=
25
0<=m,k<=25
0<=m,k<=25
m
=
D
k
(
c
)
=
c
−
k
(
m
o
d
26
)
m=D_{k}(c)=c - k(mod 26)
m=Dk(c)=c−k(mod26)
0
<
=
c
,
k
<
=
25
0<=c,k<=25
0<=c,k<=25
仿射变换
仿射变换的加解密分别是
c
=
E
a
,
b
(
m
)
=
a
m
+
b
(
m
o
d
26
)
c=E_{a,b}(m)=am+b(mod 26)
c=Ea,b(m)=am+b(mod26)
m
=
D
a
,
b
(
c
)
=
a
−
1
(
c
−
b
)
(
m
o
d
26
)
m=D_{a,b}(c)=a^{-1}(c-b)(mod 26)
m=Da,b(c)=a−1(c−b)(mod26)
其中,
a
,
b
a,b
a,b是密钥,为满足
0
<
=
a
,
b
<
=
25
0<=a,b<=25
0<=a,b<=25和
g
c
d
(
a
,
26
)
=
1
gcd(a,26)=1
gcd(a,26)=1的整数,其中
g
c
d
(
a
,
26
)
gcd(a,26)
gcd(a,26)表示
a
,
26
a,26
a,26的最大公因子,
g
c
d
(
a
,
26
)
=
1
gcd(a,26)=1
gcd(a,26)=1表示
a
a
a和
26
26
26是互素的,
a
−
1
a^{-1}
a−1表示
a
a
a的逆元,即
a
−
1
∗
a
=
1
m
o
d
26
a^{-1}*a=1mod 26
a−1∗a=1mod26
代码实现-凯撒密码
package com.cqu;
public class KaiSaEncryptionTest {
public static void main(String args[]) {
String input = "Hello World";
Integer key = 3;
String c1 = encryptionByKasStra(input);
System.out.println(c1);
String p1 = decryptByKasStra(c1);
System.out.println("解密后的明文为: " + p1);
}
/**
* 凯撒加密
*/
private static String encryptionByKasStra(String input) {
char[] inputArray = input.toCharArray();
StringBuilder cipherText = new StringBuilder();
for (char ia : inputArray) {
int b = ia;
b = (b + 3);
char newb = (char) b;
cipherText.append(newb);
}
return cipherText.toString();
}
/**
* 凯撒解密
*/
private static String decryptByKasStra(String cipherText) {
char[] cipherArray = cipherText.toCharArray();
StringBuilder plainText = new StringBuilder();
for (char ca : cipherArray) {
int m = ca;
m = m - 3;
char newm = (char) m;
plainText.append(newm);
}
return plainText.toString();
}
}
代码实现-放射变换
package com.cqu;
import com.cqu.enums.EnglishCodeNumberMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* @author wuyanling
*/
public class KaiSaEncryptionTest {
public static void main(String args[]) {
String input1 = "security";
String input2 = "vlxijh";
Integer a = 7;
Integer b = 21;
String c1 = encryptionByKasStra(a, b, input1);
System.out.println("加密后的秘文为:" + c1);
// String c1 = encryptionByKasStra(input);
// System.out.println(c1);
String p1 = decryptByKasStra(a, b, input2);
System.out.println("解密后的明文为: " + p1);
//System.out.println(15*(-4) % 26);
// System.out.println(EnglishCodeNumberMap.getNumByCode("b"));
}
/**
* 凯撒加密
*/
private static String encryptionByKasStra(Integer a, Integer b, String input) {
if (Objects.isNull(input)) {
return "";
}
char[] inputArray = input.toCharArray();
List<Integer> numberArray = Arrays.asList();
//这一步是解决抛java.lang.UnsupportedOperationException异常
List plainArray = new ArrayList(numberArray);
for (char ia : inputArray) {
for (EnglishCodeNumberMap map : EnglishCodeNumberMap.values()) {
if(map.getCode().equals(String.valueOf(ia))) {
plainArray.add(EnglishCodeNumberMap.getNumByCode(String.valueOf(ia)));
continue;
}
}
}
StringBuilder cipherText = new StringBuilder();
List<Integer> cipherArray = (List<Integer>) plainArray.stream().map(e -> (a*(int) e + b) % 26).collect(Collectors.toList());
for (Integer ci : cipherArray) {
for (EnglishCodeNumberMap map : EnglishCodeNumberMap.values()) {
if (map.getNum().equals(ci)) {
cipherText.append(map.getCode());
continue;
}
}
}
return cipherText.toString();
}
/**
* 凯撒解密
*/
private static String decryptByKasStra(Integer a, Integer b, String cipherText) {
if (Objects.isNull(cipherText)) {
return "";
}
char[] cipherArray = cipherText.toCharArray();
List<Integer> numberArray = Arrays.asList();
List ciphnerArray = new ArrayList(numberArray);
for (char ia : cipherArray) {
for (EnglishCodeNumberMap map : EnglishCodeNumberMap.values()) {
if(map.getCode().equals(String.valueOf(ia))) {
ciphnerArray.add(EnglishCodeNumberMap.getNumByCode(String.valueOf(ia)));
continue;
}
}
}
StringBuilder plainText = new StringBuilder();
Integer c = getInverseElement(a);
List<Integer> plainArray = (List<Integer>) ciphnerArray.stream().map(e ->{
if ((int) e - b > 0) {
return c * ((int) e - b) % 26;
}else{
//同余 如果 a mod b中a<0,则将(a+b) mod b
return c * ((int) e - b + 26) % 26;
}
}).collect(Collectors.toList());
for (Integer pa : plainArray) {
for (EnglishCodeNumberMap map : EnglishCodeNumberMap.values()) {
if (map.getNum().equals(pa)) {
plainText.append(map.getCode());
continue;
}
}
}
return plainText.toString();
}
private static Integer getInverseElement(Integer a) {
if (Objects.isNull(a)) {
return null;
}
Integer c = null;
for (int i = 0; i < 26; i ++) {
if (a*i % 26 == 1) {
c = i;
break;
}
}
return c;
}
}
其中字母与数字映射枚举如下
package com.cqu.enums;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* @author wuyanling
*/
public enum EnglishCodeNumberMap {
a("a", 0),
b("b", 1),
c("c", 2),
d("d", 3),
e("e", 4),
f("f", 5),
g("g", 6),
h("h", 7),
i("i", 8),
j("j", 9),
k("k", 10),
l("l", 11),
m("m", 12),
n("n", 13),
o("o", 14),
p("p", 15),
q("q", 16),
r("r", 17),
s("s", 18),
t("t", 19),
u("u", 20),
v("v", 21),
w("w", 22),
x("x", 23),
y("y", 24),
z("z", 25),
;
private String code;
private Integer num;
EnglishCodeNumberMap(String code, Integer num) {
this.code = code;
this.num = num;
}
public String getCode() {
return code;
}
public Integer getNum() {
return num;
}
private static Map<String, EnglishCodeNumberMap> codeMap = new HashMap<>();
static {
Arrays.stream(EnglishCodeNumberMap.values()).forEach(e -> codeMap.put(e.code, e));
}
public static EnglishCodeNumberMap ofType(String code) {
if (Objects.isNull(code)) {
return null;
}
return codeMap.get(code);
}
public static Integer getNumByCode(String code) {
EnglishCodeNumberMap te = ofType(code);
if (Objects.isNull(te)) {
return -1;
}
return te.num;
}
@Override
public String toString() {
return name()+":"+ code;
}
}