高级加密标准(Advanced Encryption Standard,AES)
是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一。Rijndael加密算法为比利时密码学家Joan Daemen和Vincent Rijmen所设计,结合两位作者的名字,以Rijndael之命名之,投稿高级加密标准的甄选流程。(Rijdael的发音近于 "Rhinedoll"。)
AES的区块长度固定为128比特,密钥长度则可以是128,192或256比特;而Rijndael使用的密钥和区块长度均可以是128,192或256比特。
AES加密有很多轮的重复和变换。大致步骤如下:
1、密钥扩展(KeyExpansion),
2、初始轮(Initial Round),
3、重复9轮(Rounds),每一轮又包括:SubBytes、ShiftRows、MixColumns、AddRoundKey,
4、最终轮(Final Round),最终轮没有MixColumns。
4种操作:字节替代(SubBytes)、行移位(ShiftRows)、列混淆(MixColumns)和轮密钥加(AddRoundKey)。
1 字节代替
字节代替的主要功能是通过S盒完成一个字节到另外一个字节的映射。
2 行移位
行移位的功能是实现一个4x4矩阵内部字节之间的置换。
3 列混淆
列混淆:利用GF(2^8)域上算术特性的一个代替。
4 轮密码加
这个操作相对简单,其依据的原理是“任何数和自身的异或结果为0”。加密过程中,每轮的输入与每轮密钥异或一次;因此,解密时再异或上该轮的密钥即可恢复输入。
5 密钥扩展
密钥扩展过程说明:
1) 将初始密钥以列为主,转化为4个32 bits的字,分别记为w[0…3];
2) 按照如下方式,依次求解w[j],其中j是整数并且属于[4,43];
3) 若j%4=0,则w[j]=w[j-4]⊕g(w[j-1]),否则w[j]=w[j-4]⊕w[j-1];
函数g的流程说明:
4) 将w循环左移一个字节;
5) 分别对每个字节按S盒进行映射;
6) 与32 bits的常量(RC[j/4],0,0,0)进行异或,RC是一个一维数组,其值如下。(RC的值只需要有10个,而此处用了11个,实际上RC[0]在运算中没有用到,增加RC[0]是为了便于程序中用数组表示。由于j的最小取值是4,j/4的最小取值则是1,因此不会产生错误。)
RC = {00, 01, 02, 04, 08, 10, 20, 40, 80, 1B, 36}
Js核心代码:
// inverse process column info
function InvMixColumns(state)
{
var col;
var c0, c1, c2, c3;
for( col=0; col<4; col++ )
{
c0 = state[I(0,col)];
c1 = state[I(1,col)];
c2 = state[I(2,col)];
c3 = state[I(3,col)];
// do inverse mixing, and put back into array
state[I(0,col)] = aes_mul(0x0e,c0) ^ aes_mul(0x0b,c1)
^ aes_mul(0x0d,c2) ^ aes_mul(0x09,c3);
state[I(1,col)] = aes_mul(0x09,c0) ^ aes_mul(0x0e,c1)
^ aes_mul(0x0b,c2) ^ aes_mul(0x0d,c3);
state[I(2,col)] = aes_mul(0x0d,c0) ^ aes_mul(0x09,c1)
^ aes_mul(0x0e,c2) ^ aes_mul(0x0b,c3);
state[I(3,col)] = aes_mul(0x0b,c0) ^ aes_mul(0x0d,c1)
^ aes_mul(0x09,c2) ^ aes_mul(0x0e,c3);
}
return state;
}
// insert subkey information
function AddRoundKey( state, w, base )
{
var col;
for( col=0; col<4; col++ )
{
state[I(0,col)] ^= w[base+col*4];
state[I(1,col)] ^= w[base+col*4+1];
state[I(2,col)] ^= w[base+col*4+2];
state[I(3,col)] ^= w[base+col*4+3];
}
return state;
}
// return a transposed array
function transpose( msg )
{
var row, col;
var state = new Array( 16 );
for( row=0; row<4; row++ )
for( col=0; col<4; col++ )
state[I(row,col)] = msg[I(col,row)];
return state;
}
// final AES state
var AES_output = new Array(16);
// format AES output
// -- uses the global array DES_output
function format_AES_output()
{
var i;
var bits;
var str="";
// what type of data do we have to work with?
if ( document.stuff.outtype[0].checked )
{
// convert each set of bits back to ASCII
for( i=0; i<16; i++ )
str += String.fromCharCode( AES_output[i] );
}
else
{
// output hexdecimal data (insert spaces)
str = cvt_hex8( AES_output[0] );
for( i=1; i<16; i++ )
{
str += " " + cvt_hex8( AES_output[i] );
}
}
// copy to textbox
document.stuff.outdata.value = str;
}
所有核心代码secret.js【点击下载】
Html测试页面:
<BODY>
2001年Rijndael算法成为高级加密标准(Advanced Encryption Standard,AES)的获胜者。
这个标准用来替代原先的DES,AES的区块长度固定为128比特,密钥长度则可以是128,192或256比特;而Rijndael使用的密钥和区块长度均可以是128,192或256比特。
<P>
<form name="stuff">
<br>
输入一个16个ASCII字符以内的字符串。
<p>
<table>
<tr>
<td>输入信息:</td>
<td><input type="text" name="indata" size="50" value="abcdefghijklmnop" /></td>
<td><input type="radio" name="intype" checked>ASCII
<input type="radio" name="intype">十六进制
</td>
</tr>
<tr>
<td>密钥</td>
<td><select name="key">
<OPTION value="0f1571c947d9e8590cb7add6af7f6798">0f 15 71 c9 47 d9 e8 59 0c b7 ad d6 af 7f 67 98</OPTION>
<OPTION value="f6cc34cdc555c5418254260203ad3ecd">f6 cc 34 cd c5 55 c5 41 82 54 26 02 03 ad 3e cd</OPTION>
<OPTION value="3070971ab7ce45063fd2573f49f5420d">30 70 97 1a b7 ce 45 06 3f d2 57 3f 49 f5 42 0d</OPTION>
<OPTION value="a9aa1f9fd153bcb6c7834212c51f5c41">a9 aa 1f 9f d1 53 bc b6 c7 83 42 12 c5 1f 5c 41</OPTION>
<OPTION value="d2f60c436e7ccebb8eaceaf3f86c8bad">d2 f6 0c 43 6e 7c ce bb 8e ac ea f3 f8 6c 8b ad</OPTION>
<OPTION value="2b7e151628aed2a6abf7158809cf4f3c">2b 7e 15 16 28 ae d2 a6 ab f7 15 88 09 cf 4f 3c</OPTION>
</SELECT></TD>
<TD></TD>
</TR>
<TR>
<TD colspan=3 align=center>
<INPUT type="button" value="加密" onClick="aes_encrypt();" />
<INPUT type="button" value="解密" onClick="aes_decrypt();" />
</TD>
</TR>
<TR>
<TD>输出信息:</TD>
<TD><INPUT type="text" name="outdata" size="50" /></TD>
<TD><INPUT type="radio" name="outtype" onClick="format_AES_output();">ASCII
<INPUT type="radio" name="outtype" checked onClick="format_AES_output();">十六进制
</TD>
</TR>
</TABLE>
<hr>
细节:<BR>
<TEXTAREA name="details" id="details" rows="25" cols="90"></TEXTAREA>
</FORM>
</BODY>
显示页面
Java验证
private byte[] keys = {
0x0f,0x15,0x71,(byte)0xc9, 0x47,(byte)0xd9,(byte)0xe8,0x59,
0x0c,(byte)0xb7,(byte)0xad,(byte)0xd6,(byte)0xaf,0x7f,0x67,(byte)0x98
};
//KeyGenerator 提供对称密钥生成器的功能,支持各种算法
private KeyGenerator keygen;
//SecretKey 负责保存对称密钥
private SecretKey deskey;
//Cipher负责完成加密或解密工作
private Cipher c;
//该字节数组负责保存加密的结果
private byte[] cipherByte;
public AesDemo() throws NoSuchAlgorithmException, NoSuchPaddingException{
Security.addProvider(new com.sun.crypto.provider.SunJCE());
// //实例化支持DES算法的密钥生成器(算法名称命名需按规定,否则抛出异常)
// keygen = KeyGenerator.getInstance("AES");
// //生成密钥
// deskey = keygen.generateKey();
deskey= new SecretKeySpec(keys, "AES");
System.out.println("密钥:" + UBytes.toHexString(deskey.getEncoded()));
//生成Cipher对象,指定其支持的DES算法
c = Cipher.getInstance("AES/ECB/NOPADDING"); // PKCS5Padding
}
/**
* 对字符串加密
*
* @param str
* @return
* @throws InvalidKeyException
* @throws IllegalBlockSizeException
* @throws BadPaddingException
*/
public byte[] Encrytor(String str) throws InvalidKeyException,
IllegalBlockSizeException, BadPaddingException {
// 根据密钥,对Cipher对象进行初始化,ENCRYPT_MODE表示加密模式
c.init(Cipher.ENCRYPT_MODE, deskey);
byte[] src = str.getBytes();
System.out.println("明文:" + UBytes.toHexString(src));
// 加密,结果保存进cipherByte
cipherByte = c.doFinal(src);
System.out.println("密文:" + UBytes.toHexString(cipherByte));
return cipherByte;
}
/**
* 对字符串解密
*
* @param buff
* @return
* @throws InvalidKeyException
* @throws IllegalBlockSizeException
* @throws BadPaddingException
*/
public byte[] Decryptor(byte[] buff) throws InvalidKeyException,
IllegalBlockSizeException, BadPaddingException {
// 根据密钥,对Cipher对象进行初始化,DECRYPT_MODE表示加密模式
c.init(Cipher.DECRYPT_MODE, deskey);
cipherByte = c.doFinal(buff);
return cipherByte;
}
/**
* @param args
* @throws NoSuchPaddingException
* @throws NoSuchAlgorithmException
* @throws BadPaddingException
* @throws IllegalBlockSizeException
* @throws InvalidKeyException
*/
public static void main(String[] args) throws Exception {
AesDemo de1 = new AesDemo();
String msg ="abcdefghijklmnop";
byte[] encontent = de1.Encrytor(msg);
byte[] decontent = de1.Decryptor(encontent);
System.out.println("解密:" + UBytes.toHexString(decontent));
System.out.println("明文是:" + msg);
System.out.println("加密后:" + new String(encontent));
System.out.println("解密后:" + new String(decontent));
}
结果:
密钥:0F 15 71 C9 47 D9 E8 59 0C B7 AD D6 AF 7F 67 98
明文:61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70
密文:11 0A AF F3 F2 D5 6C 9E 69 1A 95 A5 2E 19 28 EB
解密:61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70
明文是:abcdefghijklmnop
解密后:abcdefghijklmnop