基于MFC实现的AES加密解密程序

TrueLove

发布日期: 2018-12-02 17:14:35 浏览量: 2153
评分:
star star star star star star star star star star_border
*转载请注明来自write-bug.com

1 算法背景及介绍

1.1 背景

高级加密标准(Advanced Encryption Standard,AES)作为传统对称加密算法标准DES的替代者,由美国国家标准与技术研究所(NIST)于1997年提出征集该算法的公告。1999年3月22日,NIST从15个候选算法中公布了5个候选算法进入第二轮选择:MARS,RC6,Rijindael,SERPENT和Twofish。

2000年10月2日,以安全性(稳定的数学基础,没有算法弱点,算法抗密码分析的强度,算法输出的随机性)、性能(必须能在多种平台上以较快的速度实现)、大小(不能占用大量的存储空间和内存)、实现特性(灵活行、硬件和软件实行性、算法的简单性等)为标准而最终选定了两个比利时研究者Vincent Rijinmen和Joan Daemen发明的Rijndael算法,并于2001年正式发布了AES标准。

1.2 AES加密算法

AES算法本质上是一种对称分组密码体制,采用代替/置换网络。AES算法主要包括三个方面:轮变化、圈数和密钥扩展。

1.2.1 圈变化

AES每一个圈变换由以下三个层组成:

  • 非线性层——进行Subbyte变换,非线性层由16个S盒并置起到混淆的作用

  • 线行混合层——进行ShiftRow和MixColumn运算,线性混合层确保多轮之上的高度扩散

  • 密钥加层——进行AddRoundKey运算,密钥加密层将子密钥异或到中间状态

Subbyte变换是作用在状态中每个字节上的一种非线性字节转换,可以通过计算出来的S盒进行映射。

ShiftRow是一个字节换位。它将状态中的行按照不同的偏移量进行循环移位。

在MixColumn变换中,把状态中的每一列看作GF(28)上的多项式a(x)与固定多项式c(x)相乘的结果。b(x)=c(x)*a(x)的系数这样计算:*运算不是普通的乘法运算,而是特殊的运算,即 b(x)=c(x) • a(x)(mod x4+1) 算法如下图:

对于逆变化,其矩阵C要改变成相应的D,即b(x)=d(x)\*a(x)。

密钥加层运算(addround)是将圈密钥状态中的对应字节按位“异或”。

根据线性变化的性质,解密运算是加密变化的逆变化。

1.2.2 轮变化

对不同的分组长度,其对应的轮变化次数是不同的,这里要介绍的密钥长度为128位的轮变化数为10轮;密钥长度为192位的轮变化数为12轮;密钥长度为256位的轮变化数为14轮。

1.2.3 密钥扩展

AES算法利用外部输入密钥K(密钥串的字数为Nk),通过密钥的扩展程序得到共计4(Nr+1)字的扩展密钥。它涉及如下三个模块:

  • 位置变换(rotword)——把一个4字节的序列[A,B,C,D]变化成[B,C,D,A];

  • S盒变换(subword)——对一个4字节进行S盒代替;

  • 变换Rcon——Rcon表示32位比特字[xi-1,00,00,00]。这里的x是(02),如 Rcon[1]=[01000000];Rcon[2]=[02000000];Rcon[3]=[04000000]……

扩展密钥的生成:扩展密钥的前Nk个字就是外部密钥K;以后的字W[]等于它前一个字W[i-1]与前第Nk个字W[i-Nk]的“异或”,即W[]=W[i-1]⊕W[i- Nk]。但是若i为Nk的倍数,则W=W[i-Nk]⊕Subword(Rotword(W[i-1]))⊕Rcon[i/Nk]。

2 系统设计

2.1 系统主要目标

基本要求部分:

  • 在深入理解AES加密/解密算法理论的基础上,设计了一个AES加密/解密软件系统

  • 完成一个明文分组的加解密,明文和密钥是十六进制,长度都为128比特(32个16进制数),按照标准输入明文和密钥,输出密文,进行加密后,能够进行正确的解密

  • 程序运行时,输出每一轮使用的密钥,以及每一轮中字节替代、行移位、列混合,密钥加等每一步操作之后的16进制表示的值

较高要求部分:

  • 如果明文不止一个分组,程序能完成分组,然后加密;最后一个分组长度不足时填充0;密钥长度不足时填充0,过长则自动截取前面部分

  • 密钥可以采用16进制ASCII码或英文字符输入,明文输入信息可以是16进制数值或英文,任意字符(不包括汉字),或者是文本文档,进行加密后,能够进行正确的解密

  • 程序代码有比较好的结构,模块划分合理,通过调用类的成员函数实现加密解密功能,函数的参数及返回值设置合理。

  • 界面友好

2.2 主要软件需求(运行环境)

  • 本软件适用VC语言编写,编译成功后的EXE文件可以在装有Windows系统的任何计算机上使用

  • 测试平台:Windows XP Professional

  • 使用软件:Visual C++ 6.0

2.3 功能模块与系统结构

加密/解密的大致结构图

加密/解密主要流程图

3 系统功能程序设计

本程序中用到2张表格:Sbox[256],iSbox[256]和Rcon[32];均采用一维数组存放;明文分组plaintext[16]和初始密钥key[16]也均为一维数组;但在处理过程中仍把Sbox[256]和iSbox[256]看做16行16列的矩阵;把Rcon[32]看做8行4列的矩阵;把plaintext[16]和key[16]看做4行4列的矩阵,则第i行j列的数在一维数组中的位置为4i+j。扩展密钥采用二维数组w[44][4]存放。由于明文和密钥装入数组为顺序装入,即相当于AES算法中按列装入的矩阵的转置,所以进行对应的行变换即应该进行相应的列变换。

3.1 基本要求部分

3.1.1 字节替换

Sbox[256],plaintext[16]均采用一维数组存放,plaintext中存放的为转化为16进制的操作数,进行字节替换时是取plaintext存放的数据的二进制值的高4位做行坐标i,低四位做列坐标j来取Sbox中对应位置的数据替换,而plaintext的值恰好为16i+j,所以plaintext的值即为对应的替换值在Sbox中的位置。

  1. void CAESDlg::SubByte()
  2. {
  3. int i;
  4. for(i=0;i<16;i++)
  5. plaintext[i]=Sbox[plaintext[i]];
  6. }

3.1.2 行移位

Plaintext[16]采用一维数组存放操作数,把它看做每行4列的矩阵,所以第k行i列即为plaintext[4*k+i ]。由于AES采用列存放数据,而这里plaintext采用顺序存放,相当于行存放,即为列存放的转置矩阵,所以进行行移位时即应该进行相应的列移位:

列变换(行移位)情况如下图所示:

  1. void CAESDlg::ShiftUp(int i)
  2. {
  3. int j,k,temp;
  4. for(j=0;j<i;j++)
  5. {
  6. temp=plaintext[i];
  7. for(k=0;k<3;k++)
  8. plaintext[4*k+i]=plaintext[4*(k+1)+i];
  9. plaintext[i+12]=temp;
  10. }
  11. }
  12. void CAESDlg::ShiftRows()
  13. {
  14. int i;
  15. for(i=1;i<4;i++)
  16. ShiftUp(i);
  17. }

3.1.3 列混合

把一维数组plaintext[16]看做4行4列,则i行j列即为4*i+j , 列混合即为两个矩阵相乘,由于AES采用列存放数据,而这里plaintext采用顺序存放,相当于行存放,即为列存放的转置矩阵,所以另一个矩阵也转置,相乘后仍然是AES列混合后的转置矩阵:

相当于下面两个矩阵相乘:

  1. int CAESDlg::gfmultby02(int b)
  2. {
  3. if (b<0x80) //(0x80=OB10000000)
  4. return (b<<1);
  5. else
  6. return (((b<<1)-256)^(0x1b)); //(0X1b=OB00011011)
  7. }
  8. int CAESDlg::gfmultby03(int b)
  9. {
  10. return (gfmultby02(b)^b);
  11. }
  12. void CAESDlg::MixColumns()
  13. {
  14. int i,temp[16];
  15. memcpy(temp,plaintext,64);
  16. for(i=0;i<4;i++)
  17. {
  18. plaintext[4*i]=gfmultby02(temp[4*i+0]) ^ gfmultby03(temp[4*i+1]) ^ temp[4*i+2] ^ temp[4*i+3];
  19. plaintext[4*i+1]=temp[4*i+0] ^ gfmultby02(temp[4*i+1]) ^ gfmultby03(temp[4*i+2]) ^ temp[4*i+3];
  20. plaintext[4*i+2]=temp[4*i+0] ^ temp[4*i+1] ^ gfmultby02(temp[4*i+2]) ^ gfmultby03(temp[4*i+3]) ;
  21. plaintext[4*i+3]=gfmultby03(temp[4*i+0]) ^ temp[4*i+1] ^ temp[4*i+2] ^ gfmultby02(temp[4*i+3]);
  22. }
  23. }

3.1.4 密钥加

密钥w[44][4]依次存的为初始密钥和扩展后的10轮轮变换的密钥,round为加密的轮数,w[4*round+r][c]即为第round轮的密钥第r行c列。把一维数组plaintext看做4行4列,则r行c列即为4*r+c,分别行取值异或,即为密钥加:

  1. void CAESDlg::AddRoundKey(int round)
  2. {
  3. int r,c;
  4. for(r=0;r<4;++r)
  5. for(c=0;c<4;++c)
  6. plaintext[4*r+c]=(plaintext[4*r+c]^w[4*round+r][c]);
  7. }

3.1.5 密钥扩展

rowtem%flag==0时即为每轮密钥开始的行数,它的前一行移位RotWord后查表Sbox再和前4行密钥异或,第一列再和Rcon异或;当不为轮开始的第一行密钥时,直接取前一行和前四行异或:

  1. void CAESDlg::InitKey()
  2. {
  3. int inkey[16];
  4. int temp[4],flag=4;
  5. memcpy(inkey,key,64); //内存COPY函数,(目的,源,大小)
  6. for(int row=0;row<4;row++)
  7. {
  8. w[row][0] = inkey[4*row];
  9. w[row][1] = inkey[4*row+1];
  10. w[row][2] = inkey[4*row+2];
  11. w[row][3] = inkey[4*row+3];
  12. }
  13. for(int rowtem=flag;rowtem<44;rowtem++)
  14. {
  15. temp[0] = w[rowtem-1][0];
  16. temp[1] = w[rowtem-1][1];
  17. temp[2] = w[rowtem-1][2];
  18. temp[3] = w[rowtem-1][3];
  19. if (rowtem%flag==0)
  20. {
  21. RotWord(temp);
  22. SubWord(temp);
  23. temp[0] = (temp[0]^Rcon[rowtem/flag]);
  24. }
  25. // w[row] = w[row-Nk] xor temp
  26. w[rowtem][0] = ( w[rowtem-flag][0] ^ temp[0] );
  27. w[rowtem][1] = ( w[rowtem-flag][1] ^ temp[1] );
  28. w[rowtem][2] = ( w[rowtem-flag][2] ^ temp[2] );
  29. w[rowtem][3] = ( w[rowtem-flag][3] ^ temp[3] );
  30. }//loop
  31. }
  32. void CAESDlg::RotWord(int *word )
  33. {
  34. int temp;
  35. temp=word[0];
  36. word[0] = word[1];
  37. word[1] = word[2];
  38. word[2] = word[3];
  39. word[3] = temp;
  40. }
  41. void CAESDlg::SubWord(int* word )
  42. {
  43. word[0] = Sbox[ (word[0] >> 4)*16+(word[0] & 0x0f)];
  44. word[1] = Sbox[ (word[1] >> 4)*16+(word[1] & 0x0f)];
  45. word[2] = Sbox[ (word[2] >> 4)*16+(word[2] & 0x0f)];
  46. word[3] = Sbox[ (word[3] >> 4)*16+(word[3] & 0x0f)];
  47. }

3.1.6 逆字节替换

与字节替代类似,iSbox[256],plaintext[16]均采用一维数组存放,plaintext中存放的为转化为16进制的操作数,进行字节替换时是取plaintext存放的数据的二进制值的高4位做行坐标i,低四位做列坐标j来取iSbox中对应位置的数据替换,而plaintext的值恰好为16i+j,所以plaintext的值即为对应的逆替换值在iSbox中的位置。

  1. void CAESDlg::InvSubBytes()
  2. {
  3. int i;
  4. for(i=0;i<16;i++)
  5. plaintext[i]=iSbox[plaintext[i]];
  6. }

3.1.7 逆行移位

与行移位类似,Plaintext[16]采用一维数组存放操作数,把它看做每行4列的矩阵,所以第k行i列即为plaintext[4*k+i ]。由于AES采用列存放数据,而这里plaintext采用顺序存放,相当于行存放,即为列存放的转置矩阵,所以进行逆行移位时即应该进行相应的逆列移位:

逆列变换(逆行移位)情况如下图所示:

  1. void CAESDlg::ShiftDown(int i)
  2. {
  3. int j,k,temp;
  4. for(j=0;j<i;j++)
  5. {
  6. temp=plaintext[12+i];
  7. for(k=2;k>=0;k--)
  8. plaintext[4*(k+1)+i]=plaintext[4*k+i];
  9. plaintext[i]=temp;
  10. }
  11. }
  12. void CAESDlg::InvShiftRows()
  13. {
  14. int i;
  15. for(i=1;i<4;i++)
  16. ShiftDown(i);
  17. }

3.1.8 逆列混合

与列混合类似,把一维数组plaintext[16]看做4行4列,则i行j列即为4*i+j , 逆列混合即为两个矩阵相乘,由于AES采用列存放数据,而这里plaintext采用顺序存放,相当于行存放,即为列存放的转置矩阵,所以另一个矩阵也转置,相乘后仍然是AES列混合后的转置矩阵:

相当于下面两个矩阵相乘:

  1. int CAESDlg::gfmultby09(int b)
  2. {
  3. return (gfmultby02(gfmultby02(gfmultby02(b)))^b );
  4. }
  5. int CAESDlg::gfmultby0b(int b)
  6. {
  7. return (gfmultby02(gfmultby02(gfmultby02(b)))^gfmultby02(b)^b);
  8. }
  9. int CAESDlg::gfmultby0d(int b)
  10. {
  11. return (gfmultby02(gfmultby02(gfmultby02(b)))^gfmultby02(gfmultby02(b))^(b));
  12. }
  13. int CAESDlg::gfmultby0e(int b)
  14. {
  15. return (gfmultby02(gfmultby02(gfmultby02(b)))^gfmultby02(gfmultby02(b))^gfmultby02(b) );
  16. }
  17. void CAESDlg::InvMixColumns()
  18. {
  19. int i,temp[16];
  20. memcpy(temp,plaintext,64);
  21. for(i=0;i<4;i++)
  22. {
  23. plaintext[4*i]=gfmultby0e(temp[4*i+0]) ^ gfmultby0b(temp[4*i+1]) ^ gfmultby0d(temp[4*i+2]) ^ gfmultby09(temp[4*i+3]);
  24. plaintext[4*i+1]=gfmultby09(temp[4*i+0]) ^ gfmultby0e(temp[4*i+1]) ^ gfmultby0b(temp[4*i+2]) ^ gfmultby0d(temp[4*i+3]);
  25. plaintext[4*i+2]=gfmultby0d(temp[4*i+0]) ^ gfmultby09(temp[4*i+1]) ^ gfmultby0e(temp[4*i+2]) ^ gfmultby0b(temp[4*i+3]) ;
  26. plaintext[4*i+3]=gfmultby0b(temp[4*i+0]) ^ gfmultby0d(temp[4*i+1]) ^ gfmultby09(temp[4*i+2]) ^ gfmultby0e(temp[4*i+3]);
  27. }
  28. }

3.1.9 加密

先一轮密钥加AddRoundKey(0),再进入主循环,依次进行字节替换SubByte()、行移位ShiftRows()、列混合MixColumns()、密钥加AddRoundKey(round)运算,循环9次,再做一次字节替代SubByte()、行移位ShiftRows()、密钥加AddRoundKey(Nr)运算,完成加密:

  1. void CAESDlg::Cipher()
  2. {
  3. ……
  4. AddRoundKey(0);
  5. for (int round = 1; round < Nr; ++round) // main round loop
  6. {
  7. SubByte();
  8. ShiftRows();
  9. MixColumns();
  10. AddRoundKey(round);
  11. } // main round loop
  12. SubByte();
  13. ShiftRows();
  14. AddRoundKey(Nr);
  15. }

3.1.10 解密

先一轮密钥加AddRoundKey(Nr),再进入主循环,依次进行逆行移位InvShiftRows()、逆字节替换InvSubBytes()、密钥加AddRoundKey(round)、逆列混合InvMixColumns()运算,循环9次,再做一次逆行移位InvShiftRows()、逆字节替代InvSubBytes()、密钥加AddRoundKey(0)运算,完成解密:

  1. void CAESDlg::InvCipher()
  2. {
  3. AddRoundKey(Nr);
  4. for (int round=Nr-1;round>=1;round--) // main round loop
  5. {
  6. InvShiftRows();
  7. InvSubBytes();
  8. AddRoundKey(round);
  9. InvMixColumns();
  10. } // main round loop
  11. InvShiftRows();
  12. InvSubBytes();
  13. AddRoundKey(0);
  14. }

3.2 较高要求部分

3.2.1 明文分组实现

输入的明文存在m_text中,length为输入的明文的总长度,每次循环Cipher()只处理128位,长于128位的暂不处理,留作下一轮处理,不足128位的在Cipher()处理的过程中已做了填充处理;每轮k加1,tag*k就指向m_text中没处理的明文的第一个字符,经过变换后,temp中的存放的就为没处理的明文,再将temp中的前128位取出处理,依次循环直到最后处理完明文为止。

  1. void CAESDlg::OnBUTTONCipher()
  2. {
  3. ……………..
  4. do{
  5. temp="";
  6. Cipher();
  7. Show();
  8. k++;
  9. if(length>tag*k)
  10. {
  11. for(int i=0;i<tag&&i<length-tag*k;i++)
  12. {
  13. test.Format("%c",m_text[tag*k+i]);
  14. temp+=test;
  15. }
  16. if(m_RadioInputTextHex==0)
  17. InputHex(temp,plaintext,Nb);
  18. else
  19. CharToHex(temp,plaintext,Nb);
  20. }
  21. }while(length>tag*k);
  22. …………………
  23. }

3.2.2 明文最后分组的填充

明文首先是以字符串形式读入的,每次处理一个分组,处理时再根据相应的输入模式调用相应的函数在字符串中取值存到plaintext[16]数组中进行处理。

当为字符输入模式时,调用CharToHex()函数,每次处理取字符串的前16个字符换成ASCII码作为一个分组进行处理,直到最后一个分组,若不足16个字符,不足部分填充0;
当为16进制输入模式时,调用InputHex ()函数,每次处理取字符串的前32个字符换成相应的16进制代码进行处理,直到最后一个分组,若不足32个字符时,不足部分填充0;

  1. void CAESDlg::CharToHex(CString str,int *array,int n)
  2. {
  3. int i;
  4. for(i=0;i<str.GetLength()&&i<n;i++)
  5. array[i]=str[i];
  6. if(str.GetLength()<Nb)
  7. for(i=str.GetLength();i<n;i++)
  8. array[i]=0;
  9. }
  10. void CAESDlg::InputHex(CString strCS,int *array,int n)
  11. {
  12. int i,high[16],low[16];
  13. string str;
  14. str=strCS;
  15. for(i=0;i<n;i++)
  16. {
  17. if(str[2*i]>=47 && str[2*i]<=57)
  18. high[i]=(int)str[2*i]-48;
  19. else if(str[2*i]>=65 && str[2*i]<=70)
  20. high[i]=(int)str[2*i]-55;
  21. else if(str[2*i]>=97 && str[2*i]<=102)
  22. high[i]=(int)str[2*i]-87;
  23. else
  24. high[i]=0;
  25. if(str[2*i+1]>=47 && str[2*i+1]<=57)
  26. low[i]=(int)str[2*i+1]-48;
  27. else if(str[2*i+1]>=65 && str[2*i+1]<=70) //大写字母A--F
  28. low[i]=(int)str[2*i+1]-55;
  29. else if(str[2*i+1]>=97 && str[2*i+1]<=102) //小写字母a---f
  30. low[i]=(int)str[2*i+1]-87;
  31. else
  32. low[i]=0;
  33. }
  34. for(i=0;i<n;i++)
  35. array[i]=high[i]*16+low[i];
  36. }

3.2.3 密钥的填充与截取

密钥的填充与明文的填充类似,不同的是密钥只处理一个分组。

当为字符输入模式时,调用CharToHex()函数处理,若密钥长度不足16个字符时,在把密钥换成16进制ASCII码存入key[16]数组中后,不足部分填充0,填满后作为一个密钥再进行相应的处理,实现密钥的填充;若密钥长度大于16,则只取前16个字符换成16进制ASCII码存入key[16]数组中作为一个密钥,忽略后面的字符,实现密钥的截取;

当为16进制输入模式时,调用InputHex ()函数处理,若密钥长度不足32个字符时,在把密钥换成16进制代码存入key[16]数组中后,不足部分填充0,填满后作为一个密钥再进行相应的处理,实现密钥的填充;若密钥长度大于32,则只取取前32个字符换成16进制代码存入key[16]数组中作为一个密钥,忽略后面的字符,实现密钥的截取;

3.2.4 文本文件加密

文本文件加密与字符加密大致相同。从文本文件中读入字符串,相当于字符加密的字符输入模式,然后再调用相应的加密函数对字符串进行分组加密,加密结果输出为16进制值,加密结束后再把加密结果写入一个新的文本文件(加密文件Hex.txt)中,完成文本文件的加密。

  1. void CAESDlg::OnBUTTONFileCipher()
  2. {
  3. ………………………………..
  4. FileInitialize();
  5. CharToHex(m_FileData,plaintext,Nb);
  6. InitKey();
  7. m_progress.SetPos(50);
  8. tag=Nb;
  9. strFileHex="";
  10. do{
  11. temp="";
  12. CipherFile();
  13. for(i=0;i<Nb;i++)
  14. {
  15. test.Format("%02x",plaintext[i]);
  16. strFileHex+=test;
  17. }
  18. k++;
  19. if(length>tag*k)
  20. {
  21. for(int i=0;i<tag&&i<length-tag*k;i++)
  22. {
  23. test.Format("%c",m_FileData[tag*k+i]);
  24. temp+=test;
  25. }
  26. CharToHex(temp,plaintext,Nb);
  27. }
  28. }while(length>tag*k);
  29. ……………………….
  30. }

3.2.5 文本文件解密

文本文件解密与字符解密大致相同。从文本文件中读入字符串,相当于字符解密的16进制输入模式,然后再调用相应的解密函数对字符串进行相应的分组解密,解密结果输出为字符型,解密结束后再把解密结果写入一个新的文本文件(解密文件Char.txt)中,完成文本文件的解密。

  1. void CAESDlg::OnBUTTONFileInvCipher()
  2. {
  3. ……………………….
  4. FileInitialize();
  5. InputHex(m_FileData,plaintext,Nb);
  6. InitKey();
  7. m_progress.SetPos(50);
  8. tag=Nb*2;
  9. strFileChar="";
  10. do{
  11. temp="";
  12. InvCipherFile();
  13. for(i=0;i<Nb;i++)
  14. {
  15. test.Format("%c",plaintext[i]);
  16. strFileChar+=test;
  17. }
  18. k++;
  19. if(length>tag*k)
  20. {
  21. for(int i=0;i<tag&&i<length-tag*k;i++)
  22. {
  23. test.Format("%c",m_FileData[tag*k+i]);
  24. temp+=test;
  25. }
  26. InputHex(temp,plaintext,Nb);
  27. }
  28. }while(length>tag*k);
  29. ………………………….
  30. }

3.3 程序界面预览

为方便测试,设置明文和密钥的默认值为标准值。

待处理的文本框输入明文或密文进行加密或解密;可以选择为16进制输入或字符输入;密钥输入框输入加密或解密密钥,可以选择为16进制输入或字符输入。若选择为16进制模式输入,若不为有效的16进制代码,则当做0处理;若选择为字符模式输入,可以输入任意英文字符。

输入待处理明文/密文后,点击加密按钮或解密按钮进行加密或解密处理。

处理后的结果有两种显示方法,即16进制显示(显示处理后的16进制值)和字符显示(显示处理后的16进制值对应的字符);

两个换序按钮能方便的分别将处理后的两个结果框中对应的字符换到待处理的文本框中,进行验证加密/解密的正确性,或再进行多次加密处理。

右边中间输出结果框显示了每一轮使用的密钥,以及每一轮中字节替代、行移位、列混合,密钥加等每一步操作之后的16进制表示的值。

进度条显示加密的进度。

初始化按钮能回到最初的默认状态。方便测试。

文本加密,点击浏览按钮来选择文本路径。

文件加密密钥输入同字符加密的密钥输入一样,可以选择为16进制输入或字符输入,输入密钥对文本文档进行处理。

选择了文本文档路径,输入了文件加密/解密密钥后,点击对应的加密或解密按钮,进行文本文件加密或解密处理。

4 测试报告

4.1 字符加密/解密检测:

  • 明文:00112233445566778899aabbccddeeff (16进制输入模式)

  • 密钥:000102030405060708090a0b0c0d0e0f (16进制输入模式)

  • 加密结果:69c4e0d86a7b0430d8cdb78070b4c55a (16进制表示)

对照标准,输入明文和密钥,经过加密后运行结果与标准相同,中间每步的处理结果也与标准相同,按下16进制显示框对应的换序按钮,再进行相应的解密能得到正确的明文。

将Text输入方式和key输入方式换成字符输入模式,在明文输入框和密钥输入框中均输入超过1个分组长度的英文字符(包括英文特殊字符)进行加密:

明文

密钥

加密结果

点击16进制显示框对应的换序按钮,把加密结果的16进制值换到待处理文本输入框中进行解密:

密文

密钥

解密结果

将明文和密钥的输入方式换成字符输入模式,在明文输入框和密钥输入框中均输入超过1个分组长度的英文字符(包括英文特殊字符)进行加密,用加密得到的16进制值(在16进制显示框中)进行解密,能得到正确的字符(在字符显示框中显示)。

4.2 文本文档加密/解密检测

test.txt文件内容

文件加密

加密结果

解密

解密结果

经过检测:

  • 本软件能对字符和文本文档进行正确的加密和解密,加密和解密结果没有错误

  • 对于不足128bit的明文分组,最后填充0补满128bit

  • 对于不足128bit的密钥,填充0补满128bit;对于超过128bit的密钥,只截取前128bit

  • 没有发现导致致命错误的操作方法

5 结论

通过这次的课程设计,对AES的算法有了更深入的了解:字节代换的仿射变换可用S盒表示;对于不同的分组行移位也是不同的;列混合中的计算则要用到GF(28)上的多项式,再与一个固定的多项式C(x)进行模X4+1的乘法,而C(x)是固定的,而且最后一轮没用列混合。虽然此软件能顺利完成对英文字符和文本文档的加密,但也还存在很多不足,如:不能对汉字进行处理,不能处理其他格式的文件、文件夹等,只支持128bit的密钥,没有实现192bit,256bit密钥长度的加密,还需要进一步完善。

参考文献

[1] 谭浩强. C程序设计(第二版). 清华大学出版社. 1999

[2] 张海藩. 软件工程导论(第四版). 清华大学出版社. 2003

[3] 杨波. 现代密码学. 清华大学出版社. 2003

[4] 黄维通. Visual C++面向对象与可视化程序设计. 清华大学出版社. 2000

[5] 张福泰. 密码学教程(第一版). 武汉大学出版社. 2006

上传的附件 cloud_download 基于VC++的MFC类库的AES加密解密程序.7z ( 226.68kb, 130次下载 )
error_outline 下载需要11点积分

发送私信

放空的心,是最好的礼物;独走的路,是最美的风景

9
文章数
14
评论数
最近文章
eject