本博文借鉴自书本《密码编码学与网络安全——原理与实践(第七版)》,由William Stallings著,王后珍、李莉等译。
1.广泛使用的密码算法与协议可分为以下四个主要领域:
2.其中的对称加密,也称传统加密或单钥加密,是20世纪70年代公钥密码产生之前唯一的加密类型,其五个基本组成:
3.密码编码学系统所具有的的三个独立特征:
4.密码分析学和穷举攻击:
攻击类型 | 秘密分析者已知信息 | 说明 |
唯 密文 攻击 |
|
难度最大(甚至不知道加密算法)、最容易防范。 若密钥空间比较小,可采用穷举攻击。 否则运用各种统计方法对密文分析(需要对明文类型有所了解)。 |
已知 明文 攻击 |
|
与其相关的是可能词攻击。 若攻击者处理的是特定的信息,他就可能知道其中的某些关键词及其位置。 |
选择 明文 攻击 |
|
若分析者能过获得信源系统,让发送方在发送的信息中插入由他选择的信息,那么就可能实现选择明文攻击。 |
选择 密文 攻击 |
|
很少用到 |
选择 文本 攻击 |
|
很少用到 |
5.加密体制的无条件安全:
若一个密码体制满足:无论有多少可使用密文,都无法唯一的确认密文所对应的明文,则称该加密体制是无条件安全的。
即无论花费多少时间,攻击者都无法将密文解密,这仅仅是因为其所需的信息不在密文里。除了一次一密之外,所有的加密算法都不是无条件安全的。
因此加密算法的使用者应该挑选尽量满足以下标准的算法:
所有的加密技术都要用到的两个基本模块:代替和置换。代替技术是将明文字母替换成其他字母、数字或符号的方法。
1.Caesar(凯撒)密码
原理:对字母表中的每个字母,用它之后的第三个字母来代替(注意字母表是循环的,即认为紧随Z后的是字母A)。
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 |
对于每个明文字母p,代替成密文字母C,加密算法可以表示为:C=E(3,p) = (p+3)mod(26)
其中的位移量3可以是任意整数k,这样就得到了一般的Caesar算法:C=E(k,p)=(p+k)mod(26)
这里K的取值范围从1到25,解密算法是:p=D(k,C)=(C-k)mod(26)
package algorithm;
/**
* @author GDUYT
*
凯撒密码
* */
public class Caesar {
/**
* 加密方法
*
String plaintext: 明文字符串
*
int offset: 偏移量,取值为任意整数
* */
public String encrypt(String plaintext,int offset) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < plaintext.length(); i++) {
int c = plaintext.charAt(i);
if (c >= 'A' && c <= 'Z') { //如果字符是大写字母
//对26取余的结果在[-25,25]之间,对取余的结果+26然后再对26取余,结果就落在了[0,25]之间
c = (((c - 'A' + offset) % 26) + 26) % 26 + 'A';
} else if (c >= 'a' && c <= 'z') { //如果字符是小写字母
c = (((c - 'a' + offset) % 26) + 26) % 26 + 'a';
}
char d = (char)c;
sb.append(d);
}
return sb.toString();
}
/**
* 解密方法
*
ciphertext: 密文字符串
*
offset:偏移量,取值为任意整数
* */
public String decrypt(String ciphertext,int offset) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < ciphertext.length(); i++) {
int c = ciphertext.charAt(i);
if (c >= 'A' && c <= 'Z') { //如果字符是大写字母
c = (((c - 'A' - offset) % 26) + 26) % 26 + 'A';
} else if (c >= 'a' && c <= 'z') { //如果字符是小写字母
c = (((c - 'a' - offset) % 26) + 26) % 26 + 'a';
}
char d = (char)c;
sb.append(d);
}
return sb.toString();
}
}
//部分测试代码
public static void main(String[] args) {
try {
String plaintext = FileOperate.ReadIn("D:/programming/java/mec/java_ee/code/EncryptionAlgorithm/src/test/plaintext.txt");
System.out.println("明文:" + plaintext);
Caesar caesar = new Caesar();
String ciphertext = caesar.encrypt(plaintext,-1000);
System.out.println("加密:" + ciphertext);
String plaintext1 = caesar.decrypt(ciphertext, -1000);
System.out.println("解密:" + plaintext1);
} catch (IOException e) {
e.printStackTrace();
}
}
//测试结果:
明文:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
加密:opqrstuvwxyzabcdefghijklmnOPQRSTUVWXYZABCDEFGHIJKLMN
解密:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
验证:(1).J在字母表中对应10,10 + (-1000) = -990,-990 % 26 = -2 ,-2 + 26 = 24,24对应字母表中的X,故加密正确。
(2).X在字母表中对应24,24 - (-1000) = 1024,1024 % 26 = 10,10对应字母表中的J,解密正确。
2.仿射Caesar密码
即为单表加密的一种替换密码,也是Caesar密码的一种推广。具有如下定义:对于每一个明文p,其密文用c代表,则
加密函数: c = E ([a, b] , p) = (ap + b) mod m (其中m为字母的数目,在仿射Caesar密码中取26,a与m互质)
对加密算法的一个基本要求是算法是单射的,即如果pq,则E(k,p) E(k,q)。否则就会因为有很多的明文映射成相同的密文而不能解密。若不对其中的参数a、b做出限制,则部分加密过程无法做到一对一的映射。例如,当a = 2,b = 3,时,有E([a, b] ,0) = E([a, b], 13) = 3。
所以首先对与b的取值,若要E(k,p) E(k,q),则ap + b (aq + b) mod 26不成立,则ap - aq 0 mod 26不成立,此时b已经消去,因此可以得到对于b的取值没有限制。
然后对于a的取值,若要使E(k,p) = E(k,q) (0 p p 26)成立,当且仅当26整除a(p - q),因为|p-q| < 26, 所以p-q不可能是26的倍数,但有可能是2或13的倍数,因此a不能为2或13的倍数,即要求a与26互质。
解密函数:对于密文c,其明文p = D([a, b], c) = (c - b) mod m (此处满足1 a mod m)
a之乘法逆元素仅存在于a与m互质条件下。 由此,没有a的限制,可能无法解密。 易知解密方程逆于加密方程:
D(E(x)) = (E(x) - b) mod m = (((ax + b) mod m) - b) mod m = (ax + b - b) mod m = ax mod m
package algorithm;
/**
* @author GDUYT
*
仿射密码
* */
public class Affine {
/**
* 加密方法
*
String plaintext: 明文字符串
*
int a: 乘数a(a与m互质,m为字母元素种类个数,在仿射Caesar密码中m取26)
*
int b: 位移b,取值为任意整数
* */
public String encrypt(String plaintext, int a, int b) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < plaintext.length(); i++) {
int c = plaintext.charAt(i);
if (c >= 'A' && c <= 'Z') { //如果字符是大写字母
//对26取余的结果在[-25,25]之间,对取余的结果+26然后再对26取余,结果就落在了[0,25]之间
c = ((a * (c - 'A') + b) % 26 + 26) % 26 + 'A';
} else if (c >= 'a' && c <= 'z') { //如果字符是小写字母
c = ((a * (c - 'a') + b) % 26 + 26) % 26 + 'a';
}
char d = (char)c;
sb.append(d);
}
return sb.toString();
}
/**
* 解密方法
*
String plaintext: 密文字符串
*
int a: 乘数a(a与m互质,m为字母元素种类个数,在仿射Caesar密码中m取26)
*
int b: 位移b,取值可为任意整数
* */
public String decrypt(String ciphertext, int a, int b) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < ciphertext.length(); i++) {
int c = ciphertext.charAt(i);
int e = c;
if (c >= 'A' && c <= 'Z') {
c = c - 'A' - b;
} else if (c >= 'a' && c <= 'z') {
c = c - 'a' - b;
}
while (c % a != 0) { //得到可以被a整除的c值
c += 26;
}
//对26取余的结果在[-25,25]之间,对取余的结果+26然后再对26取余,结果就落在了[0,25]之间
c = ((c / a) % 26 + 26) % 26;
//将最终得到的数字编号对应到字母表中的字母ascii值
c += (e > 96) ? 'a' : 'A';
char d = (char)c;
sb.append(d);
}
return sb.toString();
}
}
//部分测试代码:
public static void main(String[] args) throws IOException {
String plaintext = FileOperate.ReadIn
("D:/programming/java/mec/java_ee/code/EncryptionAlgorithm/src/test/plaintext.txt");
System.out.println("明文:" + plaintext);
Affine affine = new Affine();
String ciphertext = affine.encrypt(plaintext, 7, 64);
System.out.println("加密:" + ciphertext);
String plaintext1 = affine.decrypt(ciphertext, 7, -64);
System.out.println("解密:" + plaintext1);
}
//输出结果:
明文:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
加密:mtahovcjqxelszgnubipwdkryfMTAHOVCJQXELSZGNUBIPWDKRYF
解密:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
验证:(1)、字母e对应4, 4 * 7 + (64) = 92,92 % 26 = 14,14对应字母表中的o,故加密正确。
(2)、字母o对应14,14 - 64 = -50,-50 + 26 = -24,-24 + 26 = 2,2 + 26 = 28,28可以被7整除,28 / 7 = 4,4对应字母e,所以解密正确。