【前端Js】高级加密解密标准AES加密(Javascript代码实现)



高级加密标准(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


  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值