目录
AES算法实验
一、实验目的
深刻掌握AES算法的运行原理
掌握对称密码工作模式
编程实现支持多种工作模式和填充方式的AES加解密程序
二、实验内容
完成AES加解密程序编写。
三、实验原理
AES(高级加密标准)是一种对称加密算法,广泛用于数据加密和保护。它的原理可以概括为以下几个关键点:
对称加密:AES使用相同的密钥进行加密和解密,这意味着发送方和接收方必须安全地共享该密钥。
分组加密:AES对数据进行分组处理,每个分组为128位(16字节)。较大的数据会被分成多个分组进行加密。
密钥长度:AES支持三种密钥长度:128位、192位和256位,密钥长度越长,安全性越高。
加密过程:AES的加密过程分为多个轮次(rounds),根据密钥长度不同,轮次数为:
10轮(128位密钥)
12轮(192位密钥)
14轮(256位密钥)
每一轮包括以下步骤:
字节替换(SubBytes):使用S-Box替换每个字节。
行移位(ShiftRows):对行进行循环左移。
列混合(MixColumns):对列进行线性变换,增强扩散性(最后一轮不进行此步骤)。
轮密钥加(AddRoundKey):将当前状态与轮密钥进行异或运算
解密过程:解密过程与加密相反,步骤顺序调整,并使用反向操作(反S-Box、行反移位、列反混合、轮密钥加)。
四、实验步骤
4.1 AES加解密流程设计
4.2 test流程设计(AES调用程序)
4.3存储格式设计
4.3.1 S盒与逆S盒
本次实验中的S盒使用unsigned char数组,非程序生成。
4.3.2 明文设计
本次实验设计中,明文以字符串的形式输入test程序中,在test程序中转换为16进制数存储在[4][4]大小的矩阵中,将16进制状态矩阵以参数形式传送至AES算法中进行加解密运算。
4.3.3 密钥设计
本次实验设计中,密钥以字符串的形式输入test程序中,在test程序中转换为16进制数存储在[4][4]大小的矩阵中,在AES扩展算法后转换为[44][4]大小的矩阵存储,和正常的轮密钥相比,每一个子密钥的行、列其实是相反的,在使用时利用[j][i]的形式调用,以保证正常的加解密。
4.4 实验过程
4.4.1 S盒测试
输入16位16进制数,测试S盒和逆S盒可以正常转换
4.4.2 单轮加密测试
进行单论数据测试,测试课本案例,得到相同结论。
4.4.3 加密测试
进行10轮加密后得到
4.4.4 解密测试
进行10轮解密后得到
4.4.5 test文件测试
4.5 实验难点及解决
4.5.1 字符转16进制
使用include <sstream>库函数,将字符串中的每两个字符转换为一个十六进制数字。
4.5.2 明文及密钥存储格式
由于涉及到异或运算,采用二维数组的存储方式利于计算、移位、代码阅读。
但是扩展密钥存储时,若按照[4]*[44]的方式进行存储,则不方便进行轮运算,若按照[44]*[4]存储,则进行密钥扩展时,按实际的存储方式是按照行进行的,但是在进行轮加密运算时,要注意行列区别
下图是测试案例中轮密钥实际的存储形式:
下图是明文矩阵的存储形式:
附录:AES加密程序代码
1.AES.h
#pragma once
#include <iostream>
#include <iomanip>
#include <cstdint>
#include <sstream>
#include"AES.h"
using namespace std;
// 轮密钥加
void AddRoundKey(int round, uint8_t state[4][4], uint8_t roundKey[44][4]);
// S-Box字节替换
void SubBytes(uint8_t state[4][4]);
// 行移位
void ShiftRows(uint8_t state[4][4]);
// 把十六进制字符串转换为矩阵(按列填入)
void hexStringToStateMatrix(const string& input, uint8_t state[4][4]);
//矩阵转为十六进制字符串
string stateMatrixToHexString(const uint8_t state[4][4]);
// GF(2^8) 中的乘法
uint8_t gmul(uint8_t a, uint8_t b);
// 列混淆(MixColumns)
void MixColumns(uint8_t state[4][4]);
//打印矩阵
void printmatrix(uint8_t state[4][4]);
// 密钥扩展函数
void KeyExpansion(uint8_t key[4][4], uint8_t expandedKeys[44][4]);
// AES加密函数
void AES_Encrypt(uint8_t state[4][4], uint8_t expandedKeys[44][4]);
// 逆S-Box字节替换
void InvSubBytes(uint8_t state[4][4]);
// 逆行移位
void InvShiftRows(uint8_t state[4][4]);
// 逆列混淆(InvMixColumns)
void InvMixColumns(uint8_t state[4][4]);
// AES解密函数
void AES_Decrypt(uint8_t state[4][4], uint8_t expandedKeys[44][4]);
void SBoxFill();
2.Test.h
#pragma once
#include"AES.h"
#include"test.h"
//从文件中读出明文
bool readPlaintext(const string& filename, string& plaintext);
//从文件中读出密文
bool readKey(const string& filename, string& key);
//将解密后的字符串写入文件中
bool writeHexString(const string& filename, const string& hexString);
int text();
3.AES.cpp
#include "AES.h"
/*————————————————两个S盒————————————————*/
//定义AES的加密S盒
unsigned char SBox[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
};
//定义AES的解密逆S盒
unsigned char InvSBox[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
};
// 轮密钥加
void AddRoundKey(int round,uint8_t state[4][4], uint8_t roundKey[44][4]) {
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
state[j][i] ^= roundKey[round * 4 + i][j];
}
}
}
// S-Box字节替换
void SubBytes(uint8_t state[4][4]) {
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
state[i][j] = SBox[state[i][j]];
}
}
}
// 行移位
void ShiftRows(uint8_t state[4][4]) {
uint8_t temp;
// 第二行左移一位
temp = state[1][0];
for (int i = 0; i < 3; ++i)
state[1][i] = state[1][i + 1];
state[1][3] = temp;
// 第三行左移两位
for (int i = 0; i < 2; ++i) {
temp = state[2][i];
state[2][i] = state[2][i + 2];
state[2][i + 2] = temp;
}
// 第四行左移三位
temp = state[3][3];
for (int i = 3; i > 0; --i)
state[3][i] = state[3][i - 1];
state[3][0] = temp;
}
// 把十六进制字符串转换为矩阵(按列填入)
void hexStringToStateMatrix(const string& input, uint8_t state[4][4]) {
for (int i = 0; i < 16; ++i) {
// 每次取两个字符,转换为一个字节
stringstream ss;
ss << hex << input.substr(2 * i, 2);
int val;
ss >> val;
state[i % 4][i / 4] = static_cast<uint8_t>(val); // 按列填入
}
}
//矩阵转为十六进制字符串
string stateMatrixToHexString(const uint8_t state[4][4]) {
stringstream ss;
for (int col = 0; col < 4; ++col) { // 按列读取
for (int row = 0; row < 4; ++row) {
ss << hex << setw(2) << setfill('0') << static_cast<int>(state[row][col]);
}
}
return ss.str();
}
// GF(2^8) 中的乘法
uint8_t gmul(uint8_t a, uint8_t b) {
uint8_t p = 0;
uint8_t hi_bit_set;
for (int i = 0; i < 8; ++i) {
if (b & 1)
p ^= a;
hi_bit_set = a & 0x80;
a <<= 1;
if (hi_bit_set)
a ^= 0x1b; // AES 中的不可约多项式
b >>= 1;
}
return p;
}
// 列混淆(MixColumns)
void MixColumns(uint8_t state[4][4]) {
uint8_t temp_state[4][4];
for (int c = 0; c < 4; ++c) {
temp_state[0][c] = gmul(0x02, state[0][c]) ^ gmul(0x03, state[1][c]) ^ state[2][c] ^ state[3][c];
temp_state[1][c] = state[0][c] ^ gmul(0x02, state[1][c]) ^ gmul(0x03, state[2][c]) ^ state[3][c];
temp_state[2][c] = state[0][c] ^ state[1][c] ^ gmul(0x02, state[2][c]) ^ gmul(0x03, state[3][c]);
temp_state[3][c] = gmul(0x03, state[0][c]) ^ state[1][c] ^ state[2][c] ^ gmul(0x02, state[3][c]);
}
// 将结果拷贝回原始状态矩阵
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
state[i][j] = temp_state[i][j];
}
}
}
//打印矩阵
void printmatrix(uint8_t state[4][4]) {
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
cout << hex << setw(2) << setfill('0') << (int)state[i][j] << " ";
}
cout << endl;
}
}
uint8_t Rcon[10] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36 }; // 轮常数
// 密钥扩展函数
void KeyExpansion(uint8_t key[4][4], uint8_t expandedKeys[44][4]) {
// 将原始密钥复制到expandedKeys的前四个字中
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
expandedKeys[i][j] = key[j][i];
}
}
// 每一轮扩展
for (int i = 4; i < 44; ++i) {
uint8_t temp[4];
// 从前一个字生成temp
for (int j = 0; j < 4; ++j) {
temp[j] = expandedKeys[i - 1][j];
}
// 每四轮进行特殊变换
if (i % 4 == 0) {
// 字循环
uint8_t t = temp[0];
temp[0] = temp[1];
temp[1] = temp[2];
temp[2] = temp[3];
temp[3] = t;
// S盒替换
for (int j = 0; j < 4; ++j) {
temp[j] = SBox[temp[j]];
}
// 轮常数异或
temp[0] ^= Rcon[(i / 4) - 1];
}
// 扩展密钥
for (int j = 0; j < 4; ++j) {
expandedKeys[i][j] = expandedKeys[i - 4][j] ^ temp[j];
}
}
}
// AES加密函数
void AES_Encrypt(uint8_t state[4][4], uint8_t expandedKeys[44][4]) {
// 初始轮密钥加
AddRoundKey(0,state, expandedKeys);
// 进行10轮加密
for (int round = 1; round <= 10; ++round) {
// SubBytes
SubBytes(state);
// ShiftRows
ShiftRows(state);
// 只有前9轮进行MixColumns
if (round < 10) {
MixColumns(state);
}
// 添加轮密钥
AddRoundKey(round,state, expandedKeys);
}
}
// 逆S-Box字节替换
void InvSubBytes(uint8_t state[4][4]) {
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
state[i][j] = InvSBox[state[i][j]];
}
}
}
// 逆行移位
void InvShiftRows(uint8_t state[4][4]) {
uint8_t temp;
// 第四行左移一位
temp = state[3][0];
for (int i = 0; i < 3; ++i)
state[3][i] = state[3][(i +1)%4];
state[3][3] = temp;
// 第三行右移两位
for (int i = 0; i < 2; ++i) {
temp = state[2][3 - i];
state[2][3 - i] = state[2][1 - i];
state[2][1 - i] = temp;
}
// 第二行右移三位
temp = state[1][3];
for (int i = 3; i > 0; --i)
state[1][i] = state[1][i - 1];
state[1][0] = temp;
}
// 逆列混淆(InvMixColumns)
void InvMixColumns(uint8_t state[4][4]) {
uint8_t temp_state[4][4];
for (int c = 0; c < 4; ++c) {
temp_state[0][c] = gmul(0x0E, state[0][c]) ^ gmul(0x0B, state[1][c]) ^ gmul(0x0D, state[2][c]) ^ gmul(0x09, state[3][c]);
temp_state[1][c] = gmul(0x09, state[0][c]) ^ gmul(0x0E, state[1][c]) ^ gmul(0x0B, state[2][c]) ^ gmul(0x0D, state[3][c]);
temp_state[2][c] = gmul(0x0D, state[0][c]) ^ gmul(0x09, state[1][c]) ^ gmul(0x0E, state[2][c]) ^ gmul(0x0B, state[3][c]);
temp_state[3][c] = gmul(0x0B, state[0][c]) ^ gmul(0x0D, state[1][c]) ^ gmul(0x09, state[2][c]) ^ gmul(0x0E, state[3][c]);
}
// 将结果拷贝回原始状态矩阵
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
state[i][j] = temp_state[i][j];
}
}
}
// AES解密函数
void AES_Decrypt(uint8_t state[4][4], uint8_t expandedKeys[44][4]) {
// 进行10轮解密
for (int round = 10; round >= 1; --round) {
// 逆行密钥
AddRoundKey(round, state, expandedKeys);
// 逆列混淆
if (round <=9) {
InvMixColumns(state);
}
InvShiftRows(state);
// 逆S-Box替代
InvSubBytes(state);
}
AddRoundKey(0, state, expandedKeys);
}
4.test.cpp
#include"AES.h"
#include <fstream>
#include <string>
//从文件中读出明文
bool readPlaintext(const string& filename, string& plaintext) {
ifstream inputFile(filename);
if (inputFile.is_open()) {
getline(inputFile, plaintext);
inputFile.close();
return true;
}
return false;
}
//从文件中读出密文
bool readKey(const string& filename, string& key) {
ifstream inputFile(filename);
if (inputFile.is_open()) {
// 跳过第一行(明文)
string dummy;
getline(inputFile, dummy);
getline(inputFile, key);
inputFile.close();
return true;
}
return false;
}
//将解密后的字符串写入文件中
bool writeHexString(const string& filename, const string& hexString) {
ofstream outputFile(filename, ios::app); // 以追加模式打开文件
if (outputFile.is_open()) {
outputFile << hexString << endl;
outputFile.close();
return true;
}
return false;
}
//测试
int text() {
string filename;
string plaintext;
string key;
cout << "请输入文件名: ";
cin >> filename;
if (readPlaintext(filename, plaintext) && readKey(filename, key)) {
// 检查明文和密钥长度
if (plaintext.length() == 32 && key.length() == 32) {
cout << "明文: " << plaintext << endl;
cout << "密钥: " << key << endl;
}
else {
cout << "文件内容格式不正确,明文和密钥应为16字节(32个十六进制字符)。" << endl;
}
}
else {
cout << "无法打开文件或读取内容,请检查文件名是否正确。" << endl;
}
// 定义AES状态矩阵(4x4字节)
uint8_t state[4][4];
uint8_t roundKey[4][4];
uint8_t expandedKeys[44][4];
// 将输入转换为状态矩阵
hexStringToStateMatrix(plaintext, state);
hexStringToStateMatrix(key, roundKey);
KeyExpansion(roundKey, expandedKeys);
AES_Encrypt(state, expandedKeys);
AES_Decrypt(state, expandedKeys);
string hexString = stateMatrixToHexString(state);
cout << "Hex String: " << hexString << endl;
if (hexString.length() == 32) {
if (writeHexString(filename, hexString)) {
cout << "已成功将hexString写入文件!" << endl;
}
else {
cout << "写入文件失败。" << endl;
}
}
else {
cout << "输入的hexString应为16字节(32个十六进制字符)。" << endl;
}
return 0;
}
5.main.cpp
#include"test.h"
int main() {
text();
return 0;
}