文档章节

高级加密标准AES加密(Javascript实现)

小鸟也疯狂
 小鸟也疯狂
发布于 2017/02/14 10:29
字数 4167
阅读 20
收藏 0
点赞 0
评论 0

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

<script language="JavaScript">
// sample key to expand:
//      2b 7e 15 16 28 ae d2 a6 ab f7 15 88 09 cf 4f 3c
// sample data:
//      32 43 f6 a8 88 5a 30 8d 31 31 98 a2 e0 37 07 34
// output:
//      39 25 84 1d 02 dc 09 fb dc 11 85 97 19 6a 0b 32

// sample key/data:
// PLAINTEXT: 00112233445566778899aabbccddeeff
// KEY:       000102030405060708090a0b0c0d0e0f
// OUTPUT:    69c4e0d86a7b0430d8cdb78070b4c55a

// accumulate values to put into text area
var accumulated_output_info;

// add a labeled value to the text area
function accumulate_output( str ) {
   accumulated_output_info = accumulated_output_info + str + "\n";
}

// convert a 8-bit value to a string
function cvt_hex8( val )
{
   var vh = (val>>>4)&0x0f;
   return vh.toString(16) + (val&0x0f).toString(16);
}

// convert a 32-bit value to a 8-char hex string
function cvt_hex32( val )
{
   var str="";
   var i;
   var v;

   for( i=7; i>=0; i-- )
   {
      v = (val>>>(i*4))&0x0f;
      str += v.toString(16);
   }
   return str;
}

// convert a two-digit hex value to a number
function cvt_byte( str )
{
  // get the first hex digit
  var val1 = str.charCodeAt(0);

  // do some error checking
  if ( val1 >= 48 && val1 <= 57 )
      // have a valid digit 0-9
      val1 -= 48;
   else if ( val1 >= 65 && val1 <= 70 )
      // have a valid digit A-F
      val1 -= 55;
   else if ( val1 >= 97 && val1 <= 102 )
      // have a valid digit A-F
      val1 -= 87;
   else
   {
      // not 0-9 or A-F, complain
      window.alert( str.charAt(1)+" is not a valid hex digit" );
      return -1;
   }

  // get the second hex digit
  var val2 = str.charCodeAt(1);

  // do some error checking
  if ( val2 >= 48 && val2 <= 57 )
      // have a valid digit 0-9
      val2 -= 48;
   else if ( val2 >= 65 && val2 <= 70 )
      // have a valid digit A-F
      val2 -= 55;
   else if ( val2 >= 97 && val2 <= 102 )
      // have a valid digit A-F
      val2 -= 87;
   else
   {
      // not 0-9 or A-F, complain
      window.alert( str.charAt(2)+" is not a valid hex digit" );
      return -1;
   }

   // all is ok, return the value
   return val1*16 + val2;
}

// add a byte to the output
function accumulate_byte( label, val )
{
   accumulated_output_info += label + cvt_hex8(val) + "\n";
}

// add a word to the output
function accumulate_wordarray( label, ary )
{
   var i, j;
   accumulated_output_info += label + " ";

   // process the four elements in this word
   for( j=0; j<4; j++ )
      accumulated_output_info += " " + cvt_hex8( ary[j] );

   // mark the end of the word
   accumulated_output_info += "\n";
}

// add an array to the output
function accumulate_array( label, ary )
{
   var i, j;
   var spacer="";

   // build a set of spaces of equal length to the label
   while( spacer.length < label.length )
      spacer += " ";

   // build the table
   for( i=0; i<16; i+= 4 )
   {
      // add label/spaces
      if ( i== 0 )
         accumulated_output_info += label + " ";
      else
         accumulated_output_info += spacer + " ";

      // process the four elements in this "row"
      for( j=0; j<4; j++ )
         accumulated_output_info += " " + cvt_hex8( ary[i+j] );

      // mark the end of this row
      accumulated_output_info += "\n";
   }
}

// S-Box substitution table
var S_enc = new Array(
 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16);

// inverse S-Box for decryptions
var S_dec = new Array(
 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38,
 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d,
 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2,
 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda,
 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a,
 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea,
 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85,
 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20,
 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31,
 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0,
 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26,
 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d);

// convert two-dimensional indicies to one-dim array indices
var I00 = 0;
var I01 = 1;
var I02 = 2;
var I03 = 3;
var I10 = 4;
var I11 = 5;
var I12 = 6;
var I13 = 7;
var I20 = 8;
var I21 = 9;
var I22 = 10;
var I23 = 11;
var I30 = 12;
var I31 = 13;
var I32 = 14;
var I33 = 15;
// conversion function for non-constant subscripts
// assume subscript range 0..3
function I(x,y) { return (x*4) + y; }

// remove spaces from input
function remove_spaces( instr ) {
   var i;
   var outstr="";

   for( i=0; i<instr.length; i++ )
      if ( instr.charAt(i) != " " )
         // not a space, include it
         outstr += instr.charAt(i);

   return outstr;
}

// get the message to encrypt/decrypt or the key
// return as a 16-byte array
function get_value( lbl, str, isASCII )
{
   var dbyte = new Array(16);
   var i;
   var val;    // one hex digit

   if ( isASCII )
   {
      // check length of data
      if ( str.length > 16 )
      {
         window.alert( lbl + " is too long, using the first 16 ASCII characters" );
      }

      // have ASCII data
      // 16 characters?
      if ( str.length >= 16 )
      {
         // 16 or more characters
         for( i=0; i<16; i++ )
         {
            dbyte[i] = str.charCodeAt(i);
         }
      }
      else
      {
         // less than 16 characters - fill with NULLs
         for( i=0; i<str.length; i++ )
         {
            dbyte[i] = str.charCodeAt(i);
         }
         for( i=str.length; i<16; i++ )
         {
            dbyte[i] = 0;
         }
      }
         
   }
   else
   {
      // have hex data - remove any spaces they used, then convert
      str = remove_spaces(str);

      // check length of data
      if ( str.length != 32 )
      {
         window.alert( lbl + " length wrong: Is " + str.length +
        " hex digits, but must be 128 bits (32 hex digits)");
         dbyte[0] = -1;
         return dbyte;
      }

      for( i=0; i<16; i++ )
      {
         // isolate and convert this substring
         dbyte[i] = cvt_byte( str.substr(i*2,2) );
         if( dbyte[i] < 0 )
         {
            // have an error
            dbyte[0] = -1;
            return dbyte;
         }
      } // for i
   } // if isASCII

   // return successful conversion
   return dbyte;
} // get_value

//do the AES GF(2**8) multiplication
// do this by the shift-and-"add" approach
function aes_mul( a, b )
{
   var res = 0;

   while( a > 0 )
   {
      if ( (a&1) != 0 )
         res = res ^ b;        // "add" to the result
      a >>>= 1;            // shift a to get next higher-order bit
      b <<= 1;            // shift multiplier also
   }

   // now reduce it modulo x**8 + x**4 + x**3 + x + 1
   var hbit = 0x10000;        // bit to test if we need to take action
   var modulus = 0x11b00;    // modulus - XOR by this to change value
   while( hbit >= 0x100 )
   {
      if ( (res & hbit) != 0 )        // if the high-order bit is set
         res ^= modulus;    // XOR with the modulus

      // prepare for the next loop
      hbit >>= 1;
      modulus >>= 1;
   }

   return res;
}

// apply the S-box substitution to the key expansion
function SubWord( word_ary )
{
   var i;

   for( i=0; i<16; i++ )
      word_ary[i] = S_enc[ word_ary[i] ];

   return word_ary;
}

// rotate the bytes in a word
function RotWord( word_ary )
{
   return new Array( word_ary[1], word_ary[2], word_ary[3], word_ary[0] );
}

// calculate the first item Rcon[i] = { x^(i-1), 0, 0, 0 }
// note we only return the first item
function Rcon( exp )
{
   var val = 2;
   var result = 1;

   // remember to calculate x^(exp-1)
   exp--;

   // process the exponent using normal shift and multiply
   while ( exp > 0 )
   {
      if ( (exp & 1) != 0 )
         result = aes_mul( result, val );

      // square the value
      val = aes_mul( val, val );

      // move to the next bit
      exp >>= 1;
   }

   return result;
}

// round key generation
// return a byte array with the expanded key information
function key_expand( key )
{
   var temp = new Array(4);
   var i, j;
   var w = new Array( 4*11 );

   // copy initial key stuff
   for( i=0; i<16; i++ )
   {
      w[i] = key[i];
   }
   accumulate_wordarray( "w[0] = ", w.slice(0,4) );
   accumulate_wordarray( "w[1] = ", w.slice(4,8) );
   accumulate_wordarray( "w[2] = ", w.slice(8,12) );
   accumulate_wordarray( "w[3] = ", w.slice(12,16) );

   // generate rest of key schedule using 32-bit words
   i = 4;
   while ( i < 44 )        // blocksize * ( rounds + 1 )
   {
      // copy word W[i-1] to temp
      for( j=0; j<4; j++ )
         temp[j] = w[(i-1)*4+j];

      if ( i % 4 == 0)
      {
         // temp = SubWord(RotWord(temp)) ^ Rcon[i/4];
         temp = RotWord( temp );
         accumulate_wordarray( "RotWord()=", temp );
         temp = SubWord( temp );
         accumulate_wordarray( "SubWord()=", temp );
         temp[0] ^= Rcon( i>>>2 );
         accumulate_wordarray( " ^ Rcon()=", temp );
      }

      // word = word ^ temp
      for( j=0; j<4; j++ )
         w[i*4+j] = w[(i-4)*4+j] ^ temp[j];
      accumulate_wordarray( "w["+i+"] = ", w.slice( i*4, i*4+4 ) );

      i++;
   }

   return w;
}

// do S-Box substitution
function SubBytes(state, Sbox)
{
   var i;

   for( i=0; i<16; i++ )
      state[i] = Sbox[ state[i] ];

   return state;
}

// shift each row as appropriate
function ShiftRows(state)
{
   var t0, t1, t2, t3;

   // top row (row 0) isn't shifted

   // next row (row 1) rotated left 1 place
   t0 = state[I10];
   t1 = state[I11];
   t2 = state[I12];
   t3 = state[I13];
   state[I10] = t1;
   state[I11] = t2;
   state[I12] = t3;
   state[I13] = t0;

   // next row (row 2) rotated left 2 places
   t0 = state[I20];
   t1 = state[I21];
   t2 = state[I22];
   t3 = state[I23];
   state[I20] = t2;
   state[I21] = t3;
   state[I22] = t0;
   state[I23] = t1;

   // bottom row (row 3) rotated left 3 places
   t0 = state[I30];
   t1 = state[I31];
   t2 = state[I32];
   t3 = state[I33];
   state[I30] = t3;
   state[I31] = t0;
   state[I32] = t1;
   state[I33] = t2;

   return state;
}

// inverset shift each row as appropriate
function InvShiftRows(state)
{
   var t0, t1, t2, t3;

   // top row (row 0) isn't shifted

   // next row (row 1) rotated left 1 place
   t0 = state[I10];
   t1 = state[I11];
   t2 = state[I12];
   t3 = state[I13];
   state[I10] = t3;
   state[I11] = t0;
   state[I12] = t1;
   state[I13] = t2;

   // next row (row 2) rotated left 2 places
   t0 = state[I20];
   t1 = state[I21];
   t2 = state[I22];
   t3 = state[I23];
   state[I20] = t2;
   state[I21] = t3;
   state[I22] = t0;
   state[I23] = t1;

   // bottom row (row 3) rotated left 3 places
   t0 = state[I30];
   t1 = state[I31];
   t2 = state[I32];
   t3 = state[I33];
   state[I30] = t1;
   state[I31] = t2;
   state[I32] = t3;
   state[I33] = t0;

   return state;
}

// process column info
function MixColumns(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 mixing, and put back into array
      state[I(0,col)] = aes_mul(2,c0) ^ aes_mul(3,c1) ^ c2 ^ c3;
      state[I(1,col)] = c0 ^ aes_mul(2,c1) ^ aes_mul(3,c2) ^ c3;
      state[I(2,col)] = c0 ^ c1 ^ aes_mul(2,c2) ^ aes_mul(3,c3);
      state[I(3,col)] = aes_mul(3,c0) ^ c1 ^ c2 ^ aes_mul(2,c3);
   }

   return state;
}

// 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;
}

// do encrytion
function aes_encrypt() {
   var w     = new Array( 44 );            // subkey information
   var state = new Array( 16 );            // working state
   var round;

   accumulated_output_info = "";

   // get the message from the user
   // also check if it is ASCII or hex
   var msg = get_value( "Message", document.stuff.indata.value, document.stuff.intype[0].checked );

   // problems??
   if ( msg[0] < 0 ) {
      document.stuff.details.value = accumulated_output_info;
      return;
   }
   accumulate_array( "Input bits", msg );

   // get the key from the user
   var key = get_value( "Key", document.stuff.key.value, false );
   // problems??
   if ( key[0] < 0 ) {
      document.stuff.details.value = accumulated_output_info;
      return;
   }
   accumulate_array( "Key bits", key );

    // expand the key
    accumulate_output("密钥扩展");
    w = key_expand( key );

    // initial state = message in columns (transposed from what we input)
    state = transpose( msg );

    accumulate_array( "Initial state", state );
    // display the round key - Transpose due to the way it is stored/used
    accumulate_output("轮密码加");
    accumulate_array( "Round Key", transpose(w.slice( 0, 16 )) ); 
    state = AddRoundKey(state, w, 0);

    for( round = 1; round < 10; round ++ ) {
        accumulate_array( "Round " + round, state );
        accumulate_output("字节代替");
        state = SubBytes(state, S_enc);
        accumulate_array( "After SubBytes", state );
        accumulate_output("行移位");
        state = ShiftRows(state);
        accumulate_array( "After ShiftRows", state );
        accumulate_output("列混淆");
        state = MixColumns(state);
        accumulate_array( "After MixColumns", state );
        // display the round key - Transpose due to the way it is stored/used
        accumulate_array( "Round Key", transpose(w.slice( round*4*4, round*16+16 )) ); 
        accumulate_output("轮密码加");
        // note here the spec uses 32-bit words, we are using bytes, so an extra *4
        state = AddRoundKey(state, w, round*4*4);
   }

    accumulate_output("字节代替");
    SubBytes(state, S_enc);
    accumulate_array( "After SubBytes", state );
    accumulate_output("行移位");
    ShiftRows(state);
    accumulate_array( "After ShiftRows", state );
    accumulate_output("轮密码加");
    AddRoundKey(state, w, 10*4*4);
    accumulate_array( "Output", state );

    // process output
    AES_output = transpose( state );
    format_AES_output( );
    document.stuff.details.value = accumulated_output_info;
}

// do decryption
function aes_decrypt() {
   var w = new Array( 44 );            // subkey information
   var state = new Array( 16 );            // working state
   var round;

   accumulated_output_info = "";

   // get the message from the user
   // also check if it is ASCII or hex
   var msg = get_value( "Message", document.stuff.indata.value,
        document.stuff.intype[0].checked );

   // problems??
   if ( msg[0] < 0 )
   {
      document.stuff.details.value = accumulated_output_info;
      return;
   }
   accumulate_array( "Input bits", msg );

   // get the key from the user
   var key = get_value( "Key", document.stuff.key.value, false );
   // problems??
   if ( key[0] < 0 )
   {
      document.stuff.details.value = accumulated_output_info;
      return;
   }
   accumulate_array( "Key bits", key );

   // expand the key
   w = key_expand( key );

   // initial state = message
   state = transpose( msg );

   accumulate_array( "Initial state", state );
   // display the round key - Transpose due to the way it is stored/used
   accumulate_array( "Round Key", transpose(w.slice( 10*4*4, 10*4*4+16 )) ); 
   state = AddRoundKey(state, w, 10*4*4);

   for( round=9; round>=1; round-- )
   {
      accumulate_array( "Round " + round, state );
      state = InvShiftRows(state);
      accumulate_array( "After InvShiftRows", state );
      state = SubBytes(state, S_dec);
      accumulate_array( "After SubBytes", state );
      // display the round key - Transpose due to the way it is stored/used
      accumulate_array( "Round Key", transpose(w.slice( round*4*4, round*16+16 )) ); 
      // note here the spec uses 32-bit words, we are using bytes, so an extra *4
      state = AddRoundKey(state, w, round*4*4);
      accumulate_array( "After AddRoundKey", state );
      state = InvMixColumns(state);
   }

   InvShiftRows(state);
   accumulate_array( "After InvShiftRows", state );
   SubBytes(state, S_dec);
   accumulate_array( "After SubBytes", state );
   AddRoundKey(state, w, 0);
   accumulate_array( "Output", state );

   // process output
   AES_output = transpose( state );
   format_AES_output( );
   document.stuff.details.value = accumulated_output_info;
}
</SCRIPT>
</HEAD>
<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>

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));
  }

 

本文转载自:https://my.oschina.net/dubenju/blog/835160

共有 人打赏支持
小鸟也疯狂

小鸟也疯狂

粉丝 11
博文 32
码字总数 9097
作品 0
朝阳
程序员
前后端API交互如何保证数据安全性?

前言 前后端分离的开发方式,我们以接口为标准来进行推动,定义好接口,各自开发自己的功能,最后进行联调整合。无论是开发原生的APP还是webapp还是PC端的软件,只要是前后端分离的模式,就避...

尹吉欢 ⋅ 06/04 ⋅ 0

JavaScript外部调用Js(自己理解加参考百度)

JavaScript文件外部加载的好处: 避免使用 避免使用CDATA。 统一定义JavaScript代码,方便查看,方便维护。 使代码更安全,可以压缩,加密单个JavaScript文件。 浏览器可以缓存JavaScript文件...

codingcoge ⋅ 01/11 ⋅ 0

CreateJS结合Falsh工具生成Canvas动画(加密字符串的由来)

CreateJS是一款制作Canvas动画的工具。 官网如下: http://www.createjs.com/ http://www.createjs.cc/ 使用CreateJS时最大的疑问就是JS上的加密字符串是如何来的,比如: 其实这个加密字符串...

easonjim ⋅ 2017/04/24 ⋅ 0

JavaScript开发区块链只需200行代码

JavaScript开发一个简单的区块链只需200行代码。通过JavaScript的开发实现过程,你将理解区块链是什么:区块链就是一个分布式数据库,存储结构是一个不断增长的链表,链表中包含着许多有序的...

hahajin ⋅ 05/14 ⋅ 0

C#/.NET字符串加密和解密实现(AES和RSA代码举例)

在很多C#项目中,都需要实现对字符串的加密和解密,那么如何实现呢?现在对称密钥加密中最流行的就是AES加密法。 密码学中的高级加密标准(Advanced Encryption Standard,AES),又称Rijndae...

小星星程序员 ⋅ 2014/08/12 ⋅ 0

BeeCDN —— 开源前端库 CDN 加速服务正式上线

闭关了好几个月,煞费苦心开发制作的前端库CDN加速服务:https://www.beecdn.com,今天正式公开发布哦。 BeeCDN介绍 做过前端开发的同学,肯定用过比如BootCDN之类的前端库加速服务,把项目中...

DragonFK ⋅ 04/24 ⋅ 2

js 实现sm4国密算法加密,解密

js实现 sm4的前台加密,java后台解密,完全搞不懂,求

笑笑不说话- ⋅ 04/18 ⋅ 0

冬日/AesEncrypt

#AesEncrypt:Aes加密/解密示例项目   附件中的“AesEncrypt.zip”是本项目的exe文件,可直接下载下来运行和查看。   高级加密标准(英语:Advanced Encryption Standard,缩写:AES),...

冬日 ⋅ 2016/08/05 ⋅ 0

接口非对称加密+Retrofit2(未完成)

照常例打出我搜到的相关文章 http://blog.csdn.net/ouyangpeng/article/details/50983574 https://www.zhihu.com/question/20874499 在讲接口加密之前,先了解AES与RSA的区别。 (具体算法咱...

qq名长是因为你没给我备注 ⋅ 04/03 ⋅ 0

Java开发小技巧(四):配置文件敏感信息处理

前言 不知道在上一篇文章中你有没有发现,中的数据库密码配置是这样写的: 其实这不是真正的密码,而是经过AES加密的。 AES的Java实现 AES(高级加密标准)是美国联邦政府采用的一种区块加密...

kMacro ⋅ 2017/12/22 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

windows profesional 2017 build problem

.net framework .... https://stackoverflow.com/questions/43330915/could-not-load-file-or-assembly-microsoft-build-frameworkvs-2017...

机油战士 ⋅ 22分钟前 ⋅ 0

python3中报错的解决方法(长期更新)

1、ImportError: No module named ‘DjangoUeditor’ 出错原因:安装DjangoUeditor库适用于python2,需要下载适用python3的 下载地址:https://github.com/twz915/DjangoUeditor3 2、python3......

xiaoge2016 ⋅ 27分钟前 ⋅ 0

数据结构与算法之双向链表

一、双向链表 1.双向链表的结点结构 typedef struct DualNode{ ElemType data; struct DualNode *prior; // 前驱结点 struct DualNode *next; // 后继结点}DualNode, *DuL...

aibinxiao ⋅ 46分钟前 ⋅ 0

五大最核心的大数据技术

大数据技术有5个核心部分,数据采集、数据存储、数据清洗、数据挖掘、数据可视化。关于这5个部分,有哪些核心技术?这些技术有哪些潜在价值?看完今天的文章就知道了。 大数据学习群:7165810...

董黎明 ⋅ 48分钟前 ⋅ 0

PhpStorm 头部注释、类注释和函数注释的设置

首先,PhpStorm中文件、类、函数等注释的设置在:setting-》Editor-》FIle and Code Template-》Includes下设置即可,其中方法的默认是这样的: /**${PARAM_DOC}#if (${TYPE_HINT} != "v...

nsns ⋅ 48分钟前 ⋅ 0

spring.net AOP

http://www.springframework.net/doc-latest/reference/html/aop-quickstart.html https://www.cnblogs.com/wujy/archive/2013/04/06/3003120.html...

whoisliang ⋅ 53分钟前 ⋅ 0

【HAVENT原创】创建 Dockerfile 生成新的镜像,并发布到 DockerHub

注意:Win7 与 Win10 的版本存在差异,Win7 版本使用 Docker Quickstart Terminal 进入控制台,Win10下面直接用管理员权限打开控制台或者 PowerShell 即可;另外 Win7 下面只能访问 C盘,/ap...

HAVENT ⋅ 53分钟前 ⋅ 0

pom.xml出现web.xml is missing ...解决方案

提示信息应该能看懂。也就是缺少了web.xml文件,<failOnMissingWebXml>被设置成true了。 搜索了一下,Stack Overflow上的答案解决了问题,分享一下。 目前被顶次数最多的回答原文如下: This...

源哥L ⋅ 54分钟前 ⋅ 0

js时间戳与日期格式之间相互转换

1. 将时间戳转换成日期格式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 // 简单的一句代码 var date = new Date(时间戳); //获取一个时间对象 /** 1. 下面是获取时间日期的方法,需要什么样的格式自己...

Jack088 ⋅ 59分钟前 ⋅ 0

web添加log4j

添加xml配置log4j.properties # Global logging configuration---root日志设置#log4j.rootLogger=info,dailyRollingFile,stdoutlog4j.rootLogger=debug,stdout,dailyRollingFile---......

黄柳淞 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部