一、手写简单加密算法(凯撒密码)
首先,我们需要知道几个基本概念:
- 明文:原始信息。
- 密钥:加密与解密算法的参数,直接影响对明文进行变换的结果。
- 密文:对明文进行变换的结果。
- 加密算法:以密钥为参数,对明文进行多种置换和转换的规则和步骤,变换结果为密文。
- 解密算法:加密算法的逆变换,以密文为输入、密钥为参数,变换结果为明文。
1. 凯撒密码介绍
凯撒密码作为一种最为古老的加密技术,在古罗马的时候都已经很流行,他的基本思想是:通过把字母移动一定的位数来实现加密和解密。明文中的所有字母都在字母表上向后(或向前)按照一个固定数目进行偏移后被替换成密文。
例如,当偏移量是 3 的时候,所有的字母 A 将被替换成 D,B 变成 E,由此可见,位数就是凯撒密码加密和解密的密钥。<br /> 字符串”ABC”的每个字符都右移 3 位则变成”DEF”,解密的时候”DEF”的每个字符左移 3 位即能还原,如下图所示:

public class CaesarDemo {
private static final String str = "hei ma!";
private static final int key = 3;
public static void main(String[] args) {
String encrypt = encrypt(str,key);
System.out.println("加密后的文本:" + encrypt);
String decrypted = decrypted(encrypt,key);
System.out.println("解密后的文本:" + decrypted);
}
/**
* 加密
* @param input 数据源(需要加密的数据)
* @param key 秘钥,即偏移量
* @return 返回加密后的数据
*/
public static String encrypt(String input,int key) {
char[] charArray = input.toCharArray();
for (int i = 0; i < charArray.length; i++) {
//字符转换成 ASCII 码值
int ascii = charArray[i];
//字符偏移,例如 a->b
ascii = ascii + key;
//ASCII 码值转换为 char
char newChar = (char) ascii;
//替换原有字符
charArray[i] = newChar;
//以上 4 行代码可以简写为以下两种任一行
//charArray[i] = (char) (charArray[i] + key)
//charArray[i] += key;
}
return new String(charArray);
}
//解密:就是加密的反操作
public static String decrypted(String input,int key) {
char[] charArray = input.toCharArray();
for (int i = 0; i < charArray.length; i++) {
charArray[i] -= key;
}
return new String(charArray);
}
}
2. 破解凯撒密码-频率分析法
如果我们知道一个密码是用凯撒密码加密的,可以使用暴力破解法来解密:凯撒移位密码只有25种密钥,最多就是将这25种可能性挨个检测一下可以了。
那在不知道的前提下,又怎样判断是凯撒密码呢?这得用到 **频率分析法**。
在任何一种书面语言中,不同的字母或字母组合出现的频率各不相同。而且,对于以这种语言书写的任意一段文本,都具有大致相同的特征字母分布。
比如,在英语中,字母 E 出现的频率很高,而 X 则出现得较少。英语文本中典型的字母分布情况如下图所示:
破解流程:
1. 统计密文里出现次数最多的字符,例如出现次数最多的字符是是’h’。
2. 计算字符’h’到’e’的偏移量,值为 3,则表示原文偏移了 3 个位置。
3. 将密文所有字符恢复偏移 3 个位置。
注意点:
- 统计密文里出现次数最多的字符时,需多统计几个备选,因为最多的可能是空格或者其他字符。
- 短文可能严重偏离标准频率,假如文章少于100个字母,那么对它的解密就会比较困难,而且不是所有文章都适用标准频度.
二.对称加密
1. 概述
加密和解密都使用同一把密钥,这种加密方法称为对称加密,也称为单密钥加密。
简单理解为:加密解密都是同一把钥匙。 
上节中学到的凯撒密码就属于对称加密,他的字符偏移量即为密钥。
基于“对称密钥”的加密算法主要有DES算法,3DES算法,AES算法,Blowfish算法,RC5算法和IDEA算法等等,我们这里主要介绍DES算法和AES算法。
2.对称密码常用的数学运算
对称密码当中有几种常用到的数学运算。
◆移位和循环移位
移位就是将一段数码按照规定的位数整体性地左移或右移。循环右移就是当右移时,把数码的最后的位移到数码的最前头,循环左移正相反。
例如,对十进制数码12345678循环右移1位(十进制位)的结果为81234567,而循环左移1位的结果则为23456781。<br />**◆置换**<br /> 就是将数码中的某一位的值根据置换表的规定,用另一位代替。它不像移位操作那样整齐有序,看上去杂乱无章。这正是加密所需,被经常应用。<br />**◆扩展**<br /> 就是将一段数码扩展成比原来位数更长的数码。扩展方法有多种,例如,可以用置换的方法,以扩展置换表来规定扩展后的数码每一位的替代值。<br />**◆压缩**<br /> 就是将一段数码压缩成比原来位数更短的数码。压缩方法有多种,例如,也可以用置换的方法,以表来规定压缩后的数码每一位的替代值。<br />**◆异或**<br /> 这是一种二进制布尔代数运算。异或的数学符号为⊕ ,它的运算法则如下:<br /> 1⊕1 = 0 <br /> 0⊕0 = 0 <br /> 1⊕0 = 1 <br /> 0⊕1 = 1 <br /> 也可以简单地理解为,参与异或运算的两数位如相等,则结果为0,不等则为1。<br />**◆迭代**<br /> 迭代就是多次重复相同的运算,这在密码算法中经常使用,以使得形成的密文更加难以破解。
总结:这些运算主要是对比特位进行操作,其共同目的就是把被加密的明文数码尽可能深地打乱,从而加大破译的难度。
三.对称加密算法
1. DES算法
①.简介
DES是Data Encryption Standard(数据加密标准)的缩写。它是由IBM公司研制的一种对称密码算法,美国国家标准局于1977年公布把它作为非机要部门使用的数据加密标准,三十年来,它一直活跃在国际保密通信的舞台上,扮演了十分重要的角色。
DES是一个分组加密算法,典型的DES以64位为分组对数据加密,加密和解密用的是同一个算法。它的密钥长度是56位(因为每个第8 位都用作奇偶校验),密钥可以是任意的56位的数,其保密性依赖于密钥。
DES加密的算法框架大致如下:
首先要生成一套加密密钥,从用户处取得一个64位长的密码口令,然后通过等分、移位、选取和迭代形成一套16个加密密钥,分别供每一轮运算中使用。
DES对64位(bit)的明文分组M进行操作,M经过一个初始置换IP,置换成m0。将m0明文分成左半部分和右半部分,各32位长。
然后进行16轮完全相同的运算(迭代),在每一轮运算过程中数据与相应的密钥结合。
经过16轮迭代后,左、右半部分合在一起经过一个末置换(数据整理),这样就完成了加密过程。
加密流程如图所示:

②代码实现
import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class DesTest {
public static void main(String[] args) throws Exception {
String str = "这是原文";
String psw = "12345678";
String encrypt = encrypt(str, psw);
System.out.println("加密后:"+encrypt);
String decrypt = decrypt(encrypt, psw);
System.out.println("解密后:"+decrypt);
}
public static String encrypt(String original,String psw) throws Exception {
//创建加密对象,参数为加密算法
Cipher cipher = Cipher.getInstance("DES");
// 调用自己的方法生成密钥
Key key = getKey(psw);
/**
* 初始化加密器
* 参数 1:加密模式
* 参数 2:密钥
*/
cipher.init(Cipher.ENCRYPT_MODE, key);
//执行加密,解密后得到的字节数组
byte[] doFinal = cipher.doFinal(original.getBytes());
//将自己数组用 Base64 编码,转换为字符串
String encode = Base64.encode(doFinal);
return encode;
}
/**
* 这个方法可以让任意长度的密码转成64位的密码
* 1. 从指定字符串生成密钥,密钥所需的字节数组长度为 8 位
* 2. 不足 8 位时后面补 0,超出 8 位只取前 8 位
*/
private static SecretKeySpec getKey(String psw) {
byte[] buffer = new byte[8];
byte[] bytes = psw.getBytes();
for(int i=0;i<buffer.length&&i<bytes.length;i++){
buffer[i]=bytes[i];
}
return new SecretKeySpec(buffer, "DES");
}
public static String decrypt(String original,String psw) throws Exception{
//获取加密器(同时也是解密器)
Cipher cipher = Cipher.getInstance("DES");
//获取密钥
Key key = getKey(psw);
//初始化密码器,设置为解密模式
cipher.init(Cipher.DECRYPT_MODE, key);
//解密。注意,这里需要将传入的原文使用 Base64 编码转换为 byte,因为加密后的密文是用 Base64 编码的
byte[] doFinal = cipher.doFinal(Base64.decode(original));
//将解密后的字节数组转换为字符串
return new String(doFinal);
}
}
2. Base64编码
①简介
加密后的结果是字节数组,这些被加密后的字节在码表(例如GBK、 UTF-8 码表)上找不到对应字符,会出现乱码,当乱码字符串再次转换为字节数组时,长度会变化,导致解密失败,所以转换后的数据是不安全的。
使用 Base64 对字节数组进行编码,任何字节都能映射成对应的 Base64 字符,之后能恢复到字节数组,利于加密后数据的保存和传输,所以转换是安全的。
Base64码表如下:
②编解码原理
a、当字符串字符个数为3的整数倍时:
比如字符串“ABC”,其在计算机内存中的 十六进制表示为 41、42、43,十进制表示为“65”“66”“67”;二进制表示为
01000001 01000010 01000011 将这三个二进制数依次取6bit
,010000/01 0100/0010 01/000011 就转换成了:
010000 010100 001001 000011,将这四个二进制数转换成十六制数为:
10,14,9,3,十进制数位为16,20,9,3。对照上面的码表,分别查
找出对应的字符为Q,U,J,D。
也是就说字符串“ABC”经过BASE64编码后得 出“QUJD”。这是最简单的情况,即ASCII码字符数刚好可以被3整除。接着继续讨论余数为2、为1的情况。
b、当字符串字符个数除以3余数为2时:
比如字符串“ce”,其在内存中十六进制表示为63,65;十 进制表示表示99,101;二进制表示为
01100011 01100101 依次取6bit
011000/11 0110/0101 这时,第3个字符不足6位,在后面补零,也就
是0101变成010100。转换结果为
011000 110110 010100 这3个二进 制数转换成十六制数为18,36,14;十进制数位为24,54,20。对照码表 得出结果“Y2U”。编码后的字符个数不足4位,用“=”填充,最后编码得出“Y2U=”。
c、当余数为1时:
比如字符串“{”,其在内存中的十六进制表示为$7B,十进制为 123,二进制位表示为
01111011 依次取6bit
011110/11 补0后为
011110/110000 转换结果为011110和110000。这两个二进制数转换成
十六进制数为1E,30,十进制数为30,48。对照码表得出结果为“ew”,补上
“=”,最后编码得出“ew= =”。解码也很简单,是编码的逆过程,即将每 个字符对照码表换算成6bit的二进制数,然后重组起来,按8位进行截取,得出原码。
3. 3DES和AES算法
①3DES算法
DES 的安全性首先取决于密钥的长度。密钥越长,破译者利用穷举法搜索密钥的难度就越大。DES采用**64bit分组长度**和**56bit密钥长度**:<br />
随着软硬件技术的发展,多核CPU、分布式计算、量子计算等理论的实现,DES在穷举方式的暴力攻击下还是相当脆弱的,因此很多人想办法用某种算法替代它,面对这种需求广泛被采用的有两种方案: <br /> 1. 设计一套全新的算法,例如AES,这个在后面会说到。 <br /> 2. 为了保护已有软硬件的投资,仍使用DES,但使用多个密钥进行多次加密,这就是多重DES加密。
例如后来演变出的 **3-DES** 算法使用了 3 个独立密钥(密钥长度为168bit)进行三重 DES 加密,这就比 DES 大大提高了安全性。如果 56 位 DES 用穷举搜索来破译需要 2∧56 次运算,而 3-DES 则需要 2∧112 次。
②AES算法
a.简介
3DES缺点是算法运行相对较慢。因为原来DES是为70年代的硬件设计的,算法代码并不是很高效,而3DES是DES算法的3轮迭代,因此更慢。而且DES和3DES的分组大小都是64bit,3DES密钥长度却是168bit,处于加密效率和安全的考虑,需要更大的分组长度。于是AES应运而生。
Advanced Encryption Standard 高级加密标准,该标准是美国国家标准技术研究所于2001年颁布的。AES旨在取代DES成为广泛使用的标准,2006年AES已成为最流行的对称加密算法。
AES使用的**分组大小为128bit**,密钥长度可以为128、192、256 bit。最简单最常用的也就是 **128 bit(16字节)** 的密钥。
**b.算法原理**
AES 加密过程涉及到 4 种操作:字节替代(SubBytes)、行移位(ShiftRows)、列混淆(MixColumns)和轮密钥加(AddRoundKey)。
解密过程分别为对应的逆操作。由于每一步操作都是可逆的,按照相反的顺序进行解密即可恢复明文。加解密中每轮的密钥分别由初始密钥扩展得到。算法中 16(byte)字节的明文、密文和轮密钥都以一个 4x4 的矩阵表示。 <br />
**c.代码实现**
AES的java实现比较简单,只需要把密码设置为16byte,然后将DES算法实现的java代码中,将DES修改为AES即可。
四.总结
到这里,我们的课程也即将告一段落了。最后大致的总结一下三种对称加密算法:
DES作为安全性最弱的算法已经在实际运用面临淘汰,而3DES依然在已有的软硬件中返回余热。不过3DES效率太低,在更多的领域被安全和效率兼具的AES所替代。
在实际开发中,对称加密算法这部分的运用大致如下图所示:
当然,这只是一个非常简易的模型。我们学习到这,加密也就入门,更多的知识有待于大家进一步发掘!