AES加密是对称的,对称加密是啥?公钥和密钥是一个,一个密钥可以用它来加密数据和解密数据,安全性低于非对称加密。
非对称加密是啥?甲方生成一对密钥并将公钥公开,需要向甲方发送信息的其他角色(乙方)使用该密钥(甲方的公钥)对机密信息进行加密后再发送给甲方:甲方再用自己的私钥对加密后的信息进行解密。甲方想要回复乙方时正好相反,使用乙方的公钥对数据进行加密,同理,乙方使用自己的私钥来进行解密。

0x01 前言

AES加密算法根据密钥的长度不同分为128位,192位和256位,接下来分析128位的对称AES算法实现。

0x02 AES算法流程

AES加密算法主要步骤有:
字节替代:ByteSub
行移位:ShiftRow
列混淆:MixColumns
轮密钥加:AddRoundKey

0x03 步骤详解及实现代码

我们用
明文:0123456789abcdeffedcba9876543210
密钥:0f1571c947d9e8590cb7add6af7f6798
密文:ff0b844a0853bf7c6934ab4364148fb9
来演示
将待加密/解密的输入转换成4x4矩阵,记为state

P.S.以下所有图片中的数据采用另一套密文和密钥
(为啥不用上面的那一套,awsl,本人好懒,最终的模板代码用的上面的数据)

1.字节替代

字节替代作用是将state矩阵的数据替换为S盒中的数据,state矩阵中的每个元素的第一位作为S盒的行索引,第二位作为S盒的列索引。将获取到的S盒中的值赋给state矩阵。
例如:state中某一元素为ab,则用S盒中第a行第b列的数据0x62替换0xab。
S盒根据密文生成的,不固定。

字节替代后变为:

S盒数据:

逆字节替代就是用逆S盒来替换state矩阵中的数据,替换方法和字节替代一致。

逆S盒数据:

代码:

void subBytes(int a[4][4], int encode){// encode 为1 代表字节替代,为0代表逆向字节替代for (int i = 0; i < 4; ++i) {for (int j = 0; j < 4; ++j) {int temp = a[i][j];int row = temp / 16;int column = temp % 16;if (encode)a[i][j] = S_BOX[row][column];elsea[i][j] = INVERSE_S_BOX[row][column];}}
}

2.行移位

行移位操作是将矩阵的第k行循环左移k-1位

经过行移位后变成

逆向行移位就是将矩阵的第k行循环右移k-1位。
代码:

void shiftRows(int a[4][4], int encode){//encode 为1代表行移位,为0代表逆向行移位for (int i = 0; i < 4; ++i) {for (int j = 0; j < i; ++j) {if (encode) {int temp = a[i][0];a[i][0] = a[i][1];a[i][1] = a[i][2];a[i][2] = a[i][3];a[i][3] = temp;} else{int temp = a[i][3];a[i][3] = a[i][2];a[i][2] = a[i][1];a[i][1] = a[i][0];a[i][0] = temp;}}}
}

3.列混肴

首先介绍aes算法中的加法和乘法:

对于任意正整数c,都有

再结合aes中的加法规则,便可得出任意两个数相乘的结果。
例如:

列混淆变换是用一个常数矩阵去乘以矩阵state来得到新的state矩阵
阵:

逆向列混淆使用另一个常数矩阵去乘以矩阵state来得到新的state矩阵:

代码:

void mixColumns(int a[4][4], int encode){//encode 为1代表列混淆,为0代表逆向列混淆for (int i = 0; i < 4; ++i) {int temp0 = a[0][i];int temp1 = a[1][i];int temp2 = a[2][i];int temp3 = a[3][i];if (encode) {a[0][i] = aes_multiple(temp0, 2) ^ aes_multiple(temp1, 3) ^ temp2 ^ temp3;a[1][i] = temp0 ^ (aes_multiple(temp1, 2)) ^ (temp2 ^ aes_multiple(temp2, 2)) ^ temp3;a[2][i] = temp0 ^ temp1 ^ (aes_multiple(temp2, 2)) ^ (temp3 ^ aes_multiple(temp3, 2));a[3][i] = temp0 ^ (aes_multiple(temp0, 2)) ^ temp1 ^ temp2 ^ aes_multiple(temp3, 2);}else{a[0][i] = aes_multiple(temp0, 14) ^ aes_multiple(temp1, 11) ^ aes_multiple(temp2, 13) ^ aes_multiple(temp3, 9);a[1][i] = aes_multiple(temp0, 9) ^ aes_multiple(temp1, 14) ^ aes_multiple(temp2, 11) ^ aes_multiple(temp3, 13);a[2][i] = aes_multiple(temp0, 13) ^ aes_multiple(temp1, 9) ^ aes_multiple(temp2, 14) ^ aes_multiple(temp3, 11);a[3][i] = aes_multiple(temp0, 11) ^ aes_multiple(temp1, 13) ^ aes_multiple(temp2, 9) ^ aes_multiple(temp3, 14);}}
}//AES乘法计算
int aes_multiple(int a, int le){int thr = le & 0x8;int sec = le & 0x4;int fir = le & 0x2;int fir_mod = le % 2;int result = 0;if (thr){int b = a;for (int i = 1; i <=3 ; ++i) {b = b<<1;if (b >= 256)b = b ^ 0x11b;}b = b % 256;result = result ^ b;}if (sec){int b = a;for (int i = 1; i <=2 ; ++i) {b = b<<1;if (b >= 256)b = b ^ 0x11b;}b = b % 256;result = result ^ b;}if (fir){int b = a << 1;if (b >= 256)b = b ^ 0x11b;b = b % 256;result = result ^ b;}if (fir_mod)result = result ^ a;return  result;
}

4.密钥扩展

密钥扩展将16字节的密钥扩展成11*16字节。设k0k1k2…k15为输入的密钥。密钥扩展流程图如下图:

我们将w[44]存储到w[11][4][4]类型的数组中,密钥扩展代码如下:

void keyExpansion(int key[4][4], int w[11][4][4]){for (int i = 0; i < 4; ++i) {for (int j = 0; j < 4; ++j) {w[0][i][j] = key[j][i];}}for (int i = 1; i < 11; ++i){for (int j = 0; j < 4; ++j) {int temp[4];if (j == 0){temp[0] = w[i-1][3][1];temp[1] = w[i-1][3][2];temp[2] = w[i-1][3][3];temp[3] = w[i-1][3][0];for (int k = 0; k < 4; ++k) {int m = temp[k];int row = m / 16;int column = m % 16;temp[k] = S_BOX[row][column];if (k == 0){temp[k] = temp[k] ^ RC[i-1];}}} else{temp[0] = w[i][j-1][0];temp[1] = w[i][j-1][1];temp[2] = w[i][j-1][2];temp[3] = w[i][j-1][3];}for (int l = 0; l < 4; ++l) {w[i][j][l] = w[i-1][j][l] ^ temp[l];}}}
}

5.轮密钥加

轮密钥加操作是将state矩阵与密钥矩阵相加,即

代码:

void addRoundKey(int a[4][4], int k[4][4]){// 由于用w[11][4][4]表示W[44]导致行列转置,所以在进行异或操作的时候应该是a[i,j] 异或 k[j,i]for (int i = 0; i < 4; ++i) {for (int j = 0; j < 4; ++j) {a[i][j] = a[i][j] ^ k[i][j];}}
}

0x04 总代码

#include <stdio.h>
#include <pbt.h>
#include <ctype.h>void aes(char*, char*, char*, int);
void aes_detail(int[4][4], int[4][4], int);
void subBytes(int [4][4], int);
void shiftRows(int [4][4], int);
void mixColumns(int [4][4], int);
void addRoundKey(int [4][4], int[4][4]);
int aes_multiple(int, int);
void keyExpansion(int key[4][4], int w[11][4][4]);
int c2i(char );/*** S盒*/
static const int S_BOX[16][16] = { 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盒*/
static const int INVERSE_S_BOX[16][16] = { 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 };
int RC[10] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36};
int main(){int method = 0;//1表示加密, 0表示解密//待加密/解密文件存放路径char * source_path = "G:\\aes2.txt";// 加密/解密后文件存放路径char *des_path = "G:\\aes3.txt";// 32位16进制密钥char * password = "0f1571c947d9e8590cb7add6af7f6798";aes(source_path, des_path, password, method);printf("success!!!!!!!!!!");}void aes(char* source_path, char* des_path, char* password, int method){//将密钥转换成4*4数组int p[4][4];for (int m = 0; m < 4; ++m) {for (int i = 0; i < 4; ++i) {int indx = 4 * i + m;p[i][m] = 16 * c2i(password[indx]) + c2i(password[indx + 1]);}}FILE *file = fopen(source_path, "r"); //获取文件的指针fseek(file, 0, SEEK_END); //移动文件的指针到文件结尾int len = ftell(file); //获取文件的长度rewind(file); //将文件指针移动回文件开始// 如果文件长度不是128位(16字节)的整数倍,则补齐int size = len;if (len % 16 != 0) {size = (len / 16 + 1) * 16;}unsigned char content[size];//读取文件内容赋值给contentfread(content, 1, len, file);for (int j = len; j < size; ++j) {content[j] = 0;}fclose(file);//存储结果unsigned char encry[size];//将文件转换成16字节的int型数组加密、解密for (int i = 0; i < size / 16; ++i) {int content_to_int[4][4];for (int j = 0; j < 4; ++j) {for (int k = 0; k < 4; ++k) {content_to_int[j][k] = content[j * 4 + k + 16 * i];}}aes_detail(content_to_int, p, method);for (int j = 0; j < 4; ++j) {for (int k = 0; k < 4; ++k) {encry[j * 4 + k + 16 * i] = content_to_int[j][k];}}}FILE *file1 = fopen(des_path, "w");fwrite(encry, size, 1, file1);fflush(file1);fclose(file1);}void aes_detail(int content[4][4],  int password[4][4], int encode){int p[11][4][4];keyExpansion(password, p);if (encode) {addRoundKey(content, p[0]);for (int i = 1; i <= 10; ++i) {subBytes(content, encode);shiftRows(content, encode);if (i != 10) {mixColumns(content, encode);}addRoundKey(content, p[i]);}}else {addRoundKey(content, p[10]);for (int i = 9; i >= 0; --i) {shiftRows(content, encode);subBytes(content, encode);addRoundKey(content, p[i]);if (i != 0) {mixColumns(content, encode);}}}
}void subBytes(int a[4][4], int encode){// encode 为1 代表字节替代,为0代表逆向字节替代for (int i = 0; i < 4; ++i) {for (int j = 0; j < 4; ++j) {int temp = a[i][j];int row = temp / 16;int column = temp % 16;if (encode)a[i][j] = S_BOX[row][column];elsea[i][j] = INVERSE_S_BOX[row][column];}}
}void shiftRows(int a[4][4], int encode){//encode 为1代表行移位,为0代表逆向行移位for (int i = 0; i < 4; ++i) {for (int j = 0; j < i; ++j) {if (encode) {int temp = a[i][0];a[i][0] = a[i][1];a[i][1] = a[i][2];a[i][2] = a[i][3];a[i][3] = temp;} else{int temp = a[i][3];a[i][3] = a[i][2];a[i][2] = a[i][1];a[i][1] = a[i][0];a[i][0] = temp;}}}
}void mixColumns(int a[4][4], int encode){//encode 为1代表列混淆,为0代表逆向列混淆for (int i = 0; i < 4; ++i) {int temp0 = a[0][i];int temp1 = a[1][i];int temp2 = a[2][i];int temp3 = a[3][i];if (encode) {a[0][i] = aes_multiple(temp0, 2) ^ aes_multiple(temp1, 3) ^ temp2 ^ temp3;a[1][i] = temp0 ^ (aes_multiple(temp1, 2)) ^ (temp2 ^ aes_multiple(temp2, 2)) ^ temp3;a[2][i] = temp0 ^ temp1 ^ (aes_multiple(temp2, 2)) ^ (temp3 ^ aes_multiple(temp3, 2));a[3][i] = temp0 ^ (aes_multiple(temp0, 2)) ^ temp1 ^ temp2 ^ aes_multiple(temp3, 2);}else{a[0][i] = aes_multiple(temp0, 14) ^ aes_multiple(temp1, 11) ^ aes_multiple(temp2, 13) ^ aes_multiple(temp3, 9);a[1][i] = aes_multiple(temp0, 9) ^ aes_multiple(temp1, 14) ^ aes_multiple(temp2, 11) ^ aes_multiple(temp3, 13);a[2][i] = aes_multiple(temp0, 13) ^ aes_multiple(temp1, 9) ^ aes_multiple(temp2, 14) ^ aes_multiple(temp3, 11);a[3][i] = aes_multiple(temp0, 11) ^ aes_multiple(temp1, 13) ^ aes_multiple(temp2, 9) ^ aes_multiple(temp3, 14);}}
}void addRoundKey(int a[4][4], int k[4][4]){// 由于用w[11][4][4]表示W[44]导致行列转置,所以在进行异或操作的时候应该是a[i,j] 异或 k[j,i]for (int i = 0; i < 4; ++i) {for (int j = 0; j < 4; ++j) {a[i][j] = a[i][j] ^ k[j][i];}}
}//AES乘法计算
int aes_multiple(int a, int le){int thr = le & 0x8;int sec = le & 0x4;int fir = le & 0x2;int fir_mod = le % 2;int result = 0;if (thr){int b = a;for (int i = 1; i <=3 ; ++i) {b = b<<1;if (b >= 256)b = b ^ 0x11b;}b = b % 256;result = result ^ b;}if (sec){int b = a;for (int i = 1; i <=2 ; ++i) {b = b<<1;if (b >= 256)b = b ^ 0x11b;}b = b % 256;result = result ^ b;}if (fir){int b = a << 1;if (b >= 256)b = b ^ 0x11b;b = b % 256;result = result ^ b;}if (fir_mod)result = result ^ a;return  result;
}void keyExpansion(int key[4][4], int w[11][4][4]){for (int i = 0; i < 4; ++i) {for (int j = 0; j < 4; ++j) {w[0][i][j] = key[j][i];}}for (int i = 1; i < 11; ++i){for (int j = 0; j < 4; ++j) {int temp[4];if (j == 0){temp[0] = w[i-1][3][1];temp[1] = w[i-1][3][2];temp[2] = w[i-1][3][3];temp[3] = w[i-1][3][0];for (int k = 0; k < 4; ++k) {int m = temp[k];int row = m / 16;int column = m % 16;temp[k] = S_BOX[row][column];if (k == 0){temp[k] = temp[k] ^ RC[i-1];}}} else{temp[0] = w[i][j-1][0];temp[1] = w[i][j-1][1];temp[2] = w[i][j-1][2];temp[3] = w[i][j-1][3];}for (int l = 0; l < 4; ++l) {w[i][j][l] = w[i-1][j][l] ^ temp[l];}}}}//将字符转换为数值
int c2i(char ch) {// 如果是数字,则用数字的ASCII码减去48, 如果ch = '2' ,则 '2' - 48 = 2if(isdigit(ch))return ch - 48;// 如果是字母,但不是A~F,a~f则返回if( ch < 'A' || (ch > 'F' && ch < 'a') || ch > 'z' )return -1;// 如果是大写字母,则用数字的ASCII码减去55, 如果ch = 'A' ,则 'A' - 55 = 10// 如果是小写字母,则用数字的ASCII码减去87, 如果ch = 'a' ,则 'a' - 87 = 10if(isalpha(ch))return isupper(ch) ? ch - 55 : ch - 87;return -1;
}

AES加解密(ECB模式)相关推荐

  1. 3des java ecb_C# And Java 3DES加解密 ECB模式/PKCS7

    c#: /// /// 完整 /// public class TripleDESHelper1 { public static string Encrypt(string aStrString, s ...

  2. SpringBoot+Vue中使用AES进行加解密(加密模式等对照关系)

    场景 若依前后端分离版本地搭建开发环境并运行项目的教程: 若依前后端分离版手把手教你本地搭建环境并运行项目_霸道流氓气质的博客-CSDN博客 在上面搭建起来前后端架构之后,在前后端分别进行AES方式的 ...

  3. iOS-AES加解密各模式(ECB、CBC、CFB、OFB)的实现

    前言 最近和服务器同学对接口进行数据加解密时用到了AES加密.原本以为AES就一种加密形式,对接过程中才学习到AES不同模式.不同填充方式下,结果都不相同.因此去学习了一下AES加密的基本概念.实现原 ...

  4. Python中的AES加解密算法

    AES加密的参数及其条件:这个AES加密的主要坑就在于这些条件,首先AES加密有几个参数 秘钥:加密的时候用秘钥,解密的时候需要同样的秘钥才能解出来 明文:需要加密的内容 模式:aes 加密常用的有E ...

  5. Golang AES 加解密

    文章目录 AES 简介 AES 加解密实现 小结 参考文献 AES 简介 利用 Go 提供的 AES 加解密与 Base64 编解码包,我们可以轻松实现 AES 加解密.实现之前,首先了解一下 AES ...

  6. java aes 工具类_Java中的AES加解密工具类:AESUtils

    本人手写已测试,大家可以参考使用 package com.mirana.frame.utils.encrypt; import com.mirana.frame.constants.SysConsta ...

  7. Java实现aes加解密

    pom文件的依赖 <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 --> <depe ...

  8. linux c openssl aes 加解密

    1.OpenSSL提供了AES加解密算法的API const char *AES_options(void); AES算法状态,是所有支持或者是部分支持. 返回值:"aes(full)&qu ...

  9. 利用openssl进行aes加解密

    之前写过aes加密算法简单说明,本篇用openssl对aes的ecb和cbc模式进行代码编写. 现在拿128位的aes加解密进行说明. 首先强调的是,在openssl提供的函数中,加密和解密每次只能针 ...

最新文章

  1. ASPJPEG缩略图生成函数
  2. linux shell /dev/tcp/${HOST}/${PORT} 简介
  3. WINCE6.0深入理解TOC
  4. 首发:徐亦达教授团队最新发表的两篇机器学习论文
  5. JDK并发包-同步控制
  6. Java 9 中的 GC 调优基础
  7. MCSE2003学习之一
  8. 深入理解JVM垃圾收集机制,下次面试你准备好了吗
  9. Spring基于注解的方式二
  10. 防暴力破解一些安全机制
  11. oracle归档日志百分比,Oracle归档日志处理
  12. mac 更换默认蓝牙适配器_解决Switch最大遗憾,谷粒ROUTE Air蓝牙适配器:简单好用...
  13. kmz转换为dwg_怎么将CAD图纸两种基本格式DWG与DXF进行互转?
  14. canbus是什么意思_CANBUS是什么意思
  15. Module not found: Error: Can‘t resolve ‘core-js/fn/promise‘
  16. 微软云+Servlet实现图片上传接口
  17. curry化 js_JS手动实现柯里化(curry)函数
  18. Something about 博弈~(updating...)
  19. 【LG5055】可持久化文艺平衡树
  20. Flask项目实战——6—(前台用户模型、前台登录注册、图形验证码、手机短信验证码、添加表单验证短信验证码请求)

热门文章

  1. Android音视频开发入门(5)使用LAME编码一个PCM文件,为了跳槽强刷1000道Android真题
  2. Mac鼠标滚轮控制浏览器
  3. 编译器报错The type of the expression must be an array type but it resolved to int.
  4. 熬夜整理,五万字长文总结 C/C++ 知识点
  5. CyberWorld赛博世界是否能成为元宇宙核心力量
  6. 【无标题】输入和输出
  7. 神经网络输入图片大小,神经网络 图像相似度
  8. 山东理工大学ACM平台题答案 2561 九九乘法表
  9. 软通动力入职考试----全套
  10. Scala入门系列(7)-Scala之函数式编程