如何在文件中读取和写入 AES 密钥?

How to read and write an AES key to and from a file?

本文关键字:AES 密钥 读取 文件      更新时间:2023-10-16

我正在尝试将AES密钥写入文件,然后稍后读取。我正在使用加密++库,AES密钥初始化如下。下面,byteunsigned char的类型定义。

byte key[CryptoPP::AES::MAX_KEYLENGTH]

密钥长度为 32 字节。我尝试将其写入文件:

FILE* file = fopen("C:\key", "wb");
fwrite(key, 1, sizeof(key), file);
fclose(file);

并使用以下方法恢复它:

FILE* read_file = fopen("C:\key", "rb");
fseek(read_file, 0, SEEK_END);
long int size = ftell(read_file);
fclose(read_file);
read_file = fopen("C:\key", "rb");
unsigned char * in = (unsigned char *)malloc(size);
byte readed_key = fread(in, sizeof(unsigned char), size, read_file);
fclose(read_file);
if (key == readed_key)
{
cout << "this is the right key !";
}
free(in);

但是,我收到一条错误消息:

不兼容的操作数类型:字节*和字节。

我不明白为什么,因为readed_keykey是用byte而不是byte*初始化的.


我在Crypto++维基上查看了AES,密钥生成如下。我发现我只是在创建密钥(而不是生成它(:

SecByteBlock key(0x00, AES::MAX_KEYLENGTH);
rnd.GenerateBlock( key, key.size() );

有了那个我不能使用

std::vector<byte> key(32);
rnd.GenerateBlock(key, key.size());

因为rnd.Generateblock无法转换std::vector< byte > into byte*

这让我发疯了。

如何在文件中读取和写入 AES 密钥?

我将避免使用您的代码,因为它主要是 C 代码。安德鲁指出了它的一些问题,所以重新讨论它是没有意义的。相反,我将向您展示Crypto++和C++做事方式。我也会SecByteBlock讨论一下。


以下是使用源和接收器将数据读入字节数组的 Crypto++ 方法。您可以在 Crypto++ wiki 中的管道中阅读有关它们的更多信息。

byte key[CryptoPP::AES::MAX_KEYLENGTH];
FileSource fs("C:\key.bin", true, new ArraySink(key, sizeof(key)));

下面是使用源和接收器将数据写入文件的 Crypto++ 方法。

byte key[CryptoPP::AES::MAX_KEYLENGTH];
ArraySource as(key, sizeof(key), true, new FileSink("C:\key.bin"));

以下是使用流将数据读入字节数组C++方法。它取自读取和写入二进制文件

byte key[CryptoPP::AES::MAX_KEYLENGTH];
std::ifstream fs("C:\key.bin", std::ios::binary);
fs.read(key, sizeof(key));

以下是使用流将数据写入文件C++方法。

byte key[CryptoPP::AES::MAX_KEYLENGTH];
std::ofstream fs("C:\key.bin", std::ios::binary);
fs.write(key, sizeof(key));

std::vector<byte> key(32);
rnd.GenerateBlock(key, key.size());

因为 rnd。生成块无法将std::vector< byte >转换为byte*.这让我发疯了。

在这里,您需要一个指向第一个元素的非常量指针。取向量中第一个元素的地址。这同样适用于std::string

std::vector<byte> key(32);
rnd.GenerateBlock(&key[0], key.size());

由于密钥是敏感的,因此应使用SecByteBlock。使用完密钥后,它会从内存中将其清零。

一般来说,如果信息是敏感的,那么你想使用SecBlock<T>。在SecByteBlock的情况下,T是一个byte,并且有一个用于SecByteBlock的typedef。但是你可以用任何东西来做SecBlock<T>

下面是使用源和接收器将数据读入SecByteBlock的 Crypto++ 方法。

SecByteBlock key(AES::MAX_KEYLENGTH);
FileSource fs("C:\key.bin", true, new ArraySink(key.begin(), key.size()));

SecByteBlock可以在构造时将元素初始化为已知值。您正在使用以下功能。所有元素都初始化为0x00

SecByteBlock key(0x00, AES::MAX_KEYLENGTH);
rnd.GenerateBlock(key, key.size());

由于您将立即用随机数据覆盖元素,因此您应该放弃初始化。只需要求一个未初始化的内存块:

SecByteBlock key(AES::MAX_KEYLENGTH);
rnd.GenerateBlock(key, key.size());

key是一个byte数组,即它的类型是byte[32](假设CryptoPP::AES::MAX_KEYLENGTH是一个等于32的整数常数(。 在某些情况下,byte[N]衰减为byte*,包括在比较期间使用==(例如在if (key == readed_key)行中(。

readed_key被定义为byte,这是不一样的。

此外,您不正确地使用了fread (3);返回值是读取的项目数,而不是读取的数据。您读取的数据存储在in数组中。您需要将key的每个元素与in的每个元素进行比较,以检查键是否相同。

编辑:感谢@vasek指出应该写比较

if (memcmp(key, in, size) == 0) { /* keys are equal */ }

由于您使用的是C++(Crypto++ 库是一个C++库(,因此您可以使用更高级别的抽象来避免使用malloc/free进行手动内存管理,并使代码更易于使用:

现场示例:

#include <cstdint>
#include <fstream>
#include <iostream>
#include <vector>
using byte = char;
int main() {
std::vector<byte> key(32);
// Code would go here to generate the `key`
// ...
{
std::ofstream out("C:\key", std::ios::out | std::ios::binary);
out.write(key.data(), key.size());
} // file is closed automatically here!
std::vector<byte> read_key(32);
{
std::ifstream in("C:\key", std::ios::in | std::ios::binary);
in.read(read_key.data(), read_key.size());
}
if (key == read_key) {
std::cout << "Keys are equal!n";
}
return 0;    
}

在这里,std::vector<byte>处理内存分配(您只需在构造函数中告诉它大小;使用.data()获取指向内容的指针;完整键的比较是免费的,std::vectoroperator==(,并且与fread/fwrite相比,iostreamsread/write的C++更容易遵循。您仍然可以执行查找以确定密钥大小;我会把它留给读者作为练习。