精华内容
下载资源
问答
  • 2021-01-23 19:31:37

    AES加解密算法全过程代码实现(C++)

    利用C++编程实现了AES的加解密过程。

    关于列混合计算不清楚的可以看上一篇博客
    DES加解密C++实现可以点这里

    主要针对128bit的明文和密钥给出实现,其他情况需要改一下Nk,Nb,Nr的值和某些地方的数组维度。

    byte GFMultiplyByte(byte L, byte R)这个函数是计算多项式模乘的结果(列混淆中的那一步)。

    其他想自己动手编编的可以复制一下这里的S盒和逆S盒或者其他常量。

    参考书籍是《密码编码与信息安全:C++实践》。

    #include <iostream>
    #include <cstdlib>
    #include <stdio.h>
    using namespace std;
    typedef unsigned char byte;
    struct word
    {
    	byte wordKey[4];
    };
    
    class AES
    {
    public:
    	AES(){
    		initRcon();
    	};
    	// ~AES();
    	void setCipherKey(byte key[]);
    	void setPlainText(byte plain[]);
    
    	//
    	void keyExpansion(byte key[], word w[]);
    	word rotWord(word w);
    	word subWord(word w);
    	word wordXOR(word w1, word w2);
    	//functions in encryption and decryption
    	void encryption();
    	void processEncryption();
    	void addRoundKey(word in[], int round);
    	void subByte(word in[]);
    	void shiftRows(word in[]);
    	void mixColumn(word in[]);
    	byte GFMultiplyByte(byte L, byte R);
    	void decryption();
    	void processDecryption();
    	void invShiftRows(word in[]);
    	void invSubByte(word in[]);
    	void invMixColumn(word in[]);
    	void initRcon();
    	void showWord(word w[], int len);
    	void showMesage();
    private:
    	byte cipherKey[16];
    	word plainText[4];
    	word cipherText[4];
    	word deCipherText[4];
    	static const int Nb=4, Nk=4, Nr=10;
    	word Rcon[11];
    	word wordKey[44];
    	static const byte SBox[16][16];
    	static const byte invSBox[16][16];
    	static const byte mixColumnMatrix[4][4];
    	static const byte invmixColumnMatrix[4][4];
    };
    
    void AES::showWord(word w[], int len){
    	int i,j;
    	for(i=0; i<len; i++){
    		for(j=0; j<4; j++){
    			printf("%x ", w[i].wordKey[j]);
    		}
    	}
    	cout<<endl;
    }
    
    void AES::showMesage(){
    	cout<<"plainText:"<<endl;
    	showWord(plainText, 4);
    	cout<<"wordKey:"<<endl;
    	showWord(wordKey, Nb*(Nr+1));
    	cout<<"cipherText:"<<endl;
    	showWord(cipherText, 4);
    	cout<<"deCipherText:"<<endl;
    	showWord(deCipherText, 4);
    }
    // initialize the plainText--trans plaintext from vector to state_matrix
    void AES::setPlainText(byte plain[]){
    	int i;
    	for(i=0; i<16; i++){
    		plainText[i/4].wordKey[i%4] = plain[i];
    	}
    }
    
    //initialize the key--from vector to state_matrix
    void AES::setCipherKey(byte key[]){
    	int i;
    	for(i=0; i<16; i++){
    		cipherKey[i] = key[i];
    	}
    	keyExpansion(cipherKey, wordKey);
    }
    
    //initialize the Rcon
    void AES::initRcon(){
    	int i,j;
    	for(i=0; i<4; i++)
    		for(j=0; j<4; j++){
    			Rcon[i].wordKey[j] = 0x0;
    		}
    	Rcon[1].wordKey[0] = 0x01;
    	Rcon[2].wordKey[0] = 0x02;
    	Rcon[3].wordKey[0] = 0x04;
    	Rcon[4].wordKey[0] = 0x08;
    	Rcon[5].wordKey[0] = 0x10;
    	Rcon[6].wordKey[0] = 0x20;
    	Rcon[7].wordKey[0] = 0x40;
    	Rcon[8].wordKey[0] = 0x80;
    	Rcon[9].wordKey[0] = 0x1b;
    	Rcon[10].wordKey[0] = 0x36;
    }
    
    //initialize the const of mixColumn and invMixColumn
    const byte AES::mixColumnMatrix[4][4] = {
    	{0x02, 0x03, 0x01, 0x01},
    	{0x01, 0x02, 0x03, 0x01},
    	{0x01, 0x01, 0x02, 0x03},
    	{0x03, 0x01, 0x01, 0x02}
    };
    const byte AES::invmixColumnMatrix[4][4] = {
    	{0x0e, 0x0b, 0x0d, 0x09},
    	{0x09, 0x0e, 0x0b, 0x0d},
    	{0x0d, 0x09, 0x0e, 0x0b},
    	{0x0b, 0x0d, 0x09, 0x0e}
    };
    
    //initialize SBox
    const byte AES::SBox[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}
    };
    const byte AES::invSBox[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
    };
    
    //keyExpansion-get the round key
    void AES::keyExpansion(byte key[], word w[]){
    	int i=0;
    	int j,k;
    	word temp;
    	while(i < Nk){
    		for(j=0; j<4; j++){
    			w[j].wordKey[i] = key[j+4*i];
    		}
    		i++;
    	}
    	i = Nk;
    	while(i < Nb*(Nr+1)){
    		temp = w[i-1];
    		if((i%Nk) == 0){
    			temp = rotWord(temp);
    			temp = subWord(temp);
    			temp = wordXOR(temp, Rcon[i / Nk]);
    		}
    		else if(Nk > 6 && (i%Nk) == 4){
    			temp = subWord(temp);
    		}
    		w[i] = wordXOR(w[i - Nk], temp);
    		i++;
    	}
    }
    
    // some sector in keyExpansion
    word AES::rotWord(word w){
    	int i;
    	word temp;
    	for(i=0; i<4; i++){
    		temp.wordKey[(i+3) % 4] = w.wordKey[i];
    	}
    	return temp;
    }
    
    word AES::subWord(word w){
    	int i;
    	byte L, R;
    	for(i=0; i<4; i++){
    		L = w.wordKey[i] >> 4;
    		R = w.wordKey[i] & 0x0f;
    		w.wordKey[i] = SBox[L][R];
    	}
    	return w;
    }
    
    word AES::wordXOR(word w1, word w2){
    	int i;
    	word temp;
    	for(i=0; i<4; i++){
    		temp.wordKey[i] = w1.wordKey[i] ^ w2.wordKey[i];
    	}
    	return temp;
    }
    
    //encryption
    void AES::encryption(){
    	int i, j ,k;
    	for(i=0; i<4; i++){
    		for(j=0; j<4; j++){
    			cipherText[i].wordKey[j] = plainText[i].wordKey[j];
    		}
    	}
    	// round function
    	addRoundKey(cipherText, 0);
    	for(i=1; i<10; i++){
    		subByte(cipherText);
    		shiftRows(cipherText);
    		mixColumn(cipherText);
    		addRoundKey(cipherText, i);
    	}
    	subByte(cipherText);
    	shiftRows(cipherText);
    	addRoundKey(cipherText, 10);
    }
    
    void AES::subByte(word in[]){
    	int i,j;
    	byte L, R;
    	for(i=0; i<4; i++){
    		for(j=0; j<4; j++){
    			L = in[i].wordKey[j] >> 4;
    			R = in[i].wordKey[j] & 0x0f;
    			in[i].wordKey[j] = SBox[L][R];
    		}
    	}
    }
    
    void AES::shiftRows(word in[]){
    	int i,j;
    	word temp[4];
    	for(i=0; i<4; i++){
    		for(j=0; j<4; j++){
    			temp[i].wordKey[j] = in[(i+j)%4].wordKey[j];
    		}
    	}
    	for(i=0; i<4; i++){
    		for(j=0; j<4; j++){
    			in[i].wordKey[j] = temp[i].wordKey[j];
    		}
    	}
    }
    
    void AES::mixColumn(word in[]){
    	word result[4];
    	int i, j, k;
    	for(i=0; i<4; i++){
    		for(j=0; j<4; j++){
    			result[i].wordKey[j] = GFMultiplyByte(mixColumnMatrix[j][0], in[i].wordKey[0]);
    			for(k=1; k<4; k++){
    				result[i].wordKey[j] ^= GFMultiplyByte(mixColumnMatrix[j][k], in[i].wordKey[k]);
    			}
    		}
    	}
    	for(i=0; i<4; i++){
    		for(j=0; j<4; j++){
    			in[i].wordKey[j] = result[i].wordKey[j];
    		}
    	}
    }
    
    //forexample: 0xaf * 0x25
    byte AES::GFMultiplyByte(byte L, byte R){
    	byte temp[8];
    	byte result = 0x00;
    	temp[0] = L;
    	int i;
        // temp[0] = L, temp[1] = L*x(modm(x)), temp[2] = L*x^2(mod(m(x))), temp[3] = L*x^3(mod(m(x)))...
    	//先计算,再存起来,后面根据R的实际情况选用需要的
    	for(i=1; i<8; i++){
    		if(temp[i-1] >= 0x80){
    			temp[i] = (temp[i-1] << 1) ^ 0x1b;
    		}else{
    			temp[i] = temp[i-1] << 1;
    		}
    	}
    	for(i=0; i<8; i++){
    		if(int((R >> i) & 0x01) == 1){
    			result ^= temp[i];
    		}
    	}
    	return result;
    }
    
    void AES::addRoundKey(word in[], int round){
    	int i, j;
    	for(i=0; i<4; i++){
    		for(j=0; j<4; j++){
    			in[i].wordKey[j] ^= wordKey[i+4*round].wordKey[j];
    		}
    	}
    }
    
    //decryption
    void AES::decryption(){
    	int i, j, k;
    	for(i=0; i<4; i++){
    		for(j=0; j<4; j++){
    			deCipherText[i].wordKey[j] = cipherText[i].wordKey[j];
    		}
    	}
    	addRoundKey(deCipherText, 10);
    	for(i=9; i>0; i--){
    		invShiftRows(deCipherText);
    		invSubByte(deCipherText);
    		addRoundKey(deCipherText, i);
    		invMixColumn(deCipherText);
    	}
    	invShiftRows(deCipherText);
    	invSubByte(deCipherText);
    	addRoundKey(deCipherText, 0);
    }
    
    void AES::invShiftRows(word in[]){
    	int i,j;
    	word temp[4];
    	for(i=0; i<4; i++){
    		for(j=0; j<4; j++){
    			temp[i].wordKey[j] = in[(i-j+4)%4].wordKey[j];
    		}
    	}
    	for(i=0; i<4; i++){
    		for(j=0; j<4; j++){
    			in[i].wordKey[j] = temp[i].wordKey[j];
    		}
    	}
    }
    
    void AES::invSubByte(word in[]){
    	int i,j;
    	byte L, R;
    	for(i=0; i<4; i++){
    		for(j=0; j<4; j++){
    			L = in[i].wordKey[j] >> 4;
    			R = in[i].wordKey[j] & 0x0f;
    			in[i].wordKey[j] = invSBox[L][R];
    		}
    	}
    }
    
    void AES::invMixColumn(word in[]){
    	word result[4];
    	int i, j, k;
    	for(i=0; i<4; i++){
    		for(j=0; j<4; j++){
    			result[i].wordKey[j] = GFMultiplyByte(invmixColumnMatrix[j][0], in[i].wordKey[0]);
    			for(k=1; k<4; k++){
    				result[i].wordKey[j] ^= GFMultiplyByte(invmixColumnMatrix[j][k], in[i].wordKey[k]);
    			}
    		}
    	}
    	for(i=0; i<4; i++){
    		for(j=0; j<4; j++){
    			in[i].wordKey[j] = result[i].wordKey[j];
    		}
    	}
    }
    
    int main(int argc, char const *argv[])
    {
    	int i;
        //设置明文和密钥
    	byte plain[16], key[16];
    	for(i=0; i<16; i++){
    		plain[i] = byte(i);
    		key[i] = 0x01;
    	}
    	AES aes;
    	aes.setPlainText(plain);
    	aes.setCipherKey(key);
    	aes.encryption();
    	aes.decryption();
    	aes.showMesage();
    	return 0;
    }
    

    [1] 王静文, 吴晓艺. 密码编码与信息安全:C++实践[M]. 清华大学出版社, 2015.

    更多相关内容
  • AES算法代码

    2017-03-30 15:36:05
    AES算法代码
  • AES加密算法,AES的全称是Advanced Encryption Standard,意思是高级加密标准。它的出现主要是为了取代DES加密算法的,因为我们都...然而AES只要求分组大小为128位,因此只有分组长度为128Bit的Rijndael才称为AES算法
  • AES加密算法代码

    2017-11-16 10:40:11
    AES加密算法FPGA实现代码,例程中有详细模块设计,及每一步流程
  • C++自己实现AES算法

    2021-01-20 03:43:25
    在移动端需要安全算法时,直接使用开源库可能不合适(开源库都比较大,也可以自己抽取需要的代码),本Demo是根据AES的原理来实现算法,采用ECB/PKCS5Padding,实现短小精悍!!  注意:本算法在生成加密key时,使用...
  • AES算法Java实现

    2019-03-26 11:06:21
    AES算法Java实现 有简单界面 使用彭长根老师的现代密码学趣味之旅
  • AES算法实现、代码

    2022-05-06 11:13:34
    AES算法实现详细过程以及部分代码帮助理解

    AES简介

    1、高级加密标准(AES,Advanced Encryption Standard)作为传统对称加密标准DES的替代者,美国国家标准与技术研究所(NIST)于1997年提出征集该算法的公告。
    2、1999年3月22日,NIST从15个候选算法中选出 5个算法进入下一轮。在2000年10月2日,以
    安全性、性能、大小、实现特点等标准而最
    终选定由比利时人的开发的Rijndael算法,
    并于2001年正式发布AES标准。

    流程图

    在这里插入图片描述

    AES的基本结构(准备阶段)

    • 典型的SPN(代换–置换网络)结构
    • AES又是分组密码,具体过程:将明文分为长度相等的组 (长度固定为128位,即每组16字节),每组逐次加密直到加密完整个明文。
    • 密钥长度位下列三种:
      在这里插入图片描述
    • AES的处理单位是字节,128位的输入明文分组P和输入密钥K都被分成16个字节,分别记为:

    P=P0P1…P15
    K=K0K1…K15

    1. 明文分组用以字节为单位的正方形矩阵描述,称为状态矩阵。(规则:矩阵中字节的排列为从上到下、从左到右依次排 列,矩阵的每一列被称为1个32比特字
      在这里插入图片描述

    整体流程

    在这里插入图片描述

    密钥扩充(加密前奏)

    将密钥扩充,需要得到四十个新列,分组得到轮密钥。
    在这里插入图片描述
    CASE1:当W[i]中i为4的整数倍时,需要用T函数进行变换W[i-1],然后用W[i-1]与W[i-4]进行异或,最后得出W[i]
    (Ps:T函数由3部分组成:字循环、字节代换和轮常量异或,这三个过程时T函数变换的充分必要条件)
    CASE2:当
    W[i]中i不是4的整数倍时,只需要将W[i-1]与W[i-4]进行异或,最后得出W[i]
    重复相同的流程所处所有的W

    核心流程

    轮函数示意图

    在这里插入图片描述

    • 字节代换(SubBytes 非线性)
      定义了S盒:(S盒是由16*16的字节组成的矩阵,S盒不可逆)
      +-
      我们通过S盒将明文分组中的元素逐个进行替换。
      例如: 明文分组为:
      在这里插入图片描述
      第一个元素19,在S盒中寻找第1行第9列的元素即可,按照上述S盒找出为 2D 。

    • 行移位 (ShiftRows 线性)为密码系统提供了扩展性
      是一个简单的左循环位移操作。
      规则 : 第n行就位移n字节
      例如:
      位移前
      在这里插入图片描述
      位移后
      在这里插入图片描述

    • 列混合 (MixColumns 非线性)为密码系统提供了扩展性
      简单的矩阵相乘操作
      将以下状态矩阵按列与固定矩阵相乘
      在这里插入图片描述
      在这里插入图片描述
      得到相乘的结果换到原来的列位置上
      在这里插入图片描述
      然后逐列依次进行

    • 轮密钥加
      我们将密钥扩展得到的轮密钥与我们的明文分组矩阵进行逐列的异或操作,将得到结果替换
      在这里插入图片描述
      替换之后
      在这里插入图片描述
      之后便进行流程的循环,不同的AES-n位循环的次数都不同,最终得到密文
      在这里插入图片描述

    • 所有轮数的流程图
      在这里插入图片描述

    AES算法的实现

    密钥扩展

    //密钥对应的扩展数组
    static int w[44];
    
    /**
     * 扩展密钥,结果是把w[44]中的每个元素初始化
     */
    static void extendKey(char *key) {
        for(int i = 0; i < 4; i++)
            w[i] = getWordFromStr(key + i * 4); 
    
        for(int i = 4, j = 0; i < 44; i++) {
            if( i % 4 == 0) {
                w[i] = w[i - 4] ^ T(w[i - 1], j); 
                j++;//下一轮
            }else {
                w[i] = w[i - 4] ^ w[i - 1]; 
            }
        }   
    
    }
    
    /**
     * 常量轮值表
     */
    static const int Rcon[10] = { 0x01000000, 0x02000000,
        0x04000000, 0x08000000,
        0x10000000, 0x20000000,
        0x40000000, 0x80000000,
        0x1b000000, 0x36000000 };
    /**
     * 密钥扩展中的T函数
     */
    static int T(int num, int round) {
        int numArray[4];
        splitIntToArray(num, numArray);
        leftLoop4int(numArray, 1);//字循环
    
        //字节代换
        for(int i = 0; i < 4; i++)
            numArray[i] = getNumFromSBox(numArray[i]);
    
        int result = mergeArrayToInt(numArray);
        return result ^ Rcon[round];
    }
    

    字节代换

    /**
     * 根据索引,从S盒中获得元素
     */
    static int getNumFromSBox(int index) {
        int row = getLeft4Bit(index);
        int col = getRight4Bit(index);
        return S[row][col];
    }
    
    /**
     * 字节代换
     */
    static void subBytes(int array[4][4]){
        for(int i = 0; i < 4; i++)
            for(int j = 0; j < 4; j++)
                array[i][j] = getNumFromSBox(array[i][j]);
    }
    

    行位移

    /**
     * 将数组中的元素循环左移step位
     */
    static void leftLoop4int(int array[4], int step) {
        int temp[4];
        for(int i = 0; i < 4; i++)
            temp[i] = array[i];
    
        int index = step % 4 == 0 ? 0 : step % 4;
        for(int i = 0; i < 4; i++){
            array[i] = temp[index];
            index++;
            index = index % 4;
        }
    }
    
    /**
     * 行移位
     */
    static void shiftRows(int array[4][4]) {
        int rowTwo[4], rowThree[4], rowFour[4];
        //复制状态矩阵的第2,3,4行
        for(int i = 0; i < 4; i++) {
            rowTwo[i] = array[1][i];
            rowThree[i] = array[2][i];
            rowFour[i] = array[3][i];
        }
        //循环左移相应的位数
        leftLoop4int(rowTwo, 1);
        leftLoop4int(rowThree, 2);
        leftLoop4int(rowFour, 3);
    
        //把左移后的行复制回状态矩阵中
        for(int i = 0; i < 4; i++) {
            array[1][i] = rowTwo[i];
            array[2][i] = rowThree[i];
            array[3][i] = rowFour[i];
        }
    }
    

    列混合

    /**
     * 列混合要用到的矩阵
     */
    static const int colM[4][4] = { 2, 3, 1, 1,
        1, 2, 3, 1,
        1, 1, 2, 3,
        3, 1, 1, 2 };
    
    static int GFMul2(int s) {
        int result = s << 1;
        int a7 = result & 0x00000100;
    
        if(a7 != 0) {
            result = result & 0x000000ff;
            result = result ^ 0x1b;
        }
    
        return result;
    }
    
    static int GFMul3(int s) {
        return GFMul2(s) ^ s;
    }
    
    /**
     * GF上的二元运算
     */
    static int GFMul(int n, int s) {
        int result;
    
        if(n == 1)
            result = s;
        else if(n == 2)
            result = GFMul2(s);
        else if(n == 3)
            result = GFMul3(s);
        else if(n == 0x9)
            result = GFMul9(s);
        else if(n == 0xb)//11
            result = GFMul11(s);
        else if(n == 0xd)//13
            result = GFMul13(s);
        else if(n == 0xe)//14
            result = GFMul14(s);
    
        return result;
    }
    
    /**
     * 列混合
     */
    static void mixColumns(int array[4][4]) {
    
        int tempArray[4][4];
    
        for(int i = 0; i < 4; i++)
            for(int j = 0; j < 4; j++)
                tempArray[i][j] = array[i][j];
    
        for(int i = 0; i < 4; i++)
            for(int j = 0; j < 4; j++){
                array[i][j] = GFMul(colM[i][0],tempArray[0][j]) ^ GFMul(colM[i][1],tempArray[1][j])
                    ^ GFMul(colM[i][2],tempArray[2][j]) ^ GFMul(colM[i][3], tempArray[3][j]);
            }
    }
    

    轮密钥加

    /**
     * 轮密钥加
     */
    static void addRoundKey(int array[4][4], int round) {
        int warray[4];
        for(int i = 0; i < 4; i++) {
    
            splitIntToArray(w[ round * 4 + i], warray);
    
            for(int j = 0; j < 4; j++) {
                array[j][i] = array[j][i] ^ warray[j];
            }
        }
    }
    

    AES加密函数

    /**
     * 参数 p: 明文的字符串数组。
     * 参数 plen: 明文的长度。
     * 参数 key: 密钥的字符串数组。
     */
    void aes(char *p, int plen, char *key){
    
        int keylen = strlen(key);
        if(plen == 0 || plen % 16 != 0) {
            printf("明文字符长度必须为16的倍数!\n");
            exit(0);
        }
    
        if(!checkKeyLen(keylen)) {
            printf("密钥字符长度错误!长度必须为16、24和32。当前长度为%d\n",keylen);
            exit(0);
        }
    
        extendKey(key);//扩展密钥
        int pArray[4][4];
    
        for(int k = 0; k < plen; k += 16) {
            convertToIntArray(p + k, pArray);
    
            addRoundKey(pArray, 0);//一开始的轮密钥加
    
            for(int i = 1; i < 10; i++){//前9轮
    
                subBytes(pArray);//字节代换
    
                shiftRows(pArray);//行移位
    
                mixColumns(pArray);//列混合
    
                addRoundKey(pArray, i);
    
            }
    
            //第10轮
            subBytes(pArray);//字节代换
    
            shiftRows(pArray);//行移位
    
            addRoundKey(pArray, 10);
    
            convertArrayToStr(pArray, p + k);
        }
    }
    

    AES解密函数

    /**
     * 参数 c: 密文的字符串数组。
     * 参数 clen: 密文的长度。
     * 参数 key: 密钥的字符串数组。
     */
    void deAes(char *c, int clen, char *key) {
    
        int keylen = strlen(key);
        if(clen == 0 || clen % 16 != 0) {
            printf("密文字符长度必须为16的倍数!现在的长度为%d\n",clen);
            exit(0);
        }
    
        if(!checkKeyLen(keylen)) {
            printf("密钥字符长度错误!长度必须为16、24和32。当前长度为%d\n",keylen);
            exit(0);
        }
    
        extendKey(key);//扩展密钥
        int cArray[4][4];
        for(int k = 0; k < clen; k += 16) {
            convertToIntArray(c + k, cArray);
    
    
            addRoundKey(cArray, 10);
    
            int wArray[4][4];
            for(int i = 9; i >= 1; i--) {
                deSubBytes(cArray);
    
                deShiftRows(cArray);
    
                deMixColumns(cArray);
                getArrayFrom4W(i, wArray);
                deMixColumns(wArray);
    
                addRoundTowArray(cArray, wArray);
            }
    
            deSubBytes(cArray);
    
            deShiftRows(cArray);
    
            addRoundKey(cArray, 0);
    
            convertArrayToStr(cArray, c + k);
    
        }
    }
    
    展开全文
  • Aes算法程序

    2017-12-10 14:20:06
    Aes算法程序 Aes算法程序Aes算法程序 Aes算法程序Aes算法程序Aes算法程序
  • 本文在可重构平台上针对 128位密钥长度AES算法的流水线性能优化技术进行了研究,通过对基本运算优化、循环展开、轮内流水线、轮间流水线、混合多级流水线结构优化等方法的讨论和实现,对比不同优化方法的优缺点及...
  • AES加密算法C语言实现,有测试代码,可直接使用,提供了加密和解密两个接口,可直接添加到工程中使用,纯C代码,方便移植
  • 主要介绍了高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密算法(微信小程序加密传输就是用这个加密算法的)。对称加密算法也就是加密和解密用相同的密钥,需要的朋友可以参考下
  • 使用Python实现密码学的AES算法
  • aes算法实现代码

    热门讨论 2012-11-22 10:01:58
    算法aes的实现代码,加密及解密功能的实现。密钥长度选择为128位,实现简单,易于理解。
  • Go-AES算法详解与代码

    千次阅读 2021-06-06 18:24:47
    AES 发展史 概述 AES的Go实现 func NewCipher(key []byte) (cipher.Block, error)

    目录

    AES

    发展史

    概述

    轮函数F

    字节代换

    行移位

    列混淆

    轮密钥加

    密钥编排

    AES和DES的不同之处

    分组模式CTR

    AES的Go实现

    aes包

    cipher包

    加密/解密

    参考


    本篇介绍分组密码AES的相关内容及Go实现,分组密码算法设计思想及其他分组模式可查看文章:Go-Des和3Des算法详解与代码

    AES

    发展史

        RSA公司举办过破译DES的比赛(DES Challenge):

    • 1997年的DES ChallengeI中用了96天
    • 1998年的DES ChallengeII-1中用了41天
    • 1998年的DES ChallengeII-2中用了56小时
    • 1999年的DES ChallengeII中用了22小时15分钟

    DES被破解,3DES过度后终于迎来了AES。

    • 1997年4月15日,美国ANSI向全球发起征集AES(advanced encryptionstandard)的活动,并为此成立了AES工作小组。
    • 1997年9月12日,美国联邦登记处公布了正式征集AES候选算法的通告。对AES的基本要求是:比三重DES快、至少与三重DES一样安全、数据分组长度为128比特、密钥长度为128/192/256比特。
    • 1998年8月12日,在首届AES候选会议(first AES candidate conference)上公布了AES的15个候选算法,任由全世界各机构和个人攻击和评论。
    • 1999年3月,在第2届AES候选会议(second AES candidate conference)上经过对全球各密码机构和个人对候选算法分析结果的讨论,从15个候选算法中选出了5个。分别是RC6、Rijndael、SERPENT、Twofish和MARS。
    • 2000年4月13日至14日,召开了第3届AES候选会议(third AES candidateconference),继续对最后5个候选算法进行讨论。
    • 2000年10月2日,NIST宣布Rijndael(Rijndael由比利时的Joan Daemen和Vincent Rijmen设计。算法的原型是 Square算法作为新的AES。经过3年多的公开讨论,Riindael终于脱颖而出。

    概述

    •  分组加密算法:明文和密文分组可变长度。
    • SPN(S变换和P变换组成的变换网络)结构:轮函数包含代换层一置换层一密钥混合层。
    版本密钥长度分组长度迭代轮数
    AES-1284410
    AES-1926412
    AES-2568414

    轮函数F

     

    字节代换

    列的每个元素作为输入用来指定S盒的地址:前4位指定S盒的后4位指定S盒的。由行和列所确定的S盒位置的元素取代了明文矩阵中相应位置的元素。

     S盒如下(反向使用S^-1盒即可)

    明文:10000111,前4位为8,后四位为7,替换为S(8,7)=17=00010001

    行移位

    行移位操作是作用于S盒的输出的,其中,列的4个行 螺旋 地左移,即第0行左移0字节第1行左移1字节第2行左移2字节第3行左移3字节,如下图所示。从该图中可以看出, 这使得列完全进行了重排,即在移位后的每列中,都包含有 未移位前每个列的一个字节。接下来就可以进行列内混合了。 (逆向行移位变换将中间态数据的后三行执行相反方向的移位操作)

    列混淆

    在列混淆变换中,将行移位后的状态阵列的每个列视为GF(2^8)上的多项式,再与一个固定的多项式c(x)进行模x^4+1乘法,要求c(x) 是模x^4+1可逆的多项式。 c(x)=’03’x^3+’01’x^2+’01’x+’02’。

    轮密钥加

     

    密钥编排

    密钥编排指从种子密钥得到轮密钥的过程,AES的密钥编排由密钥扩展轮密钥选取两部分组成,其基本原则如下:

    1. 轮密钥的总比特数等于轮数加1再乘以分组长度;如128比特的明文经过10轮的加密,则总共需 要(10+1)*128=1408比特的密钥.。
    2. 种子密钥被扩展成为扩展密钥
    3. 轮密钥从扩展密钥中取,其中第1轮轮密钥取扩展密钥的前N_b个字,第2轮轮密钥取接下来的N_b个字,依次类推。

    密钥扩展

    扩展密钥是以4字节字为元素的一维阵列,表示为W[N_b* (Nr +1)],其中前N_k个字取为种子密钥, 以后每个字按递归方式定义。扩展算法根据N_k≤6和N_k>6有所不同。

    轮密钥选取

    轮密钥i(即第i个轮密钥)由轮密钥缓冲字 W[N_b* i]到W[N_b*(i+1)]给出

    AES和DES的不同之处

    • AES的密钥长度(128位、192位、256位)是可变的,而DES的 密钥长度固定为56位。
    • DES是面向比特的运算,AES是面向字节的运算。
    • AES的加密运算和解密运算不一致,因而加密器不能同时 用作解密器,而DES的加密器可用作解密器,只是子密钥 的顺序不同。

    分组模式CTR

    加密不同的明文分组所用的计数器值必须不同(模2^d运 算,其中d是分组长度)。

    AES的Go实现

    aes包

    func NewCipher(key []byte) (cipher.Block, error)

    创建一个cipher.Block接口。参数key为密钥,长度只能是16、24、32字节,用以选择AES-128、AES-192、AES-256。

    cipher包

    func NewCTR(block Block, iv []byte) Stream

    返回一个计数器模式的、底层采用block生成key流的Stream接口,初始向量iv的长度必须等于block的块尺寸。

    stream接口的方法

    XORKeyStream(dst, src []byte)

    从加密器的key流和src中依次取出字节二者xor后写入dst,src和dst可指向同一内存地址

    加密/解密

    • 使用aes.NewCipher获取块
    • 使用cipher.CTR转为CTR模式流
    • 使用stearm.XORKeyStream进行加解密
    // plainText:明文
    // iv: 初始化向量
    // key:密钥
    // 返回密文/明文,以及错误
    func AesEncrypt(plainText, iv,key []byte) ([]byte,error) {
    	block, err :=aes.NewCipher(key)
    	if err != nil{
    		_, file, line, _ := runtime.Caller(0)
    		return nil,util.Error(file,line+1,errors.AesKeyError)
    	}
    	if len(iv) != block.BlockSize(){
    		_, file, line, _ := runtime.Caller(0)
    		return nil,util.Error(file,line+1,errors.AesIvError)
    	}
    	// create a CTR interface
    	stream := cipher.NewCTR(block,iv)
    	cipherText := make([]byte,len(plainText))
    	// encrypt or decrypt
    	stream.XORKeyStream(cipherText,plainText)
    	return cipherText,nil
    }

    代码我放到了gitee上:https://gitee.com/frankyu365/gocrypto

    您可以查看仓库Readme文档或Go-包管理(管理工具对比及go mod的使用)来进行安装

    测试代码

    	iv := []byte("12345678qwertyui")
    	key:= []byte("12345678abcdefgh09876543alnkdjfh")
    	plainText := []byte("Hi,I'm lady_killer9")
    	cipherText,_ := aes.AesEncrypt(plainText,iv,key)
    	fmt.Printf("加密后:%s\n",cipherText)
    	decryptText,_ := aes.AesDecrypt(cipherText,iv,key)
    	fmt.Printf("解密后:%s\n",decryptText)

     

    参考

    《现代密码学教程 谷利泽 杨义先等》

    AES的发展史

    Go标准库-crypto/aes

    Go标准库-crypto/cipher

    更多Go相关内容:Go-Golang学习总结笔记

    有问题请下方评论,转载请注明出处,并附有原文链接,谢谢!如有侵权,请及时联系。如果您感觉有所收获,自愿打赏,可选择支付宝18833895206(小于),您的支持是我不断更新的动力。

     

    展开全文
  • 电子-AES算法C语言实现源码带注释.txt,综合电子技术编程语言学习
  • C++ AES加密算法的实现(附代码

    千次阅读 2022-03-31 08:49:55
    AES原理讲解、代码实现

    1  AES算法介绍

    美国国家标准技术研究所在2001年发布了高级加密标准(AES)。AES是一个对称加密算法,旨在取代DES成为广泛使用的标准,该标准以Rijndael算法为核心。

    Rijndael算法是一种对称分组密码体制,采用代替或置换网络,每轮由三层组成:线性混合层确保多轮之上的高度扩散;非线性层由S盒并置起到混淆的作用;密钥加密层将子密钥异或到中间状态。

    AES标准规定Rijndael算法的分组长度为128位,而密钥长度可以为128、192或256位,相应的迭代轮数为10轮、12轮或14轮。Rijndael 汇聚了安全性能、效率、可实现性和灵活性等优点。Rijndael 对内存的需求低,使它很适合用于资源受限制的环境中,Rijndael 的操作简单,并可抵御强大和实时的攻击

    AES加密算法流程如下:

    图1. AES算法流程

    2 加密、解密涉及的操作介绍

    2.1 字节代替

    用一个S盒完成分组的字节到字节的代替;是一个基于S盒的非线性置换,它用于将每一个字节通过一个简单的查表操作映射为另一个字节。映射方法是把输入字节的高4位作为S盒的行值,低4位作为列值,然后取出S盒中对应行和列交叉位的元素作为输出

    图2.字节代换

    2.2  行移位

     AES 的行移位也是一个简单的左循环移位操作。当密钥长度为128比特时,状态矩阵的第0行左移0字节,第1行左移1字节,第2行左移2字节,第3行左移3字节

      

    图3. 行移位

    2.3 列混合

    列混合变换是通过矩阵相乘来实现的,经行移位后的状态矩阵与固定的矩阵相乘,得到混淆后的状态矩阵。

    图4. 列混合

    2.4 轮密钥加

    当前分组和扩展密钥的一部分进行按位异或,将输入或中间态S的每一列与一个密钥字ki进行按位异或,即将128位轮密钥 Ki 同状态矩阵中的数据进行逐位异或操作。

    3 密钥编排

    1)      用一个 4 字节字元素的一维数组 W[Nb*(Nr+1)]表示扩展密钥。

    2)      数组中最开始的 Nk 个字为种子密钥。

    3)      其它的字由它前面的字经过递归处理后得到。

    新列以如下的递归方式产生:

    1) 如果i不是4的倍数,那么第i列由如下等式确定:

      W[i]=W[i-4]⨁W[i-1]

    2) 如果i是4的倍数,那么第i列由如下等式确定:

      W[i]=W[i-4]⨁T(W[i-1])

    函数T由3部分组成:字循环、字节代换和轮常量异或

    a)       字循环:将1个字中的4个字节循环左移1个字节。即将输入字[b0, b1, b2, b3]变换成[b1,b2,b3,b0]。

    b)       字节代换:对字循环的结果使用S盒进行字节代换。

    c)     轮常量异或:将前两步的结果同轮常量Rcon[j]进行异或,其中j表示轮数。

    4 代码

    4.1 密钥扩展

    keyExtend.h

    #ifndef KEYEXTEND_H
    #define KEYEXTEND_H
    
    #include<bitset>
    using namespace std;
    typedef bitset<8> byte;
    typedef bitset<32> word;
    extern byte S[256];
    extern byte inv_S[256];
    extern word rcon[10];
    extern byte encry_s[4*4];
    extern byte decry_s[4*4];
    
    //定义种子密钥长度以及扩展轮数
    const int Nr = 10;//轮数 
    const int Nk = 4; //种子密钥有四个字 
    
    //密钥扩展 相关函数
    // 1 四个字节转换成一个字 
    word Word(byte b0,byte b1,byte b2,byte b3);
    // 2 字移位 
    word CycWord(word rw);
    // 3 S盒替换 
    word SubWord(word sw);
    // 4 密钥扩展 
    void KeyExpansion(byte key[4*Nk],word w[4*(Nr+1)]);
    // 加密使用的列混合数组
    
    
    #endif

    keyExtend.cpp

    #include"keyExtend.h"
    #include<iostream>
    #include<string>
    using namespace std;
    
    // S盒
    byte S[256] = {
    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 inv_S[256] = {
    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
    };
    
    // AES-128轮常量
    word rcon[10] = {
        0x01000000UL, 0x02000000UL, 0x04000000UL, 0x08000000UL, 0x10000000UL,
        0x20000000UL, 0x40000000UL, 0x80000000UL, 0x1B000000UL, 0x36000000UL
    };
    
    
    // 加密使用的列混合数组
    byte encry_s[16]={
    	0x02,0x03,0x01,0x01,
    	0x01,0x02,0x03,0x01,
    	0x01,0x01,0x02,0x03,
    	0x03,0x01,0x01,0x02
    } ;
    
    // 解密使用的列混合数组
    byte decry_s[4*4]={
    	0x0e,0x0b,0x0d,0x09,
    	0x09,0x0e,0x0b,0x0d,
    	0x0d,0x09,0x0e,0x0b,
    	0x0b,0x0d,0x09,0x0e
    };
     
    //准备事件:将四个字节转化为一个字,方便进行计算 
    word Word(byte b0,byte b1,byte b2,byte b3){
    	word wordres=0x00000000;
    	word temp;
    	temp=b0.to_ulong();//b0
    	temp<<=24;
    	wordres|=temp;
    	temp=b1.to_ulong();//b1
    	temp<<=16;
    	wordres|=temp;
    	temp=b2.to_ulong();//b2
    	temp<<=8;
    	wordres|=temp;
    	temp=b3.to_ulong();//b0
    	wordres|=temp;
    	return wordres; 	
    } 
    
    //第一步:字循环
    //将1个字中的4个字节循环左移1个字节。即将输入字[b0, b1, b2, b3]变换成[b1,b2,b3,b0]。 
    word CycWord(word rw){
    	word high = rw<<8; 
    	word low = rw>>24; 
    	return high^low;
    }
    
    //第二步:字节代换
    //对字循环的结果使用S盒进行字节代换。 
    word SubWord(word sw){
    	word temp;
    	for(int i=0;i<32;i+=8){
    		//先确定密钥字所在的位置
    		int row=sw[i+7]*8+sw[i+6]*4+sw[i+5]*2+sw[i+4]*1;
    		int col=sw[i+3]*8+sw[i+2]*4+sw[i+1]*2+sw[i]*1;
    		//进行S盒代换 
    		byte tempvar=S[row*16+col];
    		for(int j=0;j<8;j++){
    			temp[i+j]=tempvar[j];
    		}
    	}
    	return temp;	
    }
    
    //第三步:轮常量异或
    //将前两步的结果同轮常量Rcon[j]进行异或,其中j表示轮数。
    
    
    
    /*密钥扩展函数
    1) 如果i不是4的倍数,那么第i列由如下等式确定:
    	W[i]=W[i-4]^W[i-1]
    2) 如果i是4的倍数,那么第i列由如下等式确定:
    	W[i]=W[i-4]^T(W[i-1])
    */
    void KeyExpansion(byte key[4*Nk],word w[4*(Nr+1)]){
    	word temp;
    	int i=0;
    	
    	//获取种子密钥(前四个字) 
    	while(i<Nk){
    		w[i]=Word(key[4*i],key[4*i+1],key[4*i+2],key[4*i+3]);
    		i++;
    	}
    	i=Nk;
    	//开始进行密钥扩展 
    	while(i<4*(Nr+1)){
    		temp=w[i-1];
    		if(i%Nk==0){
    			w[i]=w[i-Nk]^SubWord(CycWord(temp))^rcon[i/Nk-1];
    //			cout<<"w["<<dec<<i<<"]对应的论常量为:"<<hex<<rcon[i/Nk-1]<<endl;
    //			if(i==8){
    //				cout<<"w[8]的字移位,S盒变换以及论常量异或结果分别为:"<<endl;
    //				cout<<CycWord(temp)<<endl;
    //				cout<<SubWord(CycWord(temp))<<endl;
    //				word c=SubWord(CycWord(temp))^ rcon[i/Nk-1]; 
    //				cout<<c<<endl;
    //			}	
    		}else{
    			w[i]=w[i-Nk]^temp;
    		}
    		i++;
    	}
    }
    
    
     

    4.2 加密

    encryption.h

    #ifndef ENCRYPTION_H
    #define ENCRYPTION_H
    #include "keyExtend.h"
    
    using namespace std;
    
    /*
    预处理工作
    	1 设计有限域上的乘法函数 
    */
    
    // 设计有限域上的乘法函数 
    byte GFMul(byte a,byte b);
    
    
    
    // 1 轮密钥加
    void RKey_Add(byte sta_matr[4*4],word w[4]);
    
    // 2 字节代换
    void SubBytes(byte sta_matr[4*4]);
    
    // 3 行移位--按行进行字节移位
    void ShiftRow(byte sta_matr[4*4]); 
    
    // 4 列混合 
    void MixColumns(byte sta_matr[4*4],byte s[4*4]); 
    
    // 5 加密函数
    void encrypt(byte in[4*4],word w[4*(Nr+1)]); 
    
    #endif

    encryption.cpp

    #include<iostream>
    #include<string>
    #include"encryption.h"
    using namespace std;
    
    
    //有限域上的乘法 GF(2^8)  表示含有2的N次方个元素的有限域  代码已测没问题 
    // 注意可以手写一下二进制乘法就知道原理了 
    byte GFMul(byte a, byte b) { 
    	byte p = 0;
    	for (int i= 0;i< 8;i++) {
    		//先判断b的低阶位		
    		if (b[0] == 1)
    			p ^= a;
    		//拿到a的高阶位 
    		int temp=a[7];
    		a <<= 1;
    		//左移导致溢出了 所以用假如没有丢失数据的左移后a mod m(x)  等价于丢失数据后a ^ 0x1b 
    		if (temp==1) 
    			a ^= 0x1b; 
    		b >>= 1;
    	}
    	return p;
    }
    
    
    // 1 轮密钥加 将状态矩阵的一列的四个字节和轮密钥的对应字节进行异或   
    void RKey_Add(byte sta_matr[4*4],word w[4]){
    	for(int i=0;i<4;i++){
    		//每一轮完成一列 四个字节的异或 
    		word k0 = w[i]>>24;  
    		word k1 = (w[i]<<8)>>24;
    		word k2 = (w[i]<<16)>>24;
    		word k3 = (w[i]<<24)>>24;
    		
    		sta_matr[i] = sta_matr[i]^byte(k0.to_ulong());
    		sta_matr[i+4] = sta_matr[i+4]^byte(k1.to_ulong());
    		sta_matr[i+8] = sta_matr[i+8]^byte(k2.to_ulong()); 
    		sta_matr[i+12] = sta_matr[i+12]^byte(k3.to_ulong());
    	} 
    	
    }
    
    // 2 字节代换  经测试没有问题 
    void SubBytes(byte sta_matr[4*4]){
    	// 将16个字节依次进行代换
    	for(int i=0;i<16;i++){
    		//bitset地址存放是低位在前,高位在后,与常规相反,计算需要谨慎 
    		int row = sta_matr[i][7]*8+sta_matr[i][6]*4+sta_matr[i][5]*2+sta_matr[i][4]*1;
    		int col = sta_matr[i][3]*8+sta_matr[i][2]*4+sta_matr[i][1]*2+sta_matr[i][0]*1;
    		sta_matr[i] = S[row*16+col]; 
    	} 
    	
    	
    }
    
    // 3 行移位--按行进行字节移位   代码已测没问题 
    void ShiftRow(byte sta_matr[4*4]){
    	//第二行循环左移一个字节
    	//第三行循环左移二个字节 
    	//第三行循环左移三个字节
    	
    	for(int i=0;i<4;i++){
    		byte temp[i];
    		//存数 防止被覆盖
    		for(int j=0;j<i;j++){
    			temp[j]=sta_matr[i*4+j];
    		} 
    		// 将不会发生下标溢出的进行赋值 
    		for(int j=0;j<4-i;j++){
    			sta_matr[i*4+j]=sta_matr[i*4+j+i];	
    		}
    		// 将暂存的数放回状态数组 行中 
    		for(int m=4-i;m<4;m++){
    			sta_matr[i*4+m]=temp[m+i-4];
    		}
    	} 
    }
    
    // 4 列混合   经测试没问题 
    void MixColumns(byte sta_matr[4*4],byte s[4*4]){
    	byte matr[4];
    	for(int i=0;i<4;i++){
    		for(int j=0;j<4;j++)
    			matr[j] = sta_matr[i+j*4];
     
    		sta_matr[i] = GFMul(s[0], matr[0]) ^ GFMul(s[1], matr[1]) ^ GFMul(s[2], matr[2]) ^ GFMul(s[3], matr[3]);
    		sta_matr[i+4] = GFMul(s[4], matr[0]) ^ GFMul(s[5], matr[1]) ^ GFMul(s[6], matr[2]) ^ GFMul(s[7], matr[3]);
    		sta_matr[i+8] = GFMul(s[8], matr[0]) ^ GFMul(s[9], matr[1]) ^ GFMul(s[10], matr[2]) ^ GFMul(s[11], matr[3]);
    		sta_matr[i+12] = GFMul(s[12], matr[0]) ^ GFMul(s[13], matr[1]) ^ GFMul(s[14], matr[2]) ^ GFMul(s[15], matr[3]);
    	}
    	
    }
    
    // 5 加密函数
    void encrypt(byte sta_matr[4*4],word w[4*(Nr+1)]){
    	word key[4];
    	for(int i=0; i<4; i++)
    		key[i] = w[i];
    	//先进行一次轮密钥加 
    	RKey_Add(sta_matr,key);
    //	cout<<"第0轮加密的结果是:"<<endl;
    //		for(int i=0;i<16;i++){
    //		cout<<hex<<sta_matr[i].to_ulong()<<"  ";
    //		if((i+1)%4==0)cout<<endl;}
    	//九轮操作   S盒  行移位  列混合  轮密钥加 
    	for(int r=1; r<Nr; r++)
    	{
    		SubBytes(sta_matr);
    		ShiftRow(sta_matr);
    		MixColumns(sta_matr,encry_s);
    		for(int i=0; i<4; i++)
    			key[i] = w[4*r+i];
    		RKey_Add(sta_matr, key);
    //		cout<<endl;
    //		cout<<"第"<<r<<"轮加密的结果是:"<<endl;
    //		for(int i=0;i<16;i++){
    //		cout<<hex<<sta_matr[i].to_ulong()<<"  ";
    //		if((i+1)%4==0)cout<<endl;
    //		}  
    	}
     	//第十轮   S盒  行移位  轮密钥加 
    	SubBytes(sta_matr);
    	ShiftRow(sta_matr);
    	for(int i=0; i<4; ++i)
    		key[i] = w[4*Nr+i];
    	RKey_Add(sta_matr, key);
    	cout<<endl;
    //	cout<<"第10轮加密的结果是:"<<endl;
    //	for(int i=0;i<16;i++){
    //		cout<<hex<<sta_matr[i].to_ulong()<<"  ";
    //		if((i+1)%4==0)cout<<endl;
    //	}  
    }
    

    4.3 解密

    decrypt.h

    #ifndef DECRYPT_H
    #define DECRYPT_H
    #include"encryption.h"
    
    
    using namespace std;
    
    // 1 逆行变换
    void InvShiftRow(byte sta_matr[4*4]);
    
    // 2 逆S盒变换
    void InvSubBytes(byte sta_matr[4*4]);
    
    // 3 逆列变换
    void InvMixColumns(byte sta_matr[4*4]);
    
    // 4 解密函数
    void decrypt(byte in[4*4],word w[4*(Nr+1)]);  
     
    #endif

    decrypt.cpp

    #include<iostream>
    #include<string>
    #include"decrypt.h"
    
    
    using namespace std;
    
    // 1 逆行变换  循环右移     已测试没有问题 
    void InvShiftRow(byte sta_matr[4*4]){
    	for(int i=0;i<4;i++){
    		byte temp[i];
    		//存数 防止被覆盖
    		for(int j=0;j<i;j++){
    			temp[j]=sta_matr[i*4+3-j];
    		} 
    		// 将不会发生下标溢出的进行赋值 
    		for(int j=0;j<4-i;j++){
    			sta_matr[i*4+3-j]=sta_matr[i*4+3-j-i];	
    		}
    		// 将暂存的数放回状态数组 行中 
    		for(int m=0;m<i;m++){
    			sta_matr[i*4+m]=temp[i-m-1];
    		}
    	} 
    
    }
    // 2 逆S盒变换    没变化没问题 
    void InvSubBytes(byte sta_matr[4*4]){
    	// 将16个字节依次进行代换
    	for(int i=0;i<16;i++){
    		//bitset地址存放是低位在前,高位在后,与常规相反,计算需要谨慎 
    		int row = sta_matr[i][7]*8+sta_matr[i][6]*4+sta_matr[i][5]*2+sta_matr[i][4];
    		int col = sta_matr[i][3]*8+sta_matr[i][2]*4+sta_matr[i][1]*2+sta_matr[i][0];
    		sta_matr[i] = inv_S[row*16+col]; 
    	} 
    }
    
    // 3 逆列变换   没变化没问题 
    void InvMixColumns(byte sta_matr[4*4],byte s[4*4]){
    	byte matr[4];
    	for(int i=0;i<4;i++){
    		for(int j=0;j<4;j++)
    			matr[j] = sta_matr[i+j*4];
     
    		sta_matr[i] = GFMul(s[0], matr[0]) ^ GFMul(s[1], matr[1]) ^ GFMul(s[2], matr[2]) ^ GFMul(s[3], matr[3]);
    		sta_matr[i+4] = GFMul(s[4], matr[0]) ^ GFMul(s[5], matr[1]) ^ GFMul(s[6], matr[2]) ^ GFMul(s[7], matr[3]);
    		sta_matr[i+8] = GFMul(s[8], matr[0]) ^ GFMul(s[9], matr[1]) ^ GFMul(s[10], matr[2]) ^ GFMul(s[11], matr[3]);
    		sta_matr[i+12] = GFMul(s[12], matr[0]) ^ GFMul(s[13], matr[1]) ^ GFMul(s[14], matr[2]) ^ GFMul(s[15], matr[3]);
    	}
    }
    
    // 4 解密函数 
    void decrypt(byte sta_matr[4*4],word w[4*(Nr+1)]){
    	word key[4];
    	for(int i=0; i<4; i++)
    		key[i] = w[4*Nr+i];
    	//先进行一次轮密钥加 
    	RKey_Add(sta_matr,key);
    	//九轮操作  逆行移位   逆S盒 轮密钥加  逆列混合 
    	for(int r=Nr-1; r>0; r--)
    	{
    		InvShiftRow(sta_matr);
    		InvSubBytes(sta_matr);
    		for(int i=0; i<4; i++)
    			key[i] = w[4*r+i];
    		RKey_Add(sta_matr, key);
    		InvMixColumns(sta_matr,decry_s); 	
    	}
     	//第十轮   逆行移位   逆S盒 轮密钥加 
    	InvShiftRow(sta_matr);
    		InvSubBytes(sta_matr);
    		for(int i=0; i<4; i++)
    			key[i] = w[i];
    		RKey_Add(sta_matr, key);
    } 
    
     

    4.4 main函数

    #include"encryption.h"
    #include"decrypt.h"
    #include<iostream>
    #include<bitset>
    
    int main(){
    	//种子密钥 
    	byte key[16] = {0x2b, 0x7e, 0x15, 0x16, 
    					0x28, 0xae, 0xd2, 0xa6, 
    					0xab, 0xf7, 0x15, 0x88, 
    					0x09, 0xcf, 0x4f, 0x3c};
    //	byte key[16] = {0x00, 0x01, 0x02, 0x03, 
    //					0x04, 0x05, 0x06, 0x07, 
    //					0x08, 0x09, 0x01, 0x02, 
    //					0x03, 0x04, 0x05, 0x06};
    //	byte key[16] = {0x00, 0x01, 0x02, 0x03, 
    //						0x04, 0x05, 0x06, 0x07, 
    //						0x08, 0x09, 0x0a, 0x0b, 
    //						0x0c, 0x0d, 0x0e, 0x0f};
    
    
    	//输入的明文 
    	byte sta_matr[16]={0x32,0x88,0x31,0xe0,
    						0x43,0x5a,0x31,0x37,
    						0xf6,0x30,0x98,0x07,
    						0xa8,0x8d,0xa2,0x34};
    //    byte sta_matr[16]={0x61,0x62,0x63,0x64,
    //    					0x65,0x66,0x67,0x68,
    //    					0x69,0x6A,0x6B,0x6C,
    //    					0x6D,0x6E,0x6F,0x70					
    //	}; 
    //	byte sta_matr[16] = {0x00, 0x11, 0x22, 0x33, 
    //							0x44, 0x55, 0x66, 0x77, 
    //							0x88, 0x99, 0xaa, 0xbb, 
    //							0xcc, 0xdd, 0xee, 0xff};
     
    						
    	//进行密钥扩展
    	word w[4*(Nr+1)];
    	KeyExpansion(key,w); 
    	
    	//输出密钥
    	cout<<"密钥是:"<<endl;
    	for(int i=0;i<16;i++){
    		cout<<hex<<key[i].to_ulong()<<"  ";
    		if((i+1)%4==0)cout<<endl;
    	}   
    	cout<<endl;
    	//输出明文
    	cout<<"明文是:"<<endl;
    	for(int i=0;i<16;i++){
    		cout<<hex<<sta_matr[i].to_ulong()<<"  ";
    		if((i+1)%4==0)cout<<endl;
    	}  
    	//输出密文
    	cout<<endl;
    	encrypt(sta_matr,w);
    	cout<<"密文是:"<<endl;
    	for(int i=0;i<16;i++){
    		cout<<hex<<sta_matr[i].to_ulong()<<"  ";
    		if((i+1)%4==0)cout<<endl;
    	}  
    	
    	//再次进行解密
    	cout<<endl;
    	cout<<"密文解密是:"<<endl;
    	decrypt(sta_matr,w);
    	for(int i=0;i<16;i++){
    		cout<<hex<<sta_matr[i].to_ulong()<<"  ";
    		if((i+1)%4==0)cout<<endl;
    	}  
    	return 0;
    	
    
    
    	
    /*
    	以下是函数正确性验证部分
    		1 密钥扩展验证
    			for(int i=0;i<4*(Nr+1);i++){
    			cout<<"w["<<dec<<i<<"]="<<hex<<w[i].to_ulong()<<endl;
    			}
    		
    		2 验证有限域乘法
    			byte temp=GFMul(0x57,0x83);
    			for(int i=0;i<8;i++){
    				cout<<temp[i]<<" ";}
    				cout<<endl;
    			cout<<"0x57*0x83:"<<hex<<temp.to_ulong(); 
    		
    		3 测试字节代换有无问题
    			SubBytes(sta_matr);
    			cout<<"字节代换后是:"<<endl;
    			for(int i=0;i<16;i++){
    				cout<<hex<<sta_matr[i].to_ulong()<<"  ";
    				if((i+1)%4==0)cout<<endl;
    			} 
    			
    		4 测试列混合函数是否正确
    			byte s[16] = {0xc9,0xe5,0xfd,0x2b, 
    					0x7a,0xf2,0x78,0x6e,
    					0x63,0x9c,0x26,0x67,
    					0xb0,0xa7,0x82,0xe5}; 
    			MixColumns(s,encry_s);
    			for(int i=0;i<16;i++){
    				cout<<hex<<s[i].to_ulong()<<"  ";
    				if((i+1)%4==0)cout<<endl;
    			} 	
    			
    		
    		
    */	
    	
    /*
    	以下维验证bitset类型数据的存储以及计算方式
    		1 小端模式:即常规思维的0011 0011在计算机存储变成1100 1100
    		2 定义的两个byte(bitset<8>)数据进行异或也是按照两个小端形式的数据进行异或,存储的依旧是小端格式 
    		3 如果按位输出 小端格式  按字节输出 大端格式 
    		4 比如使用a则正常顺序(大端) 仅当按位的时候才是小端 
    		5 a^b 按字节输出是正常大端顺序 
    			byte temp0=0x57;
    			cout<<temp<<endl;
    			cout<<(temp>>1)<<endl;
    			cout<<temp[5];
    			byte temp2=0x83;
    			cout<<(temp^temp2);
    			cout<<"temp1:";
    			for(int i=0;i<8;i++){
    				cout<<temp[i]<<" ";
    			} 
    			cout<<endl; 
    			cout<<"temp2:";
    			for(int i=0;i<8;i++){
    				cout<<temp2[i]<<" ";
    			} 
    			cout<<endl; 
    			cout<<"temp1^temp2:";
    			byte temp3=temp^temp2;
    			for(int i=0;i<8;i++){
    				cout<<temp3[i]<<" ";
    			} 
    			cout<<dec<<temp3.to_ulong();
    */		 
    } 

    4.5 结果测试 

    展开全文
  • 高级加密标准(AES)为最常见的对称加密算法(微信小程序加密传输就是用这个加密算法的),对称加密算法也就是加密和解密用相同的密钥。
  • 用C语言实现的AES加密解密算法

    千次下载 热门讨论 2013-08-26 10:36:17
    用C语言实现的AES加密解密算法,用C语言实现的AES加密解密算法
  • 介绍了一种用FPGA来快速实现硬件IP核的AES算法的方法,采用Xilinx公司的Virtex XCV-1000-6器件,并给出了时序仿真图,结果表明了其有效性。
  • Delphi AES 算法

    2018-09-06 21:28:34
    本组代码采用标准AES算法(基础算法引用ElAES.pas,感谢作者),代码支持AES/ECB/PKCS5Padding、AES/CBC/PKCS5Padding 密钥长度128/192/256bit,密钥0填充,Delphi与JAVA互相加解密。加密前Delphi与JAVA统一字符编码...
  • AES加密算法代码实现

    千次阅读 2021-10-25 22:59:37
    AES加密算法代码实现 作业目标 C语言实现AES加密算法,并将其优化到尽量快的速度。 算法描述 AES简介 高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密算法,又称Rijndael加密法,是美国联邦政府...
  • 文章目录前言一、AES简介二、加解密过程1.常规版2.优化版三、 各函数简要介绍1.密钥编排、密钥扩展函数 ...本文主要分享了AES算法的基础知识和C语言的简单实现。 一、AES简介 AES是分组密码,安全性良好。 与
  • AES算法的java实现中的字节替代代码,没太看懂,请大佬赐教。 ![图片说明](https://img-ask.csdn.net/upload/201810/12/1539325077_37480.jpg)
  • AES算法描述及C语言实现

    万次阅读 多人点赞 2018-05-06 23:16:25
    AES算法是当前最流行的对称加密算法,也是一种分组加密算法,分组密码就是把明文分为固定长度的一组一组,每次加密一组数据,直到加密完整个明文数据。AES算法根据分组长度可以分为AES128, AES192,AES256,其所要求...
  • 利用Verilog语言,实现AES算法快速硬件实现,对于系统学习Verilog语言和安全芯片设计帮助较大
  • aes算法演示代码

    2014-01-14 14:14:56
    代码适合AES加密的源代码,还有演示操作
  • [转]AES加密算法及java代码实现

    千次阅读 2017-08-22 14:59:50
    AES加密 AES是一个对称密码,旨在取代DES成为广泛使用...加密解密算法的输入是一个128位分组。这些分组被描述成4×4的字节方阵,这个分组被复制到state数组中,并在加密和解密的每一阶段都被修改。在字节方阵中
  • aes算法官方visual studio代码
  • AES加密算法c语言实现代码#include "stdio.h"#include "memory.h"#include "time.h"#include "stdlib.h"……#include "stdio.h"#include "memory.h"#include "time.h"#include "stdlib.h"#define PLAIN_FILE_OPEN_...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 30,412
精华内容 12,164
关键字:

aes算法代码