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

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

我正在尝试将 AES 密钥写入文件然后稍后读取。我正在使用 Crypto++ 库,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);

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

incompatible operand types : byte* and byte.

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


我查看了Crypto++ wiki上的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*

这让我发疯....

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

readed_key定义为byte,两者不一样。

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

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

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

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

live example:

#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==) 相比,C++ iostreams read/writefread/fwrite 相比更容易理解。您仍然可以进行搜索以确定密钥大小;我将其保留为 exercise to the reader.

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

我将避免使用您的代码,因为它主要是 C 代码。 Andrew 指出了它的一些问题,因此没有必要重复它。相反,我将向您展示 Crypto++ 和 C++ 的处理方式。我也会稍微讨论一下 SecByteBlock


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

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++ 方法。它取自 Reading and writing binary file

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());

Because rnd.Generateblock can't convert std::vector< byte > into byte*. This is driving me crazy....

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

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

由于密钥敏感,您应该使用SecByteBlock。使用完毕后,它会将内存中的密钥归零。

一般来说,如果信息是敏感的,那么你要使用SecBlock<T>。在 SecByteBlock 的情况下,T 是一个 byteSecByteBlock 有一个 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());