【声明】

(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. uva11991 Easy Problem from Rujia Liu?

    Though Rujia Liu usually sets hard problems for contests (for example, regional contests like Xi'an ...

  2. Javascript中的浅拷贝和深拷贝

    很多开发语言中都有浅拷贝和深拷贝的说法,这里简单区分一下它们在Javascript中的区别,以及jQuery中深拷贝的实现. 在谈浅拷贝和深拷贝之前,先要屡清楚Javascript中的按值访问和按引用 ...

  3. jQuery菜单示例(全选,反选,取消)

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. appium python api收集

    1.contexts contexts(self): Returns the contexts within the current session. 返回当前会话中的上下文,使用后可以识别H5页面的 ...

  5. python线程与进程手记

    ------------------------------线程---------------------------#线程应用的第一种方式:thread模块是比较底层的模块#import threa ...

  6. Spring Cloud官方文档中文版-服务发现:Eureka服务端

    官方文档地址为:http://cloud.spring.io/spring-cloud-static/Dalston.SR3/#spring-cloud-eureka-server 文中例子我做了一些 ...

  7. matlab-常用函数(2)

    isempty(A) 功能解释 isempty()用来判断 一个矩阵是否为空矩阵,其用法相当于C语言中的"a==NULL". 当参数为空矩阵时,该函数返回逻辑值"1&qu ...

  8. Day-9: 面对对象高级编程

    数据封装.继承和多态只是面向对象编程中最基础的3个概念. 下面整理面向对象高级编程的更为强大的技巧. 使用__slots__:Python属于动态语言,可以允许已创建好的类动态地绑定任何属性和方法.但 ...

  9. Oracle数据库中直方图对执行计划的影响

    在Oracle数据库中,CBO会默认目标列的数据在其最小值low_value和最大值high_value之间均匀分布,并按照均匀分布原则,来计算目标列 施加查询条件后的可选择率以及结果集的cardin ...

  10. JAVA基础第十组(5道题)

    46.[程序46] 题目:两个字符串连接程序 package com.niit.homework1; import java.util.Scanner; /** * @author: Annie * ...