QT-小工具基于AES-128计算CMAC值
前言
简单使用Qt来开发一款小工具,实现计算一个二进制文件的CMAC值,用户通过选择一个二进制文件,然后输入密钥key值,来计算CMAC值,本篇文章会将实现的代码给出,也会简单的去介绍一下什么是AES加密和CAMC。接下来直接进入正题。
AES
AES(Advanced Encryption Standard)是一种对称加密算法,被广泛应用于保护敏感数据的安全性。AES的设计目标是提供高度的安全性,并且在各种设备上都能高效运行。
AES算法有三个固定的密钥长度:128比特、192比特和256比特。其中,AES-128使用128比特(16字节)的密钥长度。下面是AES-128的一些关键特点:
1、密钥长度: AES-128使用128比特(16字节)的密钥,这是算法的基本安全性级别。密钥的长度直接影响到算法的安全性,较长的密钥一般能提供更高的安全性,但也会增加计算复杂度。
2、分组长度: AES-128将数据分成128比特(16字节)的块进行加密。这是AES算法中的固定分组长度。
3、轮数: AES-128使用10轮的加密迭代。每一轮都涉及不同的运算,包括替代字节、行移位、列混淆和轮密钥加。这些运算共同增强了算法的安全性。
4、替代字节(SubBytes): 在替代字节阶段,每个字节都会被替换为一个预定义的字节,通过S盒(Substitution Box)进行替换。这一步增加了算法的非线性性,提高了安全性。
5、行移位(ShiftRows): 在行移位阶段,AES-128中的每一行都会按照固定的规则进行循环左移。这个步骤有助于增加数据的混淆度。
6、列混淆(MixColumns): 列混淆是一个线性变换,通过将每一列与一个固定矩阵相乘,增加了算法的复杂性。
7、轮密钥加(AddRoundKey): 在每一轮中,轮密钥都会与数据块进行按位异或的操作。轮密钥是从主密钥扩展而来,通过一系列密钥扩展算法生成。
CMAC
CMAC(Cipher-based Message Authentication Code)是一种基于密码的消息认证码算法。它是一种确定性的密钥相关函数,用于计算消息的认证码以验证消息的完整性和真实性。CMAC是从CBC-MAC(Cipher Block Chaining Message Authentication Code)演变而来的,但在设计上解决了一些安全性问题。
CMAC主要有两个阶段:生成和验证。
生成阶段:
输入消息和密钥。
使用加密算法对消息进行处理,产生一个固定长度的认证码。
验证阶段:
输入消息、密钥和认证码。
使用加密算法对消息进行处理,产生一个新的认证码。
将生成的认证码与输入的认证码进行比较。如果两者匹配,消息被验证为完整和真实。
CMAC提供了一种安全的方式来对消息进行认证,而不需要使用数字签名。它适用于各种应用,如网络通信、文件传输等,以确保消息在传输过程中没有被篡改。
CMAC的一种具体实现是使用AES(Advanced Encryption Standard)算法,因此在某些上下文中,CMAC也被称为AES-CMAC。
实现
openssl
OpenSSL 是一个开源的密码学工具包,提供了一系列的加密算法和安全通信协议的实现。它支持多种操作系统,包括类Unix系统(如Linux和BSD)以及Windows。以下是 OpenSSL 的一些主要特点和用法:
加密算法: OpenSSL 提供了一系列加密算法,包括对称加密算法(如AES、DES、3DES)、非对称加密算法(如RSA、DSA、ECDSA)、哈希函数(如MD5、SHA-1、SHA-256)等。这些算法可以用于数据加密、数字签名、消息认证码等。
SSL/TLS 协议: OpenSSL 实现了 SSL(Secure Sockets Layer)和 TLS(Transport Layer Security)协议,用于安全的网络通信。它支持多个协议版本,包括 SSLv2、SSLv3、TLSv1、TLSv1.1、TLSv1.2、TLSv1.3。SSL/TLS 协议用于在客户端和服务器之间建立加密通信通道,确保数据的机密性和完整性。
命令行工具: OpenSSL 提供了一些命令行工具,其中最常用的是 openssl 命令。通过 openssl 命令,用户可以执行各种操作,如生成密钥对、创建数字证书、进行加密解密操作等。
calculateFileCMAC
当用户在界面上选择文件后会执行此函数。
参数:
key:密钥,长度为 AES_BLOCK_SIZE。
filePath:需要计算 CMAC 的文件路径。
操作步骤:
1、打开文件,读取文件中的所有数据。
2、如果文件数据的长度小于 64KB,进行填充,填充数据为 0xFF。
3、调用 calculateCMAC 函数计算文件的 CMAC,并返回结果。
calculateCMAC
将文件数据读出后会执行此函数
参数:
key:密钥,长度为 AES_BLOCK_SIZE(一般为 16 字节)。
data:需要计算 CMAC 的数据。
操作步骤:
检查密钥长度是否正确,如果不正确则输出错误信息并返回空 QByteArray。
创建一个 CMAC 上下文(CMAC_CTX)。
对输入的数据进行字节序翻转(每四个字节翻转一次)。
使用 OpenSSL 函数 CMAC_Init 初始化 CMAC 上下文,指定使用 AES-128-CBC 算法。
使用 CMAC_Update 更新 CMAC 上下文,将数据添加到计算中。
使用 CMAC_Final 完成 CMAC 计算,得到最终的认证码。
将认证码转换为 QByteArray 类型的结果。
释放 CMAC 上下文。
文件处理:
根据原始文件路径创建新的文件路径,将文件复制到新路径。
在新文件中追加计算得到的 CMAC。
将计算得到的 CMAC 以十六进制形式显示在界面的文本编辑框中。
创建一个新文件,将翻转后的数据写入新文件中。
关键代码
calculateFileCMAC:
QByteArray cmacopenssl::calculateFileCMAC(const QByteArray &key, const QString &filePath)
{
QByteArray result;
// Read the content of the file
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly)) {
qDebug() << "Failed to open file:" << file.errorString();
return result;
}
//qint64 fileSize = file.size();
QByteArray fileData = file.readAll();
file.close();
//fileData = QByteArray::fromHex("aaaaaaaaaa");
// Calculate CMAC for the file data
// Check the length of the fileData
qint64 dataSize = fileData.size();
qint64 paddingSize = 64 * 1024 - dataSize;
// Check if padding is needed
if (paddingSize > 0) {
QByteArray paddingData(paddingSize, '\xff');
//fileData.append(paddingData);
}
//qDebug()<<fileData.toHex();
qDebug()<<"size: "<<fileData.size();
qDebug()<<fileData.toHex();
result = calculateCMAC(key, fileData);
return result;
}
calculateCMAC:
QByteArray cmacopenssl::calculateCMAC(const QByteArray &key, const QByteArray &data)
{
QByteArray result;
// Check key length
if (key.length() != AES_BLOCK_SIZE) {
qDebug() << "Key length should be " << AES_BLOCK_SIZE << " bytes.";
return result;
}
// Create a CMAC context
CMAC_CTX *ctx = CMAC_CTX_new();
// Reverse the endianness of every four bytes in the input data
QByteArray reversedData = data;
qDebug()<<reversedData.toHex();
for (int i = 0; i < reversedData.size(); i += 4) {
// Ensure that we have at least four bytes to convert
if (i + 3 < reversedData.size()) {
char temp = reversedData[i];
reversedData[i] = reversedData[i + 3];
reversedData[i + 3] = temp;
temp = reversedData[i + 1];
reversedData[i + 1] = reversedData[i + 2];
reversedData[i + 2] = temp;
}
}
// Initialize CMAC context with the key
if (CMAC_Init(ctx, key.constData(), key.length(), EVP_aes_128_cbc(), nullptr) != 1) {
qDebug() << "CMAC_Init failed.";
CMAC_CTX_free(ctx);
return result;
}
//Update CMAC context with the data
if (CMAC_Update(ctx, data.constData(), data.length()) != 1) {
qDebug() << "CMAC_Update failed.";
CMAC_CTX_free(ctx);
return result;
}
// Finalize CMAC calculation
unsigned char mac[AES_BLOCK_SIZE];
size_t macLength;
if (CMAC_Final(ctx, mac, &macLength) != 1) {
qDebug() << "CMAC_Final failed.";
CMAC_CTX_free(ctx);
return result;
}
// Convert the result to QByteArray
result = QByteArray(reinterpret_cast<char*>(mac), macLength);
// Free the CMAC context
CMAC_CTX_free(ctx);
QFileInfo fileInfo(filePath);
QString newFilePath = fileInfo.path() + "/" + fileInfo.baseName() + ".security." + fileInfo.suffix();
if (!QFile::copy(filePath, newFilePath)) {
qDebug() << "Failed to create a copy of the original file:" << filePath;
}
QFile copiedFile(newFilePath);
if (!copiedFile.open(QIODevice::Append)) {
qDebug() << "Failed to open copied file for appending:" << newFilePath;
}
// Append the result to the copied file
copiedFile.write(result);
copiedFile.close();
qDebug() << "CMAC result appended to the copied file and saved to:" << newFilePath;
ui->textEdit->setText(result.toHex());
QFileInfo fileInf(filePath);
QString newFile = fileInf.path() + "/" + fileInf.baseName() + "_reversedData." + fileInf.suffix();
QFile reversedDataFile(newFile);
if (reversedDataFile.open(QIODevice::WriteOnly)) {
reversedDataFile.write(reversedData);
reversedDataFile.close();
qDebug() << "Reversed data written to the new file:" << newFilePath;
} else {
qDebug() << "Failed to open the new file for writing:" << newFilePath;
}
return result;
}
PS:在线求一个对加密算法熟悉的大佬
想咨询一些问题