随着对称密码的发展,DES数据加密标准算法由于密钥长度较小(56位),已经不适应当今分布式开放网络对数据加密安全性的要求,因此1997年NIST 公开征集新的数据加密标准,即AES[1]。经过三轮的筛选,比利时Joan Daeman和Vincent Rijmen提交的Rijndael算法被提议为AES的最终算法。此算法将成为美国新的数据加密标准而被广泛应用在各个领域中。尽管人们对AES还有不 同的看法,但总体来说,AES作为新一代的数据加密标准汇聚了强安全性、高性能、高效率、易用和灵活等优点。AES设计有三个密钥长 度:128,192,256位,相对而言,AES的128密钥比DES的56密钥强1021倍[2]。AES算法主要包括三个方面:轮变化、圈数和密钥扩 展。 AES 是一个新的可以用于保护电子数据的加密算法。明确地说,AES 是一个迭代的、对称密钥分组的密码,它可以使用128、192 和 256 位密钥,并且用 128 位(16字节)分组加密和解密数据。与公共密钥密码使用密钥对不同,对称密钥密码使用相同的密钥加密和解密数据。通过分组密码返回的加密数据 的位数与输入数据相同。迭代加密使用一个循环结构,在该循环中重复置换(permutations )和替换(substitutions)输入数据。Figure 1 显示了 AES 用192位密钥对一个16位字节数据块进行加密和解密的情形。 AES算法概述 192位密钥的值是: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 0 1 2 3 4 5 6 7 8 9 10 1112 13 14 15 16 17 18 19 20 21 22 23
AES 算法的主循环对 State 矩阵执行四个不同的操作,在规范中被称为 SubBytes(字节替换)、ShiftRows(行位移变换)、MixColumns(列混合变换) 和 AddRoundKey。除了每次循环 AddRoundKey 都被调用并使用密钥调度表的下面四行外,AddRoundKey 与预备处理步骤中的 AddRoundKey 相同。SubBytes 例程是一个代替操作,它将 State 矩阵中的每个字节替换成一个由 Sbox 决定的新字节。比如,如果 State[0,1]的值是 0x40 如果你想找到它的代替者,你取 State[0,1] 的值 (0x40) 并让 x 等于左边的数字(4)并让 y 等于右边的数字(0)。然后你用 x 和 y 作为索引 进到 Sbox 表中寻找代替值,如 Figure 2 所示。 此处加法和乘法是专门的数学域操作,而不是平常整数的加法和乘法。 密钥扩展 AES加密和解密算法使用了一个由种子密钥字节数组生成的密钥调度表。AES规范中称之为密钥扩展例程(KeyExpansion)。从本质上讲,从一 个原始密钥中生成多重密钥以代替使用单个密钥大大增加了比特位的扩散。虽然不是无法抵御的困难,但理解 KeyExpansion 仍是 AES 算法中的一个难点。KeyExpansion 例程高级伪代码如下所示: KeyExpansion(byte[] key, byte[][4] w) { copy the seed key into the first rows of w for each remaining row of w { use two of the previous rows to create a new row } } “用前面两行来产生一个新行”(“use two of the previous rows to create a new row”)的例程用到了两个子 例程,RotWord 和 SubWord 以及一个名为“Rcon”的常数表(作为“轮常数”)。让我们先来逐个看一下这三东西,然后再回到整个 KeyExpansion 的讨论中来。 RotWord 例程很简单。它接受一个4个字节的数组并将它们向左旋转一个位置。因为轮调度表 w[] 有四列,RotWord 将 w[]的1行左旋。注意 KeyExpansion 使用的这个 RotWord 函数与加密算法使用的 ShiftRows (行位移变换)例程非常相似,只是它 处理的是单行密钥调度 w[],而不是整个加密状态表 State[]。 SubWord 例程使用替换表 Sbox 对一给定的一行密钥调度表 w[] 进行逐字节替换。KeyExpansion 操作中的替换实际上就像在加密算法中的 替换一样。被代替的输入字节被分成 (x,y) 对,它被当作进入替换表 Sbox 的索引。举例来说,0x27的代替结果是 x=2 和 y=7,并且 Sbox[2,7] 返回 0xcc。 KeyExpansion 例程使用一个被称为轮常数表的数组 Rcon[]。这些常数都是4个字节,每一个与密钥调度表的某一行相匹配。AES 的 KeyExpansion 例程需要11个轮常数。你可以在 Figure 7 中看到这些常数清单。 每个轮常数的最左边的字节是GF(28)域中2的幂次方。它的另一个表示方法是其每个值是前一个值乘上0x02,正如前一部分讨论 GF(28) 乘法 时所描述的那样。注意 0x80 × 0x02 = 0x1b 是 0x80 左移1个比特位后紧接着与 0x1b 进行异或,如前所述。 现在让我们更进一步看看 KeyExpansion 内幕中的循环。这里所用的伪码比以前更为详细,这个循环是: for (row = Nk; row < (4 * Nr+1); ++row) { temp = w[row-1] if (row % Nk == 0) temp = SubWord(RotWord(temp)) xor Rcon[row/Nk] else if (Nk == 8 and row % Nk == 4) temp = SubWord(temp) w[row] = w[row-Nk] xor temp } 先不要去看if子句,你将看到密钥调度表 w[] 的每一行都是前面一行与行 Nk 异或的结果(4, 6, 或 8 取决于密钥的长度)。if条件的第一部分用 SubWord、RotWord 以及与轮常数的异或修改密钥调度表的每个第4、第6或第8行,取决于是否密钥的长度是128、192或256位。这个条件的第二部分将修改行 12、20 和 28 等等——对于256位密钥而言——每 一个第8行都将添加密钥调度额外的可变性。 让我们用本文开头所举的例子来考察 KeyExpansion 是如何开始的。种子密钥是192-bit / 6-word 值: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 密钥调度字节表 w[] 的维数是 4 列并且 Nb × (Nr + 1) 等于 4 × (12 + 1),或 52 行。KeyExpansion 将种子密钥的值拷贝到密钥调度字节表 w[] 的第一行。因为我的种子密钥是 192 位(24字节),并且 w[] 表总是 4 列,在这种情况下KeyExapansion 将种子密钥拷贝到 w[] 的前面 6 行。现在让我们看看 KeyExapansion 例程是如何填充密钥调度表其余部分的。在我的例子里,第一个被计算的行是第 6 行 ,因为第0-5行已被种子密钥的值填上了: temp = w[row-1] = 14 15 16 17 条件 (row % Nk == 0)为真,因此首先 RotWord 子程序被应用: temp = 15 16 17 14 这时 SubWord 被应用: temp = 59 47 f0 fa 用 Rcon[row / Nk] = Rcon[6 / 6] = 01 00 00 00 进行异或: temp = 58 47 f0 fa 这时用 w[row-Nk] = w[6-6] = 00 01 02 03 异或,产生了下面结果: w[6] = 58 46 f2 f9 密钥调度表 w[] 中其余所有行来重复这个过程本身。 总而言之,AES 加密和解密的一个重要部分就是从最初的种子密钥中生成多重轮密钥。这个 KeyExapansion 算法生成一个密钥调度并 以某种方式进行替代和置换,在这种方式中,加密和解密算法极其相似。
一. AES对称加密:
AES加密 分组
二. 分组密码的填充
分组密码的填充
e.g.:
PKCS#5填充方式
三. 流密码:
四. 分组密码加密中的四种模式:
3.1 ECB模式
优点:
1.简单;
2.有利于并行计算;
3.误差不会被传送;
缺点:
1.不能隐藏明文的模式;
2.可能对明文进行主动攻击;
3.2 CBC模式:
优点:
1.不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。
缺点:
1.不利于并行计算;
2.误差传递;
3.需要初始化向量IV
3.3 CFB模式:
优点:
1.隐藏了明文模式;
2.分组密码转化为流模式;
3.可以及时加密传送小于分组的数据;
缺点:
1.不利于并行计算;
2.误差传送:一个明文单元损坏影响多个单元;
3.唯一的IV;
3.4 OFB模式:
优点:
1.隐藏了明文模式;
2.分组密码转化为流模式;
3.可以及时加密传送小于分组的数据;
缺点:
1.不利于并行计算;
2.对明文的主动攻击是可能的;
3.误差传送:一个明文单元损坏影响多个单元;
例: ============================
import javax.crypto.*; import javax.crypto.spec.*;
public class AES { public static String asHex(byte buf[]) { StringBuffer strbuf = new StringBuffer(buf.length * 2); int i; for (i = 0; i < buf.length; i++) { if (((int) buf[i] & 0xff) < 0x10) strbuf.append("0"); strbuf.append(Long.toString((int) buf[i] & 0xff, 16)); } return strbuf.toString(); }
public static void main(String[] args) throws Exception { String message = "这是个加密的例子"; System.out.println(" 原文: " + message); System.out.println(" 原文转换格式显示:" +asHex(message.getBytes()));//string=》byte=》Hex 显示
//======生成密码 KeyGenerator kgen = KeyGenerator.getInstance("AES");// 获取密匙生成器 kgen.init(128);//生成128位的AES密码生成器 SecretKey skey = kgen.generateKey();// 生成密匙
byte[] raw = skey.getEncoded();//编码格式 SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");//生成一组扩展密钥,并放入一个数组之中
Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, skeySpec);//用ENCRYPT_MODE模式,用skeySpec密码组,生成AES加密方法 // ========加密message byte[] encrypted = cipher.doFinal(message.getBytes());// 加密message System.out.println(" 加密后: " + encrypted);//打印密文 System.out.println(" 密文转换格式后:"+asHex(encrypted));//把密文转换成16进制格式
//=======解密 cipher.init(Cipher.DECRYPT_MODE, skeySpec); byte[] original = cipher.doFinal(encrypted);// 解密 String originalString = new String(original, "UTF8");// 重新显示明文 System.out.println(" 解密后:" + originalString); System.out.println(" 解密出的消息转换格式显示:" +asHex(original));//byte型原文 转换成16进制型字符 现实 } }
================================== 运行结果: 原文: 这是个加密的例子 原文转换格式显示:e8bf99e698afe4b8aae58aa0e5af86e79a84e4be8be5ad90 加密后: [B@7e80fa6f 密文转换格式后:6ab7212486090091888c15d30d65a362c9abd56be3e34541b513cd80a6716099 解密后:这是个加密的例子 解密出的消息转换格式显示:e8bf99e698afe4b8aae58aa0e5af86e79a84e4be8be5ad90 |
AES加密算法原理
最新推荐文章于 2023-04-13 16:05:03 发布
AES加密算法原理
2011年09月22日 星期四 16:05