【声明】

(1) 本文源码

在一位未署名网友源码基础上,利用Qt编程,实现了AES加解密算法,并添加了文件加解密功能。在此表示感谢!该源码仅供学习交流,请勿用于商业目的。

(2) 图片及描述

除图1外,图片及部分解析来自http://zh.wikipedia.org/wiki/%E9%AB%98%E7%BA%A7%E5%8A%A0%E5%AF%86%E6%A0%87%E5%87%86。图1为个人劳动成果,请勿盗用此图。

【简介】

AES(Advanced Encryption Standard,高级加密标准),于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一。

【算法描述】

AES的区块长度固定为128 比特,密钥长度则可以是128,192或256比特。AES加密过程是在一个4×4的字节矩阵上运作,这个矩阵又称为“体(state)”,其初值就是一个明文区块(矩阵中一个元素大小就是明文区块中的一个Byte)。加密时,各轮AES加密循环(除最后一轮外)均包含4个步骤: 1.AddRoundKey — 矩阵中的每一个字节都与该次轮密钥(round key)做XOR运算;每个子密钥由密钥生成方案产生。 2.SubBytes — 通过一个非线性的替换函数,用查找表的方式把每个字节替换成对应的字节。 3.ShiftRows — 将矩阵中的每个横列进行循环式移位。 4.MixColumns — 为了充分混合矩阵中各个直行的操作。这个步骤使用线性转换来混合每内联的四个字节。 最后一个加密循环中省略MixColumns步骤,而以另一个AddRoundKey取代。 AES算法加解密流程如图1所示:

图1 AES加密算法流程图

【算法解析】

1 常量定义

S-Box

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

Rcon

  1. const unsigned char AES::Rcon[11*4]=
  2. {
  3. 0x00, 0x00, 0x00, 0x00,
  4. 0x01, 0x00, 0x00, 0x00,
  5. 0x02, 0x00, 0x00, 0x00,
  6. 0x04, 0x00, 0x00, 0x00,
  7. 0x08, 0x00, 0x00, 0x00,
  8. 0x10, 0x00, 0x00, 0x00,
  9. 0x20, 0x00, 0x00, 0x00,
  10. 0x40, 0x00, 0x00, 0x00,
  11. 0x80, 0x00, 0x00, 0x00,
  12. 0x1b, 0x00, 0x00, 0x00,
  13. 0x36, 0x00, 0x00, 0x00
  14. };
const unsigned char AES::Rcon[11*4]=
{
0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00,
0x1b, 0x00, 0x00, 0x00,
0x36, 0x00, 0x00, 0x00
};

2 密钥扩展(Expand Key) AES算法利用外部输入密钥Key(又称为基密钥,密钥串的字数为Nk),通过密钥扩展可得到共4(Nk+1)字的扩展密钥w[4× (Nr+1)],其中Nr为数据分组密钥的轮数。密钥扩展主要包括3个步骤: (1) 位置变换RotWord() 把一个4字节的基密钥序列[a0,a1,a2,a3],左移一个字节变为[a1,a2,a3,a0]。

  1. void AES::RotWord(unsigned char * word,unsigned char *result)
  2. {
  3. result[0] = word[1];
  4. result[1] = word[2];
  5. result[2] = word[3];
  6. result[3] = word[0];
  7. }
void AES::RotWord(unsigned char * word,unsigned char *result)
{
result[0] = word[1];
result[1] = word[2];
result[2] = word[3];
result[3] = word[0];
}

(2) SubWord() 对一个4字节的输入字[a0,a1,a2,a3],每一个字节进行S盒变换。

  1. void AES::SubWord(unsigned char * word,unsigned char* result)
  2. {
  3. result[0] =  Sbox[ 16*(word[0] >> 4)+ (word[0] & 0x0f) ];
  4. result[1] =  Sbox[ 16*(word[1] >> 4)+ (word[1] & 0x0f) ];
  5. result[2] =  Sbox[ 16*(word[2] >> 4)+ (word[2] & 0x0f) ];
  6. result[3] =  Sbox[ 16*(word[3] >> 4)+ (word[3] & 0x0f) ];
  7. }
void AES::SubWord(unsigned char * word,unsigned char* result)
{
result[0] = Sbox[ 16*(word[0] >> 4)+ (word[0] & 0x0f) ];
result[1] = Sbox[ 16*(word[1] >> 4)+ (word[1] & 0x0f) ];
result[2] = Sbox[ 16*(word[2] >> 4)+ (word[2] & 0x0f) ];
result[3] = Sbox[ 16*(word[3] >> 4)+ (word[3] & 0x0f) ];
}

(3) 变换Rcon[] Rcon[i]表示32比特字符串[xi-1,00,00,00]。

  1. temp[0] = (byte)( (int)temp[0] ^ (int) Rcon[4*(row/Nk)+0] );
  2. temp[1] = (byte)( (int)temp[1] ^ (int) Rcon[4*(row/Nk)+1] );
  3. temp[2] = (byte)( (int)temp[2] ^ (int) Rcon[4*(row/Nk)+2] );
  4. temp[3] = (byte)( (int)temp[3] ^ (int) Rcon[4*(row/Nk)+3] );
temp[0] = (byte)( (int)temp[0] ^ (int) Rcon[4*(row/Nk)+0] );
temp[1] = (byte)( (int)temp[1] ^ (int) Rcon[4*(row/Nk)+1] );
temp[2] = (byte)( (int)temp[2] ^ (int) Rcon[4*(row/Nk)+2] );
temp[3] = (byte)( (int)temp[3] ^ (int) Rcon[4*(row/Nk)+3] );

扩展密钥的前Nk个字就是基密钥Key;以后的字w[i]等于它前一个字w[i-1]与前第Nk个字w[i-Nk]的异或,即w[i]=w[i-1] XOR w[i-Nk]。但如果i是Nk的倍数,则w[i]=w[i-Nk] XOR SubWord(RotWord(w[i-1])) XOR Rcon[i/Nk]。

  1. void AES::KeyExpansion()
  2. {
  3. unsigned char result[4],result2[4];
  4. memset(w,0,16*15);//没有根据key的位数进行开辟空间,直接开辟了最大空间
  5. int row;
  6. for (row = 0; row < Nk; row++)//Nk=4,6,8得到初始密码
  7. {
  8. w[4*row+0] =  key[4*row];
  9. w[4*row+1] =  key[4*row+1];
  10. w[4*row+2] =  key[4*row+2];
  11. w[4*row+3] =  key[4*row+3];
  12. }
  13. unsigned char temp[4];
  14. for (row = Nk; row < Nb * (Nr+1); row++)//产生密匙顺序表
  15. {
  16. temp[0] =  w[4*(row-1)+0];
  17. temp[1] =  w[4*(row-1)+1];
  18. temp[2] =  w[4*(row-1)+2];
  19. temp[3] =  w[4*(row-1)+3];
  20. if (row % Nk == 0)
  21. {
  22. RotWord(temp,result);
  23. SubWord(result,result2);
  24. memcpy(temp,result2,4);//
  25. //RotWord 例程非常简单,它接受 4 字节的数组并将它们向左旋转位移 1 位。
  26. //因为轮回次序表 w[] 有四列,所以 RotWord 会将一行 w[] 向左旋转位移.
  27. //SubWord 例程使用置换表 Sbox,针对密钥次序表 w[] 的给定行执行逐字节置换。
  28. temp[0] = (byte)( (int)temp[0] ^ (int) Rcon[4*(row/Nk)+0] );
  29. temp[1] = (byte)( (int)temp[1] ^ (int) Rcon[4*(row/Nk)+1] );
  30. temp[2] = (byte)( (int)temp[2] ^ (int) Rcon[4*(row/Nk)+2] );
  31. temp[3] = (byte)( (int)temp[3] ^ (int) Rcon[4*(row/Nk)+3] );
  32. }
  33. else if ( Nk > 6 && (row % Nk == 4) )
  34. {
  35. SubWord(temp,result);
  36. memcpy(temp,result,4);
  37. }
  38. // w[row] = w[row-Nk] xor temp
  39. w[4*row+0] = (byte) ( (int) w[4*(row-Nk)+0] ^ (int)temp[0] );
  40. w[4*row+1] = (byte) ( (int) w[4*(row-Nk)+1] ^ (int)temp[1] );
  41. w[4*row+2] = (byte) ( (int) w[4*(row-Nk)+2] ^ (int)temp[2] );
  42. w[4*row+3] = (byte) ( (int) w[4*(row-Nk)+3] ^ (int)temp[3] );
  43. }  // for loop
  44. }  // KeyExpansion()
void AES::KeyExpansion()
{
unsigned char result[4],result2[4];
memset(w,0,16*15);//没有根据key的位数进行开辟空间,直接开辟了最大空间
int row;
for (row = 0; row < Nk; row++)//Nk=4,6,8得到初始密码
{
w[4*row+0] = key[4*row];
w[4*row+1] = key[4*row+1];
w[4*row+2] = key[4*row+2];
w[4*row+3] = key[4*row+3];
}
unsigned char temp[4];
for (row = Nk; row < Nb * (Nr+1); row++)//产生密匙顺序表
{
temp[0] = w[4*(row-1)+0];
temp[1] = w[4*(row-1)+1];
temp[2] = w[4*(row-1)+2];
temp[3] = w[4*(row-1)+3];
if (row % Nk == 0)
{
RotWord(temp,result);
SubWord(result,result2);
memcpy(temp,result2,4);//
//RotWord 例程非常简单,它接受 4 字节的数组并将它们向左旋转位移 1 位。
//因为轮回次序表 w[] 有四列,所以 RotWord 会将一行 w[] 向左旋转位移.
//SubWord 例程使用置换表 Sbox,针对密钥次序表 w[] 的给定行执行逐字节置换。
temp[0] = (byte)( (int)temp[0] ^ (int) Rcon[4*(row/Nk)+0] );
temp[1] = (byte)( (int)temp[1] ^ (int) Rcon[4*(row/Nk)+1] );
temp[2] = (byte)( (int)temp[2] ^ (int) Rcon[4*(row/Nk)+2] );
temp[3] = (byte)( (int)temp[3] ^ (int) Rcon[4*(row/Nk)+3] );
}
else if ( Nk > 6 && (row % Nk == 4) )
{
SubWord(temp,result);
memcpy(temp,result,4);
}
// w[row] = w[row-Nk] xor temp
w[4*row+0] = (byte) ( (int) w[4*(row-Nk)+0] ^ (int)temp[0] );
w[4*row+1] = (byte) ( (int) w[4*(row-Nk)+1] ^ (int)temp[1] );
w[4*row+2] = (byte) ( (int) w[4*(row-Nk)+2] ^ (int)temp[2] );
w[4*row+3] = (byte) ( (int) w[4*(row-Nk)+3] ^ (int)temp[3] );
} // for loop
} // KeyExpansion()

3 轮密钥加(Add Round Key) 如图2所示,经过扩展的密钥,根据加密的轮数用相应的扩展密钥的4个数据项和中间状态矩阵上的列进行按位异或:

[s(0,c)’, s(1,c)’, s(2,c)’, s(3,c)’]= [s(0,c), s(1,c), s(2,c), s(3,c)] XOR [W(round×Nb+c)]。

图2 Add Round Key

  1. void AES::AddRoundKey(int round)
  2. {
  3. int r,c;
  4. for (r = 0; r < 4; r++)
  5. {
  6. for (c = 0; c < 4; c++)
  7. {//w:    4*x+y
  8. State[r][c]=(unsigned char)((int)State[r][c]^(int)w[4*((round*4)+c)+r]);
  9. }
  10. }
  11. }  // AddRoundKey()
void AES::AddRoundKey(int round)
{
int r,c;
for (r = 0; r < 4; r++)
{
for (c = 0; c < 4; c++)
{//w: 4*x+y
State[r][c]=(unsigned char)((int)State[r][c]^(int)w[4*((round*4)+c)+r]);
}
}
} // AddRoundKey()

4 字节替代(Substitute Bytes) 如图3所示,从S-Box中找出S[A]=S[x,y]的值,其中A为输入矩阵任一元素。将

转换为

图3 Substitute Bytes

  1. void AES::SubBytes()
  2. {
  3. int r,c;
  4. for (r = 0; r < 4; r++)
  5. {
  6. for (c = 0; c < 4; c++)
  7. {
  8. State[r][c] =  Sbox[ 16*(State[r][c] >> 4)+ ( State[r][c] & 0x0f) ];
  9. }
  10. }
  11. }  // SubBytes
  12. void AES::InvSubBytes()
  13. {
  14. int r,c;
  15. for (r = 0; r < 4; r++)
  16. {
  17. for (c = 0; c < 4; c++)
  18. {
  19. State[r][c] =  iSbox[ 16*( State[r][c] >> 4)+( State[r][c] & 0x0f) ];
  20. }
  21. }
  22. }  // InvSubBytes
void AES::SubBytes()
{
int r,c;
for (r = 0; r < 4; r++)
{
for (c = 0; c < 4; c++)
{
State[r][c] = Sbox[ 16*(State[r][c] >> 4)+ ( State[r][c] & 0x0f) ];
}
}
} // SubBytes void AES::InvSubBytes()
{
int r,c;
for (r = 0; r < 4; r++)
{
for (c = 0; c < 4; c++)
{
State[r][c] = iSbox[ 16*( State[r][c] >> 4)+( State[r][c] & 0x0f) ];
}
}
} // InvSubBytes

5 行移位(Shift Rows) 如图4所示,将矩阵中的每一个横列进行循环式移位。移位的规则是:第一行维持不变,第二、第三、第四行的每个字节向左循环移位的偏移量分别为1格,2格,3格。

图4 Shift Rows

  1. void AES::ShiftRows()
  2. {
  3. unsigned char temp[4*4];
  4. int r,c;
  5. for (r = 0; r < 4; r++)  // copy State into temp[]
  6. {
  7. for (c = 0; c < 4; c++)
  8. {
  9. temp[4*r+c] =  State[r][c];
  10. }
  11. }
  12. for (r = 1; r < 4; r++)  // shift temp into State
  13. {
  14. for (c = 0; c < 4; c++)
  15. {
  16. State[r][c] = temp[ 4*r+ (c + r) % Nb ];
  17. }
  18. }
  19. }  // ShiftRows()
  20. void AES::InvShiftRows()
  21. {
  22. unsigned char temp[4*4];
  23. int r,c;
  24. for (r = 0; r < 4; r++)  // copy State into temp[]
  25. {
  26. for (c = 0; c < 4; c++)
  27. {
  28. temp[4*r+c] =  State[r][c];
  29. }
  30. }
  31. for (r = 1; r < 4; r++)  // shift temp into State
  32. {
  33. for (c = 0; c < 4; c++)
  34. {
  35. State[r][ (c + r) % Nb ] = temp[4*r+c];
  36. }
  37. }
  38. }  // InvShiftRows()
void AES::ShiftRows()
{
unsigned char temp[4*4];
int r,c;
for (r = 0; r < 4; r++) // copy State into temp[]
{
for (c = 0; c < 4; c++)
{
temp[4*r+c] = State[r][c];
}
} for (r = 1; r < 4; r++) // shift temp into State
{
for (c = 0; c < 4; c++)
{
State[r][c] = temp[ 4*r+ (c + r) % Nb ];
}
}
} // ShiftRows() void AES::InvShiftRows()
{
unsigned char temp[4*4];
int r,c;
for (r = 0; r < 4; r++) // copy State into temp[]
{
for (c = 0; c < 4; c++)
{
temp[4*r+c] = State[r][c];
}
}
for (r = 1; r < 4; r++) // shift temp into State
{
for (c = 0; c < 4; c++)
{
State[r][ (c + r) % Nb ] = temp[4*r+c];
}
}
} // InvShiftRows()

6 列混淆(Mix Columns) 如图5所示,列变换的中间状态矩阵State如下所示:

经过上述变换,原来的列被混淆为新列。

图5 Mix Column

  1. void AES::MixColumns()
  2. {
  3. unsigned char temp[4*4];
  4. int r,c;
  5. for (r = 0; r < 4; r++)  // copy State into temp[]
  6. {
  7. for (c = 0; c < 4; c++)
  8. {
  9. temp[4*r+c] =  State[r][c];
  10. }
  11. }
  12. for (c = 0; c < 4; c++)
  13. {
  14. State[0][c] = (unsigned char) ( (int)gfmultby02(temp[0+c]) ^ (int)gfmultby03(temp[4*1+c]) ^
  15. (int)gfmultby01(temp[4*2+c]) ^ (int)gfmultby01(temp[4*3+c]) );
  16. State[1][c] = (unsigned char) ( (int)gfmultby01(temp[0+c]) ^ (int)gfmultby02(temp[4*1+c]) ^
  17. (int)gfmultby03(temp[4*2+c]) ^ (int)gfmultby01(temp[4*3+c]) );
  18. State[2][c] = (unsigned char) ( (int)gfmultby01(temp[0+c]) ^ (int)gfmultby01(temp[4*1+c]) ^
  19. (int)gfmultby02(temp[4*2+c]) ^ (int)gfmultby03(temp[4*3+c]) );
  20. State[3][c] = (unsigned char) ( (int)gfmultby03(temp[0+c]) ^ (int)gfmultby01(temp[4*1+c]) ^
  21. (int)gfmultby01(temp[4*2+c]) ^ (int)gfmultby02(temp[4*3+c]) );
  22. }
  23. }  // MixColumns
  24. void AES::InvMixColumns()
  25. {
  26. unsigned char temp[4*4];
  27. int r,c;
  28. for (r = 0; r < 4; r++)  // copy State into temp[]
  29. {
  30. for (c = 0; c < 4; c++)
  31. {
  32. temp[4*r+c] =  State[r][c];
  33. }
  34. }
  35. for (c = 0; c < 4; c++)
  36. {
  37. State[0][c] = (unsigned char) ( (int)gfmultby0e(temp[c]) ^ (int)gfmultby0b(temp[4+c]) ^
  38. (int)gfmultby0d(temp[4*2+c]) ^ (int)gfmultby09(temp[4*3+c]) );
  39. State[1][c] = (unsigned char) ( (int)gfmultby09(temp[c]) ^ (int)gfmultby0e(temp[4+c]) ^
  40. (int)gfmultby0b(temp[4*2+c]) ^ (int)gfmultby0d(temp[4*3+c]) );
  41. State[2][c] = (unsigned char) ( (int)gfmultby0d(temp[c]) ^ (int)gfmultby09(temp[4+c]) ^
  42. (int)gfmultby0e(temp[4*2+c]) ^ (int)gfmultby0b(temp[4*3+c]) );
  43. State[3][c] = (unsigned char) ( (int)gfmultby0b(temp[c]) ^ (int)gfmultby0d(temp[4+c]) ^
  44. (int)gfmultby09(temp[4*2+c]) ^ (int)gfmultby0e(temp[4*3+c]) );
  45. }
  46. }  // InvMixColumns
  47. unsigned char AES::gfmultby01(unsigned char b)
  48. {
  49. return b;
  50. }
  51. unsigned char AES::gfmultby02(unsigned char b)
  52. {
  53. if (b < 0x80)
  54. return (unsigned char)(int)(b <<1);
  55. else
  56. return (unsigned char)( (int)(b << 1) ^ (int)(0x1b) );
  57. }
  58. unsigned char AES::gfmultby03(unsigned char b)
  59. {
  60. return (unsigned char) ( (int)gfmultby02(b) ^ (int)b );
  61. }
  62. unsigned char AES::gfmultby09(unsigned char b)
  63. {
  64. return (unsigned char)( (int)gfmultby02(gfmultby02(gfmultby02(b))) ^
  65. (int)b );
  66. }
  67. unsigned char AES::gfmultby0b(unsigned char b)
  68. {
  69. return (unsigned char)( (int)gfmultby02(gfmultby02(gfmultby02(b))) ^
  70. (int)gfmultby02(b) ^
  71. (int)b );
  72. }
  73. unsigned char AES::gfmultby0d(unsigned char b)
  74. {
  75. return (unsigned char)( (int)gfmultby02(gfmultby02(gfmultby02(b))) ^
  76. (int)gfmultby02(gfmultby02(b)) ^
  77. (int)(b) );
  78. }
  79. unsigned char AES::gfmultby0e(unsigned char b)
  80. {
  81. return (unsigned char)( (int)gfmultby02(gfmultby02(gfmultby02(b))) ^
  82. (int)gfmultby02(gfmultby02(b)) ^
  83. (int)gfmultby02(b) );
  84. }
void AES::MixColumns()
{
unsigned char temp[4*4];
int r,c;
for (r = 0; r < 4; r++) // copy State into temp[]
{
for (c = 0; c < 4; c++)
{
temp[4*r+c] = State[r][c];
}
}
for (c = 0; c < 4; c++)
{
State[0][c] = (unsigned char) ( (int)gfmultby02(temp[0+c]) ^ (int)gfmultby03(temp[4*1+c]) ^
(int)gfmultby01(temp[4*2+c]) ^ (int)gfmultby01(temp[4*3+c]) );
State[1][c] = (unsigned char) ( (int)gfmultby01(temp[0+c]) ^ (int)gfmultby02(temp[4*1+c]) ^
(int)gfmultby03(temp[4*2+c]) ^ (int)gfmultby01(temp[4*3+c]) );
State[2][c] = (unsigned char) ( (int)gfmultby01(temp[0+c]) ^ (int)gfmultby01(temp[4*1+c]) ^
(int)gfmultby02(temp[4*2+c]) ^ (int)gfmultby03(temp[4*3+c]) );
State[3][c] = (unsigned char) ( (int)gfmultby03(temp[0+c]) ^ (int)gfmultby01(temp[4*1+c]) ^
(int)gfmultby01(temp[4*2+c]) ^ (int)gfmultby02(temp[4*3+c]) );
}
} // MixColumns void AES::InvMixColumns()
{
unsigned char temp[4*4];
int r,c;
for (r = 0; r < 4; r++) // copy State into temp[]
{
for (c = 0; c < 4; c++)
{
temp[4*r+c] = State[r][c];
}
}
for (c = 0; c < 4; c++)
{
State[0][c] = (unsigned char) ( (int)gfmultby0e(temp[c]) ^ (int)gfmultby0b(temp[4+c]) ^
(int)gfmultby0d(temp[4*2+c]) ^ (int)gfmultby09(temp[4*3+c]) );
State[1][c] = (unsigned char) ( (int)gfmultby09(temp[c]) ^ (int)gfmultby0e(temp[4+c]) ^
(int)gfmultby0b(temp[4*2+c]) ^ (int)gfmultby0d(temp[4*3+c]) );
State[2][c] = (unsigned char) ( (int)gfmultby0d(temp[c]) ^ (int)gfmultby09(temp[4+c]) ^
(int)gfmultby0e(temp[4*2+c]) ^ (int)gfmultby0b(temp[4*3+c]) );
State[3][c] = (unsigned char) ( (int)gfmultby0b(temp[c]) ^ (int)gfmultby0d(temp[4+c]) ^
(int)gfmultby09(temp[4*2+c]) ^ (int)gfmultby0e(temp[4*3+c]) );
}
} // InvMixColumns unsigned char AES::gfmultby01(unsigned char b)
{
return b;
} unsigned char AES::gfmultby02(unsigned char b)
{
if (b < 0x80)
return (unsigned char)(int)(b <<1);
else
return (unsigned char)( (int)(b << 1) ^ (int)(0x1b) );
} unsigned char AES::gfmultby03(unsigned char b)
{
return (unsigned char) ( (int)gfmultby02(b) ^ (int)b );
} unsigned char AES::gfmultby09(unsigned char b)
{
return (unsigned char)( (int)gfmultby02(gfmultby02(gfmultby02(b))) ^
(int)b );
} unsigned char AES::gfmultby0b(unsigned char b)
{
return (unsigned char)( (int)gfmultby02(gfmultby02(gfmultby02(b))) ^
(int)gfmultby02(b) ^
(int)b );
} unsigned char AES::gfmultby0d(unsigned char b)
{
return (unsigned char)( (int)gfmultby02(gfmultby02(gfmultby02(b))) ^
(int)gfmultby02(gfmultby02(b)) ^
(int)(b) );
} unsigned char AES::gfmultby0e(unsigned char b)
{
return (unsigned char)( (int)gfmultby02(gfmultby02(gfmultby02(b))) ^
(int)gfmultby02(gfmultby02(b)) ^
(int)gfmultby02(b) );
}

7 AES加密 加密时,首先进行密钥扩展。密钥扩展的结果是将初始密钥按照一定的移位和置换操作扩展为11组128位的密钥,存储在一个W[44][4]的数组里。将输入的明文,按列顺序组合成4×4的矩阵,直接与第0组密钥W[0,3](即基密钥Key)进行异或,作为轮加密的输入。然后,循环10次进行字节替代(Substitute Bytes)、行位移(Shift Rows)、列混淆(Mix Columns)、轮密钥加运算(Add Round Key)。最后一轮运算不进行列混淆变换。最后,输出128位的密文比特流。

  1. void AES::Cipher(unsigned char* input, unsigned char* output)  // encipher 16-bit input
  2. {
  3. // state = input
  4. memset(&State[0][0],0,16);
  5. int i;
  6. for (i = 0; i < (4 * Nb); i++)//
  7. {
  8. State[i % 4][ i / 4] = input[i];
  9. }
  10. AddRoundKey(0);
  11. for (int round = 1; round <= (Nr - 1); round++)  // main round loop
  12. {
  13. SubBytes();
  14. ShiftRows();
  15. MixColumns();
  16. AddRoundKey(round);
  17. }  // main round loop
  18. SubBytes();
  19. ShiftRows();
  20. AddRoundKey(Nr);
  21. // output = state
  22. for (i = 0; i < (4 * Nb); i++)
  23. {
  24. output[i] =  State[i % 4][ i / 4];
  25. }
  26. }  // Cipher()
void AES::Cipher(unsigned char* input, unsigned char* output)  // encipher 16-bit input
{
// state = input
memset(&State[0][0],0,16);
int i;
for (i = 0; i < (4 * Nb); i++)//
{
State[i % 4][ i / 4] = input[i];
}
AddRoundKey(0);
for (int round = 1; round <= (Nr - 1); round++) // main round loop
{
SubBytes();
ShiftRows();
MixColumns();
AddRoundKey(round);
} // main round loop
SubBytes();
ShiftRows();
AddRoundKey(Nr);
// output = state
for (i = 0; i < (4 * Nb); i++)
{
output[i] = State[i % 4][ i / 4];
}
} // Cipher()

8 AES解密 解密时,进行加密过程逆运算,除轮密钥加和密钥扩展不变外,其余都需要进行相应的逆变换。当基密钥正确,并且采用正确的解密算法,点击解密,对文件进行正确解密。

  1. void AES::InvCipher(unsigned char * input, unsigned char * output)  // decipher 16-bit input
  2. {
  3. // state = input
  4. int i;
  5. memset(&State[0][0],0,16);
  6. for (i = 0; i < (4 * Nb); i++)
  7. {
  8. State[i % 4][ i / 4] = input[i];
  9. }
  10. AddRoundKey(Nr);
  11. for (int round = Nr-1; round >= 1; round--)  // main round loop
  12. {
  13. InvShiftRows();
  14. InvSubBytes();
  15. AddRoundKey(round);
  16. InvMixColumns();
  17. }  // end main round loop for InvCipher
  18. InvShiftRows();
  19. InvSubBytes();
  20. AddRoundKey(0);
  21. // output = state
  22. for (i = 0; i < (4 * Nb); i++)
  23. {
  24. output[i] =  State[i % 4][ i / 4];
  25. }
  26. }  // InvCipher()
void AES::InvCipher(unsigned char * input, unsigned char * output)  // decipher 16-bit input
{
// state = input
int i;
memset(&State[0][0],0,16);
for (i = 0; i < (4 * Nb); i++)
{
State[i % 4][ i / 4] = input[i];
}
AddRoundKey(Nr);
for (int round = Nr-1; round >= 1; round--) // main round loop
{
InvShiftRows();
InvSubBytes();
AddRoundKey(round);
InvMixColumns();
} // end main round loop for InvCipher
InvShiftRows();
InvSubBytes();
AddRoundKey(0);
// output = state
for (i = 0; i < (4 * Nb); i++)
{
output[i] = State[i % 4][ i / 4];
}
} // InvCipher()

【算法举例】

  1. void print(const char *key, unsigned char* value)
  2. {
  3. int i;
  4. printf("%s:\n", key);
  5. for(i=0; i<16; i++)
  6. {
  7. printf("%s%#x ", value[i]>15 ? "" : "0", value[i]);
  8. }
  9. printf("\n");
  10. }
  11. unsigned char input[] =
  12. {
  13. 0x32, 0x43, 0xf6, 0xa8,
  14. 0x88, 0x5a, 0x30, 0x8d,
  15. 0x31, 0x31, 0x98, 0xa2,
  16. 0xe0, 0x37, 0x07, 0x34
  17. };
  18. unsigned char output[16] = { 0 };
  19. unsigned char key[] =
  20. {
  21. 0x2b, 0x7e, 0x15, 0x16,
  22. 0x28, 0xae, 0xd2, 0xa6,
  23. 0xab, 0xf7, 0x15, 0x88,
  24. 0x09, 0xcf, 0x4f, 0x3c
  25. };
  26. AES aes(Bits128,key);
  27. //-1-
  28. print("Input", input);
  29. aes.Cipher(input,output);
  30. print("After Cipher", output);
  31. aes.InvCipher(output,input);
  32. print("After InvCipher", input);
void print(const char *key, unsigned char* value)
{
int i;
printf("%s:\n", key);
for(i=0; i<16; i++)
{
printf("%s%#x ", value[i]>15 ? "" : "0", value[i]);
}
printf("\n");
} unsigned char input[] =
{
0x32, 0x43, 0xf6, 0xa8,
0x88, 0x5a, 0x30, 0x8d,
0x31, 0x31, 0x98, 0xa2,
0xe0, 0x37, 0x07, 0x34
};
unsigned char output[16] = { 0 };
unsigned char key[] =
{
0x2b, 0x7e, 0x15, 0x16,
0x28, 0xae, 0xd2, 0xa6,
0xab, 0xf7, 0x15, 0x88,
0x09, 0xcf, 0x4f, 0x3c
}; AES aes(Bits128,key); //-1-
print("Input", input);
aes.Cipher(input,output);
print("After Cipher", output);
aes.InvCipher(output,input);
print("After InvCipher", input);

【文件加密】

本文仅分析AES算法本身,不就AES文件加密进行分析。源码中的文件加密功能仅供测试用。实际使用时,文件加密可使用多线程,要考虑加锁、明文字节填充等问题。

【源码下载】

http://download.csdn.net/detail/tandesir/4613524

【参考文献】

1 http://zh.wikipedia.org/wiki/%E9%AB%98%E7%BA%A7%E5%8A%A0%E5%AF%86%E6%A0%87%E5%87%86

AES加解密算法Qt实现的更多相关文章

  1. AES加解密算法在Android中的应用及Android4.2以上版本调用问题

     from://http://blog.csdn.net/xinzheng_wang/article/details/9159969 AES加解密算法在Android中的应用及Android4.2以上 ...

  2. DES加解密算法Qt实现

      算法解密qt加密table64bit [声明] (1) 本文源码 大部分源码来自:DES算法代码.在此基础上,利用Qt编程进行了改写,实现了DES加解密算法,并添加了文件加解密功能.在此对署名为b ...

  3. AES加解密算法

    直接粘代码,该类是基于微信公众号消息加密解密所提供的PHP DEMO改造而来,目前使用于彬彬大学APP接口token校验中. php的mcrypt 扩展已经过时了大约10年,并且用起来很复杂.因此它被 ...

  4. 最强加密算法?AES加解密算法Matlab和Verilog实现

    目录 背景 AES加密的几种模式 基本运算 AES加密原理 Matlab实现 Verilog实现 Testbench 此本文首发于公众号[两猿社],重点讲述了AES加密算法的加密模式和原理,用MATL ...

  5. 【加解密专辑】对接触到的PGP、RSA、AES加解密算法整理

    先贴代码,有空再整理思路 PGP加密 using System; using System.IO; using Org.BouncyCastle.Bcpg; using Org.BouncyCastl ...

  6. Aes 加解密算法

    public class AesHelper    {        /// <summary>        /// 生成128位的随机AES秘钥        /// </sum ...

  7. PHP完整的AES加解密算法使用及例子(256位)

    依赖PHP自身的mcrypt扩展 <?php class aes { // CRYPTO_CIPHER_BLOCK_SIZE 32 private $_secret_key = 'default ...

  8. C#与java中的AES加解密互解算法

    一.C#版AES加解密算法 public class AESCode { public string Key { get; set; } public string Encrypt(string va ...

  9. RSA,AES加解密算法的实现

    目录 Python实现RSA公钥加密算法 RSA公钥加密算法原理 RSA算法的Python实现 AES加解密算法实现 AES加解密算法原理 AES加解密算法Python实现 参考文献 Python实现 ...

随机推荐

  1. TCP协议三次握手与四次挥手通俗解析

    TCP/IP协议三次握手与四次握手流程解析 一.TCP报文格式 TCP/IP协议的详细信息参看<TCP/IP协议详解>三卷本.下面是TCP报文格式图: 图1 TCP报文格式 上图中有几个字 ...

  2. [读书笔记] 二、条件注解@Conditional,组合注解,元注解

    一.条件注解@Conditional,组合注解,元注解 1. @Conditional:满足特定条件创建一个Bean,SpringBoot就是利用这个特性进行自动配置的. 例子: 首先,两个Condi ...

  3. WP开发图片保存到独立存储并从独立存储中读取

    需要添加引用命名空间 using System.IO; using System.IO.IsolatedStorage; 1.将图片保存到独立存储空间 using (IsolatedStorageFi ...

  4. MariaDB体验1----数据库安装

    之前一直都是使用的微软Sql Server数据库,现在在学习数据分析,要用到mysql.刚好公司在进行云架构升级,数据库选型为MariaDB,就顺势安装体验了一把MariaDB.这里记录一下学习过程. ...

  5. 小而美的 React Form 组件

    背景 之间在一篇介绍过 Table 组件< React 实现一个漂亮的 Table > 的文章中讲到过,在企业级后台产品中,用的最多且复杂的组件主要包括 Table.Form.Chart, ...

  6. IOS学习【xcode 7新特性url链接】

    由于xcode7的更新,在访问http链接的时候会输出错误信息 The resource could not be loaded because the App Transport Security ...

  7. 移动端适配方案以及rem和px之间的转换

    背景 开发移动端H5页面 面对不同分辨率的手机 面对不同屏幕尺寸的手机 视觉稿 在前端开发之前,视觉MM会给我们一个psd文件,称之为视觉稿. 对于移动端开发而言,为了做到页面高清的效果,视觉稿的规范 ...

  8. vmware 遇到 “无法打开内核设备 \\.\Global\vmx86” 解决

    问题描述:vmware没有正常关闭,再次打开使用时蓝屏,在安全模式下再次打开不会蓝屏,但提示"无法打开内核设备 \.\Global\vmx86: 系统找不到指定的文件,你想要安装VMware ...

  9. 团队作业8----第二次项目冲刺(Beta阶段) 第五天

    BETA阶段冲刺第五天 1.小会议ing 2.每个人的工作 (1)昨天已完成的工作 文件读取的方式采用按钮的: (2) 今天计划完成的工作 (3) 工作中遇到的困难: 林莹:源代码的部分我们已经初步完 ...

  10. [BT5]信息收集1-1 Dnsenum

    0.工具介绍 The purpose of Dnsenum is to gather as much information as possible about a domain. The progr ...