加密算法学习(一、上)——传统加密算法(基础概念、Caesar密码、仿射密码)

本博文借鉴自书本《密码编码学与网络安全——原理与实践(第七版)》,由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
 * <br>凯撒密码
 * */
public class Caesar {
	
	/**
	 * 加密方法
	 * <br>String plaintext: 明文字符串
	 * <br>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();
	}
	
	/**
	 * 解密方法
	 * <br>ciphertext: 密文字符串
	 * <br>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互质

对加密算法的一个基本要求是算法是单射的,即如果p\neqq,则E(k,p) \neq  E(k,q)。否则就会因为有很多的明文映射成相同的密文而不能解密。若不对其中的参数a、b做出限制,则部分加密过程无法做到一对一的映射。例如,当a = 2,b = 3,时,有E([a, b] ,0) = E([a, b], 13) = 3。

所以首先对与b的取值,若要E(k,p) \neq  E(k,q),则ap + b \equiv (aq + b) mod 26不成立,则ap - aq \equiv 0 mod 26不成立,此时b已经消去,因此可以得到对于b的取值没有限制。

然后对于a的取值,若要使E(k,p) =  E(k,q) (0 \leq p \leq p \leq 26)成立,当且仅当26整除a(p - q),因为|p-q| < 26, 所以p-q不可能是26的倍数,但有可能是2或13的倍数,因此a不能为2或13的倍数,即要求a与26互质。

解密函数:对于密文c,其明文p = D([a, b], c) = a^{-1}(c - b) mod m        (此处满足1 \equiv a a^{-1} mod m)

a之乘法逆元素仅存在于a与m互质条件下。 由此,没有a的限制,可能无法解密。 易知解密方程逆于加密方程:

D(E(x)) = a^{-1} (E(x) - b) mod m = a^{-1}(((ax + b) mod m) - b) mod m = a^{-1}(ax + b - b) mod m = a^{-1}ax mod m

package algorithm;

/**
 * @author GDUYT
 * <br>仿射密码
 * */
public class Affine {
	
	/**
	 * 加密方法
	 * <br>String plaintext:  明文字符串
	 * <br>int a: 乘数a(a与m互质,m为字母元素种类个数,在仿射Caesar密码中m取26)
	 * <br>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();
	}
	
	/**
	 * 解密方法
	 * <br>String plaintext:  密文字符串
	 * <br>int a: 乘数a(a与m互质,m为字母元素种类个数,在仿射Caesar密码中m取26)
	 * <br>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,所以解密正确。

猜你喜欢

转载自blog.csdn.net/GDUYT_gduyt/article/details/91410742