最近项目中有一个需求,实现AES128的加密算法,用于硬件和平台的通信。硬件加密部分使用C语言完成、平台有两种不同的环境:java(Linux)和C#(Windows)。在网上搜集了一些资料,有人实现过纯C代码的AES加密解密算法,这样实际上有一种较为简单的解决思路:加密部分直接拿过来使用;解密部分可以打包为dll(windows环境)或SO(linux环境)库供平台调用。但考虑到环境的兼容性等问题最后决定分别在Java和C#中实现算法的解密部分。
AES128算法的实现参考如下代码:https://github.com/openluopworld/aes_128
一、数据加密部分,直接调用项目中的加密函数即可。
二、数据解密部分,也就是用Java和C#将aes_encrypt_128函数重新实现。
2.1、Java中实现aes_encrypt_128
和C语言相比在Java中实现解密算法需要注意几个细节:
1、Java中没有数组指针的概念:C语言的数组指针主要是方便控制计算的范围,这个功能实际上可以用数组的索引来实现,
2、C语言中的uint8_t 也就是unsigned char在Java中与之对应的是byte,但Java的byte取值为-128-127:0xf2由于超出127,在java中默认是int类型,这里在声明的时候需要强制类型转换。
同时为了和C中的计算对应,在超过127的时候可以与0x0FF做逻辑与(Java中的位运算会将byte转换为int然后进行计算)处理,转换为int操作,这里做逻辑与运算的目的是为了将-128-127的范围转换为0-255的范围,在Java中这一步十分重要,因为java没有无符号的概念,如果不处理byte的负数转换为整型后仍为负数,这在大部分的时候并不是我们想要的结果。
代码如下:
package com.run.gradewall.model;
import java.util.Arrays;
/*
*
* 主要是解密、解密,10轮产生轮秘钥的函数,
* 加密与解密函数分别调用产生轮秘钥的函数,每轮的输入与轮密钥异或一次,轮秘钥产生函数需要调用S盒函数,进行映射
* 变量: *roundkeys存放产生轮秘钥的指针,*plaintext存放明文的指针,*ciphertext存放密文的指针,*state运行加密操作的4*4矩阵
*
*/
public class AES {
/*
* 作用:进行映射操作的S盒
* 类型:静态的一个Byte的数据
*/
private static byte[] SBOX = new byte[] {
//0 1 2 3 4 5 6 7 8 9 A B C D E F
0x63, 0x7c, 0x77, 0x7b, (byte) 0xf2, 0x6b, 0x6f, (byte) 0xc5, 0x30, 0x01, 0x67, 0x2b, (byte) 0xfe, (byte) 0xd7, (byte) 0xab, 0x76,
(byte)0xca, (byte)0x82, (byte)0xc9, 0x7d, (byte)0xfa, 0x59, 0x47, (byte)0xf0, (byte)0xad, (byte)0xd4, (byte)0xa2, (byte)0xaf, (byte)0x9c, (byte)0xa4, 0x72, (byte)0xc0,
(byte)0xb7, (byte)0xfd, (byte)0x93, 0x26, 0x36, 0x3f, (byte)0xf7, (byte)0xcc, 0x34, (byte)0xa5, (byte)0xe5, (byte)0xf1, 0x71, (byte)0xd8, 0x31, 0x15,
0x04, (byte)0xc7, 0x23, (byte)0xc3, 0x18, (byte)0x96, 0x05, (byte)0x9a, 0x07, 0x12, (byte)0x80, (byte)0xe2, (byte)0xeb, 0x27, (byte)0xb2, 0x75,
0x09, (byte)0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, (byte)0xa0, 0x52, 0x3b, (byte)0xd6, (byte) 0xb3, 0x29, (byte)0xe3, 0x2f, (byte)0x84,
0x53, (byte)0xd1, 0x00, (byte)0xed, 0x20, (byte)0xfc, (byte)0xb1, 0x5b, 0x6a, (byte)0xcb, (byte)0xbe, 0x39, 0x4a, 0x4c, 0x58, (byte)0xcf,
(byte)0xd0, (byte)0xef, (byte)0xaa, (byte)0xfb, 0x43, 0x4d, 0x33, (byte)0x85, 0x45, (byte)0xf9, 0x02, 0x7f, 0x50, 0x3c, (byte)0x9f, (byte)0xa8,
0x51, (byte)0xa3, 0x40, (byte)0x8f, (byte)0x92, (byte)0x9d, 0x38, (byte)0xf5, (byte)0xbc, (byte)0xb6, (byte)0xda, 0x21, 0x10, (byte)0xff, (byte)0xf3, (byte)0xd2,
(byte)0xcd, 0x0c, 0x13, (byte)0xec, 0x5f, (byte)0x97, 0x44, 0x17, (byte)0xc4, (byte)0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, (byte)0x81, 0x4f, (byte)0xdc, 0x22, 0x2a, (byte)0x90, (byte)0x88, 0x46, (byte)0xee, (byte)0xb8, 0x14, (byte)0xde, 0x5e, 0x0b, (byte)0xdb,
(byte)0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, (byte)0xc2, (byte)0xd3, (byte)0xac, 0x62, (byte)0x91, (byte)0x95, (byte)0xe4, 0x79,
(byte)0xe7, (byte)0xc8, 0x37, 0x6d, (byte)0x8d, (byte)0xd5, 0x4e, (byte)0xa9, 0x6c, 0x56, (byte)0xf4, (byte)0xea, 0x65, 0x7a, (byte)0xae, 0x08,
(byte)0xba, 0x78, 0x25, 0x2e, 0x1c, (byte)0xa6, (byte)0xb4, (byte)0xc6, (byte)0xe8, (byte)0xdd, 0x74, 0x1f, 0x4b, (byte)0xbd, (byte)0x8b, (byte)0x8a,
0x70, 0x3e, (byte)0xb5, 0x66, 0x48, 0x03, (byte)0xf6, 0x0e, 0x61, 0x35, 0x57, (byte)0xb9, (byte)0x86, (byte)0xc1, 0x1d, (byte)0x9e,
(byte)0xe1, (byte)0xf8, (byte)0x98, 0x11, 0x69, (byte)0xd9, (byte)0x8e, (byte)0x94, (byte)0x9b, 0x1e, (byte)0x87, (byte)0xe9, (byte)0xce, 0x55, 0x28, (byte)0xdf,
(byte)0x8c, (byte)0xa1, (byte)0x89, 0x0d, (byte)0xbf, (byte)0xe6, 0x42, 0x68, 0x41, (byte)0x99, 0x2d, 0x0f, (byte)0xb0, 0x54, (byte)0xbb, 0x16 };
/*
* 作用:进行逆映射的S盒
* 类型:静态的一个Byte的数据
*/
private static byte[] INV_SBOX = new byte[] {
0x52, 0x09, 0x6a, (byte) 0xd5, 0x30, 0x36, (byte) 0xa5, 0x38, (byte) 0xbf, 0x40, (byte) 0xa3, (byte) 0x9e, (byte) 0x81, (byte) 0xf3, (byte) 0xd7, (byte) 0xfb,
0x7c, (byte) 0xe3, 0x39, (byte) 0x82, (byte) 0x9b, 0x2f, (byte) 0xff, (byte) 0x87, 0x34, (byte) 0x8e, 0x43, 0x44, (byte) 0xc4, (byte) 0xde, (byte) 0xe9, (byte) 0xcb,
0x54, 0x7b, (byte) 0x94, 0x32, (byte) 0xa6, (byte) 0xc2, 0x23, 0x3d, (byte) 0xee, 0x4c, (byte) 0x95, 0x0b, 0x42, (byte) 0xfa, (byte) 0xc3, 0x4e,
0x08, 0x2e, (byte) 0xa1, 0x66, 0x28, (byte) 0xd9, 0x24, (byte) 0xb2, 0x76, 0x5b, (byte) 0xa2, 0x49, 0x6d, (byte) 0x8b, (byte) 0xd1, 0x25,
0x72, (byte) 0xf8, (byte) 0xf6, 0x64, (byte) 0x86, 0x68, (byte) 0x98, 0x16, (byte) 0xd4, (byte) 0xa4, 0x5c, (byte) 0xcc, 0x5d, 0x65, (byte) 0xb6, (byte) 0x92,
0x6c, 0x70, 0x48, 0x50, (byte) 0xfd, (byte) 0xed, (byte) 0xb9, (byte) 0xda, 0x5e, 0x15, 0x46, 0x57, (byte) 0xa7, (byte) 0x8d, (byte) 0x9d, (byte) 0x84,
(byte) 0x90, (byte) 0xd8, (byte) 0xab, 0x00, (byte) 0x8c, (byte) 0xbc, (byte) 0xd3, 0x0a, (byte) 0xf7, (byte) 0xe4, 0x58, 0x05, (byte) 0xb8, (byte) 0xb3, 0x45, 0x06,
(byte) 0xd0, 0x2c, 0x1e, (byte) 0x8f, (byte) 0xca, 0x3f, 0x0f, 0x02, (byte) 0xc1, (byte) 0xaf, (byte) 0xbd, 0x03, 0x01, 0x13, (byte) 0x8a, 0x6b,
0x3a, (byte) 0x91, 0x11, 0x41, 0x4f, 0x67, (byte) 0xdc, (byte) 0xea, (byte) 0x97, (byte) 0xf2, (byte) 0xcf, (byte) 0xce, (byte) 0xf0, (byte) 0xb4, (byte) 0xe6, 0x73,
(byte) 0x96, (byte) 0xac, 0x74, 0x22, (byte) 0xe7, (byte) 0xad, 0x35, (byte) 0x85, (byte) 0xe2, (byte) 0xf9, 0x37, (byte) 0xe8, 0x1c, 0x75, (byte) 0xdf, 0x6e,
0x47, (byte) 0xf1, 0x1a, 0x71, 0x1d, 0x29, (byte) 0xc5, (byte) 0x89, 0x6f, (byte) 0xb7, 0x62, 0x0e, (byte) 0xaa, 0x18, (byte) 0xbe, 0x1b,
(byte) 0xfc, 0x56, 0x3e, 0x4b, (byte) 0xc6, (byte) 0xd2, 0x79, 0x20, (byte) 0x9a, (byte) 0xdb, (byte) 0xc0, (byte) 0xfe, 0x78, (byte) 0xcd, 0x5a, (byte) 0xf4,
0x1f, (byte) 0xdd, (byte) 0xa8, 0x33, (byte) 0x88, 0x07, (byte) 0xc7, 0x31, (byte) 0xb1, 0x12, 0x10, 0x59, 0x27, (byte) 0x80, (byte) 0xec, 0x5f,
0x60, 0x51, 0x7f, (byte) 0xa9, 0x19, (byte) 0xb5, 0x4a, 0x0d, 0x2d, (byte) 0xe5, 0x7a, (byte) 0x9f, (byte) 0x93, (byte) 0xc9, (byte) 0x9c, (byte) 0xef,
(byte) 0xa0, (byte) 0xe0, 0x3b, 0x4d, (byte) 0xae, 0x2a, (byte) 0xf5, (byte) 0xb0, (byte) 0xc8, (byte) 0xeb, (byte) 0xbb, 0x3c, (byte) 0x83, 0x53, (byte) 0x99, 0x61,
0x17, 0x2b, 0x04, 0x7e, (byte) 0xba, 0x77, (byte) 0xd6, 0x26, (byte) 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d };
/*
* 作用:秘钥扩展中要进行异或操作的一维数组
* 类型:静态的一个Byte的数据
*/
private static byte[] RC = new byte[] {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, (byte) 0x80, 0x1b, 0x36};
/*
* 作用:初始设置的秘钥,为16个Byte
* 类型:一个Byte的数据
*/
private static byte[] key = new byte[] { 0x40, 0x41, 0x40, 0x41, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x41, 0x40, 0x41, 0x39};
/*
* 作用:存放秘钥扩展后的轮秘钥,为44个字,共176Byte
* 类型:一个Byte的数据
*/
private static int AES_BLOCK_SIZE = 16;
private static int AES_ROUNDS = 10;
private static byte[] roundkeys = new byte[176];// AES-128 has 10 rounds, and there is a AddRoundKey before first round. (10+1)x16=176.
/*
* 功能: 由初始秘钥产生轮秘钥,将产生的轮秘钥放在*roundkeys中
* 参数: 传入初始秘钥的地址,和轮秘钥的地址
* 返回值: 无
*/
private void aes_key_schedule_128(byte[] key, byte[]roundkeys)
{
byte[] temp = new byte[4];
int last4bytes = 12; // point to the last 4 bytes of one round
int i;
int index =0;//用于循环计算
for (i = 0; i < 16; i++)
{
roundkeys[index++] = key[i];
}
//利用索引解决C中的指针问题
int index_l4b = 0;
for (i = 0; i < 10; i++)
{ //更新代替引用
// k0-k3 for next round
//java中的byte-127--128需要&0x0FF处理
temp[3] = SBOX[roundkeys[last4bytes+index_l4b++]&0x0FF];
temp[0] = SBOX[roundkeys[last4bytes+index_l4b++]&0x0FF];
temp[1] = SBOX[roundkeys[last4bytes+index_l4b++]&0x0FF];
temp[2] = SBOX[roundkeys[last4bytes+index_l4b++]&0x0FF];
temp[0] ^= RC[i];
int lastround = 16*i;
roundkeys[index++] = (byte) (temp[0] ^ roundkeys[lastround++]);
roundkeys[index++] = (byte) (temp[1] ^ roundkeys[lastround++]);
roundkeys[index++] = (byte) (temp[2] ^ roundkeys[lastround++]);
roundkeys[index++] = (byte) (temp[3] ^ roundkeys[lastround++]);
// k4-k7 for next round
roundkeys[index++] = (byte) (roundkeys[last4bytes+index_l4b++] ^ roundkeys[lastround++]);
roundkeys[index++] = (byte) (roundkeys[last4bytes+index_l4b++] ^ roundkeys[lastround++]);
roundkeys[index++] = (byte) (roundkeys[last4bytes+index_l4b++] ^ roundkeys[lastround++]);
roundkeys[index++] = (byte) (roundkeys[last4bytes+index_l4b++] ^ roundkeys[lastround++]);
// k8-k11 for next round
roundkeys[index++] = (byte) (roundkeys[last4bytes+index_l4b++] ^ roundkeys[lastround++]);
roundkeys[index++] = (byte) (roundkeys[last4bytes+index_l4b++] ^ roundkeys[lastround++]);
roundkeys[index++] = (byte) (roundkeys[last4bytes+index_l4b++] ^ roundkeys[lastround++]);
roundkeys[index++] = (byte) (roundkeys[last4bytes+index_l4b++] ^ roundkeys[lastround++]);
// k12-k15 for next round
roundkeys[index++] = (byte) (roundkeys[last4bytes+index_l4b++] ^ roundkeys[lastround++]);
roundkeys[index++] = (byte) (roundkeys[last4bytes+index_l4b++] ^ roundkeys[lastround++]);
roundkeys[index++] = (byte) (roundkeys[last4bytes+index_l4b++] ^ roundkeys[lastround++]);
roundkeys[index++] = (byte) (roundkeys[last4bytes+index_l4b++] ^ roundkeys[lastround++]);
}
}
/*
* 功能: 将矩阵中的每个横列进行逆循环式移位
* 描述:
* Row0: s0 s4 s8 s12 >>> 0 byte
* Row1: s1 s5 s9 s13 >>> 1 byte
* Row2: s2 s6 s10 s14 >>> 2 bytes
* Row3: s3 s7 s11 s15 >>> 3 bytes
* 参数: 传入一个4*4的矩阵
* 返回值: 无
*/
private void inv_shift_rows(byte[] state)
{
byte temp;
//row1
temp = state[13];
state[13] = state[9];
state[9] = state[5];
state[5] = state[1];
state[1] = temp;
//row2
temp = state[14];
state[14] = state[6];
state[6] = temp;
temp = state[10];
state[10] = state[2];
state[2] = temp;
// row3
temp = state[3];
state[3] = state[7];
state[7] = state[11];
state[11] = state[15];
state[15] = temp;
}
/*
* 功能: 加密或解密中使用的多项式(x^8 + x^4 + x^3 + x + 1 = 0)更快处理数据
* 不使用mul(uint8_t a, uint8_t b),而使用mul2(int8_t a)
* 参数: 传入要处理的一个Byte数据
* 返回值: 直接返回处理后的数据
*/
private final byte mul2(byte a)
{
//考虑java中byte有符号
return (byte) ((a & 0x80) != 0 ? (( (a & 0x0FF) << 1) ^ 0x1b) : ( (a & 0x0FF) << 1));
}
/*
* 功能: 对密文进行解密的解密函数,将解密后的明文放在*plaintext中
* 参数: 传入轮秘钥的地址、明文、密文的地址
* 返回值: 无
*/
private void aes_decrypt_128(byte[] roundkeys, byte[] ciphertext, byte[] plaintext)
{
byte[] tmp = new byte[16];
byte t,u,v;
int i,j;
int rdIndex =160 ;//定义roundkeys的索引,这里相当于指针的作用
// first round
for(i=0 ; i<AES_BLOCK_SIZE; ++i)
{
plaintext[i] = (byte) (ciphertext[i] ^ roundkeys[rdIndex+i]);
}
rdIndex -= 16;
inv_shift_rows(plaintext);
for (i = 0; i < AES_BLOCK_SIZE; ++i)
{
plaintext[i] = INV_SBOX[plaintext[i]&0x0FF];
}
for (j = 1; j < AES_ROUNDS; ++j)
{
// Inverse AddRoundKey
for (i = 0; i < AES_BLOCK_SIZE; ++i) {
tmp[i] = (byte) (plaintext[i] ^ roundkeys[rdIndex+i]);
}
/*
* Inverse MixColumns
* [0e 0b 0d 09] [s0 s4 s8 s12]
* [09 0e 0b 0d] . [s1 s5 s9 s13]
* [0d 09 0e 0b] [s2 s6 s10 s14]
* [0b 0d 09 0e] [s3 s7 s11 s15]
*/
for (i = 0; i < AES_BLOCK_SIZE; i += 4) {
t = (byte) (tmp[i] ^ tmp[i + 1] ^ tmp[i + 2] ^ tmp[i + 3]);
plaintext[i] = (byte) (t ^ tmp[i] ^ mul2((byte) (tmp[i] ^ tmp[i + 1])));
plaintext[i + 1] = (byte) (t ^ tmp[i + 1] ^ mul2((byte) (tmp[i + 1] ^ tmp[i + 2])));
plaintext[i + 2] = (byte) (t ^ tmp[i + 2] ^ mul2((byte) (tmp[i + 2] ^ tmp[i + 3])));
plaintext[i + 3] = (byte) (t ^ tmp[i + 3] ^ mul2((byte) (tmp[i + 3] ^ tmp[i])));
u = mul2(mul2((byte) (tmp[i] ^ tmp[i + 2])));
v = mul2(mul2((byte) (tmp[i + 1] ^ tmp[i + 3])));
t = mul2((byte) (u ^ v));
plaintext[i] ^= t ^ u;
plaintext[i + 1] ^= t ^ v;
plaintext[i + 2] ^= t ^ u;
plaintext[i + 3] ^= t ^ v;
}
// Inverse ShiftRows
inv_shift_rows(plaintext);
// Inverse SubBytes
for (i = 0; i < AES_BLOCK_SIZE; ++i) {
plaintext[i] = INV_SBOX[plaintext[i]&0x0FF];
}
rdIndex -= 16;
}
// last AddRoundKey
for (i = 0; i < AES_BLOCK_SIZE; ++i) {
plaintext[i] ^= roundkeys[rdIndex+i];
}
}
}
2.2、C#中实现aes_encrypt_128
1、和C语言相比C#中也没有数组指针的概念,这里采用和Java中同样的处理方法利用数组索引解决;
2、但与Java不同C#中的byte的取值范围和C语言中unsigned char一样为0-255,不需要与0x0FF进行位与操作处理。
C#对应的代码如下:
using System;
/*
*
* 主要是解密、解密,10轮产生轮秘钥的函数,
* 加密与解密函数分别调用产生轮秘钥的函数,每轮的输入与轮密钥异或一次,轮秘钥产生函数需要调用S盒函数,进行映射
* 变量: *roundkeys存放产生轮秘钥的指针,*plaintext存放明文的指针,*ciphertext存放密文的指针,*state运行加密操作的4*4矩阵
*
*/
namespace AES128
{
public class AES
{
static int AES_BLOCK_SIZE = 16;
static int AES_ROUNDS = 10;
static int AES_ROUND_KEY_SIZE = 176;// AES-128 has 10 rounds, and there is a AddRoundKey before first round. (10+1)x16=176.
/*
* 作用:初始设置的秘钥,为16个Byte
* 类型:一个Byte的数据
*/
byte[] key = { 0x40, 0x41, 0x40, 0x41, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x41, 0x40, 0x41, 0x39 };
/*
* 作用:存放秘钥扩展后的轮秘钥,为44个字,共176Byte
* 类型:一个Byte的数据
*/
byte[] roundkeys = new byte[AES_ROUND_KEY_SIZE];
/*
* 作用:秘钥扩展中要进行异或操作的一维数组
* 类型:静态的一个Byte的数据
*/
static byte[] RC = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 };
/*
* 作用:进行映射操作的S盒
* 类型:静态的一个Byte的数据
*/
static byte[] SBOX = {
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 };
/*
* 作用:进行逆映射的S盒
* 类型:静态的一个Byte的数据
*/
static byte[] INV_SBOX = {
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 };
/**
* 功能: 由初始秘钥产生轮秘钥,将产生的轮秘钥放在*roundkeys中
* 参数: 传入初始秘钥的地址,和轮秘钥的地址
* 返回值: 无
*/
void aes_key_schedule_128(byte[] key, byte[] roundkeys)
{
byte[] temp = new byte[4];
int last4bytes = 12; // point to the last 4 bytes of one round
int i;
int index = 0;//用于循环计算
for (i = 0; i < 16; i++)
{
roundkeys[index++] = key[i];
}
//利用索引解决C中的指针问题
int index_l4b = 0;
for (i = 0; i < 10; i++)
{ //更新代替引用
// k0-k3 for next round
//java中的byte-127--128需要&0x0FF处理\C#中没有必要
temp[3] = SBOX[roundkeys[last4bytes + index_l4b++]];
temp[0] = SBOX[roundkeys[last4bytes + index_l4b++]];
temp[1] = SBOX[roundkeys[last4bytes + index_l4b++]];
temp[2] = SBOX[roundkeys[last4bytes + index_l4b++]];
temp[0] ^= RC[i];
int lastround = 16 * i;
roundkeys[index++] = (byte)(temp[0] ^ roundkeys[lastround++]);
roundkeys[index++] = (byte)(temp[1] ^ roundkeys[lastround++]);
roundkeys[index++] = (byte)(temp[2] ^ roundkeys[lastround++]);
roundkeys[index++] = (byte)(temp[3] ^ roundkeys[lastround++]);
// k4-k7 for next round
roundkeys[index++] = (byte)(roundkeys[last4bytes + index_l4b++] ^ roundkeys[lastround++]);
roundkeys[index++] = (byte)(roundkeys[last4bytes + index_l4b++] ^ roundkeys[lastround++]);
roundkeys[index++] = (byte)(roundkeys[last4bytes + index_l4b++] ^ roundkeys[lastround++]);
roundkeys[index++] = (byte)(roundkeys[last4bytes + index_l4b++] ^ roundkeys[lastround++]);
// k8-k11 for next round
roundkeys[index++] = (byte)(roundkeys[last4bytes + index_l4b++] ^ roundkeys[lastround++]);
roundkeys[index++] = (byte)(roundkeys[last4bytes + index_l4b++] ^ roundkeys[lastround++]);
roundkeys[index++] = (byte)(roundkeys[last4bytes + index_l4b++] ^ roundkeys[lastround++]);
roundkeys[index++] = (byte)(roundkeys[last4bytes + index_l4b++] ^ roundkeys[lastround++]);
// k12-k15 for next round
roundkeys[index++] = (byte)(roundkeys[last4bytes + index_l4b++] ^ roundkeys[lastround++]);
roundkeys[index++] = (byte)(roundkeys[last4bytes + index_l4b++] ^ roundkeys[lastround++]);
roundkeys[index++] = (byte)(roundkeys[last4bytes + index_l4b++] ^ roundkeys[lastround++]);
roundkeys[index++] = (byte)(roundkeys[last4bytes + index_l4b++] ^ roundkeys[lastround++]);
}
}
/*
* 功能: 将矩阵中的每个横列进行逆循环式移位
* 描述:
* Row0: s0 s4 s8 s12 >>> 0 byte
* Row1: s1 s5 s9 s13 >>> 1 byte
* Row2: s2 s6 s10 s14 >>> 2 bytes
* Row3: s3 s7 s11 s15 >>> 3 bytes
* 参数: 传入一个4*4的矩阵
* 返回值: 无
*/
private void inv_shift_rows(byte[] state)
{
byte temp;
//row1
temp = state[13];
state[13] = state[9];
state[9] = state[5];
state[5] = state[1];
state[1] = temp;
//row2
temp = state[14];
state[14] = state[6];
state[6] = temp;
temp = state[10];
state[10] = state[2];
state[2] = temp;
// row3
temp = state[3];
state[3] = state[7];
state[7] = state[11];
state[11] = state[15];
state[15] = temp;
}
/*
* 功能: 加密或解密中使用的多项式(x^8 + x^4 + x^3 + x + 1 = 0)更快处理数据
* 不使用mul(uint8_t a, uint8_t b),而使用mul2(int8_t a)
* 参数: 传入要处理的一个Byte数据
* 返回值: 直接返回处理后的数据
*/
private byte mul2(byte a)
{
//考虑java中byte有符号
return (byte)((a & 0x80) != 0 ? ((a << 1) ^ 0x1b) : (a << 1));
}
/*
* 功能: 对密文进行解密的解密函数,将解密后的明文放在*plaintext中
* 参数: 传入轮秘钥的地址、明文、密文的地址
* 返回值: 无
*/
private void aes_decrypt_128(byte[] roundkeys, byte[] ciphertext, byte[] plaintext)
{
byte[] tmp = new byte[16];
byte t, u, v;
int i, j;
int rdIndex = 160;//定义roundkeys的索引,这里相当于指针的作用
// first round
for (i = 0; i < AES_BLOCK_SIZE; ++i)
{
plaintext[i] = (byte)(ciphertext[i] ^ roundkeys[rdIndex + i]);
}
rdIndex -= 16;
inv_shift_rows(plaintext);
for (i = 0; i < AES_BLOCK_SIZE; ++i)
{
plaintext[i] = INV_SBOX[plaintext[i] & 0x0FF];
}
for (j = 1; j < AES_ROUNDS; ++j)
{
// Inverse AddRoundKey
for (i = 0; i < AES_BLOCK_SIZE; ++i)
{
tmp[i] = (byte)(plaintext[i] ^ roundkeys[rdIndex + i]);
}
/*
* Inverse MixColumns
* [0e 0b 0d 09] [s0 s4 s8 s12]
* [09 0e 0b 0d] . [s1 s5 s9 s13]
* [0d 09 0e 0b] [s2 s6 s10 s14]
* [0b 0d 09 0e] [s3 s7 s11 s15]
*/
for (i = 0; i < AES_BLOCK_SIZE; i += 4)
{
t = (byte)(tmp[i] ^ tmp[i + 1] ^ tmp[i + 2] ^ tmp[i + 3]);
plaintext[i] = (byte)(t ^ tmp[i] ^ mul2((byte)(tmp[i] ^ tmp[i + 1])));
plaintext[i + 1] = (byte)(t ^ tmp[i + 1] ^ mul2((byte)(tmp[i + 1] ^ tmp[i + 2])));
plaintext[i + 2] = (byte)(t ^ tmp[i + 2] ^ mul2((byte)(tmp[i + 2] ^ tmp[i + 3])));
plaintext[i + 3] = (byte)(t ^ tmp[i + 3] ^ mul2((byte)(tmp[i + 3] ^ tmp[i])));
u = mul2(mul2((byte)(tmp[i] ^ tmp[i + 2])));
v = mul2(mul2((byte)(tmp[i + 1] ^ tmp[i + 3])));
t = mul2((byte)(u ^ v));
plaintext[i] ^=(byte)(t ^ u);
plaintext[i + 1] ^= (byte)(t ^ v);
plaintext[i + 2] ^= (byte)(t ^ u);
plaintext[i + 3] ^= (byte)(t ^ v);
}
// Inverse ShiftRows
inv_shift_rows(plaintext);
// Inverse SubBytes
for (i = 0; i < AES_BLOCK_SIZE; ++i)
{
plaintext[i] = INV_SBOX[plaintext[i] & 0x0FF];
}
rdIndex -= 16;
}
// last AddRoundKey
for (i = 0; i < AES_BLOCK_SIZE; ++i)
{
plaintext[i] ^= roundkeys[rdIndex + i];
}
}
}
}