【问题标题】:How to read and write an AES key to and from a file?如何在文件中读取和写入 AES 密钥?
【发布时间】:2017-07-19 09:29:57
【问题描述】:

我正在尝试将 AES 密钥写入文件,然后再读取。我正在使用 Crypto++ 库,并且 AES 密钥初始化如下。下面,byteunsigned char 的 typedef。

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

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

不兼容的操作数类型:byte* 和 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&lt; byte &gt; into byte*

这让我发疯了......

【问题讨论】:

标签: c++ arrays vector file-io crypto++


【解决方案1】:

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

我将避免使用您的代码,因为它主要是 C 代码。安德鲁指出了它的一些问题,所以重新散列它是没有意义的。相反,我将向您展示 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());

因为 rnd.Generateblock 无法将 std::vector&lt; byte &gt; 转换为 byte*。这让我发疯了......

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

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

由于密钥是敏感的,您应该使用SecByteBlock。一旦你完成使用它,它就会从内存中将密钥归零。

一般来说,如果信息是敏感信息,那么您希望使用SecBlock&lt;T&gt;。对于SecByteBlockTbyteSecByteBlock 有一个 typedef。但是你可以用任何东西制作SecBlock&lt;T&gt;

这是使用源和接收器将数据读入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());

【讨论】:

  • 感谢您的详细回答,jww,如果可以,请更正intialize。 :)
  • 谢谢@Teo。是的,我有时拼写很糟糕。如果我打开拼写检查,那么我的拼写错误就会变成语法错误......
  • 呵呵,没关系。我自己碰巧是个糟糕的拼写者。
【解决方案2】:

keybyte数组,即它的类型是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 进行手动内存管理,并使代码更易于使用:

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&lt;byte&gt; 处理内存分配(您只需在构造函数中告诉它大小;使用.data() 获取指向内容的指针;完整密钥与std::vector 的比较免费提供operator==) 和 C++ iostreams read/writefread/fwrite 相比更容易理解。您仍然可以通过搜索来确定密钥大小;我会将其保留为 exercise to the reader

【讨论】:

  • 另外值得注意的比较应该使用if (memcmp(key, in, size) == 0) { /* keys are equal */ }
  • 我明白了。那么有没有办法(无论是否使用 fread)返回文件中的数据并将其存储在字节数组中?
  • fread(in, sizeof(unsigned char), size, read_file)是正确的,但是key不在fread的返回值中,而是在in数组中。
  • ok."in" 是一个无符号字符*,所以我不想将读取的密钥存储在其中。我可以在 fread 中放置一个字节变量而不是 "in" 吗?跨度>
  • 是的,你可以。试一试。
猜你喜欢
  • 2014-03-18
  • 2012-09-20
  • 2016-11-11
  • 1970-01-01
  • 2022-01-22
  • 1970-01-01
  • 2012-09-15
  • 2014-11-07
相关资源
最近更新 更多