我可以对std :: array使用自定义分配器来获得安全的加密密钥吗?


9

我知道它std::array是完全分配在堆栈中的,但是这个问题是由需要考虑两点的安全问题引起的:

  1. 输入的数据在std::array销毁时将归零或随机化
  2. 输入中的数据std::array将被锁定,因此无论是崩溃还是交换内存,它都不会进入磁盘

通常情况下,用std::vector的解决方案是创建一个自定义分配器的是做这些事情。但是,对于std::array,我没有看到如何执行此操作,因此也没有看到这个问题。

我能做的最好的事情是:

template <typename T, std::size_t Size>
struct SecureArray : public std::array<T, Size>
{
    static_assert(std::is_pod<T>::value, "Only POD types allowed")
    static_assert(sizeof(T) == 1, "Only 1-byte types allowed")
    virtual ~SecureArray()
    {
        std::vector<uint8_t> d = RandomBytes(Size); // generates Size random bytes
        std::memcpy(this->data(), d.data(), Size);
    }
}

但这显然缺少内存锁定,std::array这使首先要使用的性能方案变得复杂std::array

有更好的解决方案吗?


评论不作进一步讨论;此对话已转移至聊天
塞缪尔·刘

对不起,那是给mods的;另一个是拒绝标志的国防部,不是你。当然,您唯一能做的就是指出答案是否正确,因此我可以将赏金分配给最佳答案。我当然可以评估自己,但是我不是那么出色的专家。一旦分配了赏金的原因就消失了。
Maarten Bodewes

@ Maarten-reinstateMonica不幸的是,没有一个答案能以干净的方式解决问题。
量子物理学家

@TheQuantumPhysicist被认为是一种干净的方法是什么?您可以尝试使这些要求明确吗?这也有助于考虑可能的解决方案。我想我可能知道您的意思,但我也认为您可能更精确。
Maarten Bodewes,

@ Maarten-reinstateMonica使用我们已经以某种方式拥有的分配器。从头开始重写内容是个坏主意,并且需要进行大量测试。那应该是最后的手段。下面的答案提出了一些显而易见的解决方案,我已经在评论中避免了(在将其移至聊天之前)。
量子物理学家

Answers:


5

std::array不能使用分配器;但是,似乎您的SecureArray类可以通过自定义构造函数/解构函数实现所需的功能。

像这样:

#include <sys/mman.h>

template<class T, std::size_t Size>
struct SecureArray : public std::array<T, Size>
{
    // Your static_asserts...

    SecureArray(void) {
        mlock(std::array<T, Size>::data(), sizeof(T) * Size);
    }

    ~SecureArray(void) {
        char *bytes = reinterpret_cast<char *>(std::array<T, Size>::data());
        for (std::size_t i = 0; i < sizeof(T) * Size; i++)
            bytes[i] = 0;
        munlock(bytes, sizeof(T) * N);
    }
};

4

我知道std::array完全分配在堆栈中

这不是真的。std::array不会分配任何内存,因此取决于您分配内存的位置。

auto* arr = new std::array<int, 100>(); // BUM! it is allocated on the heap

但这显然缺少内存锁定,std::array这使首先要使用的性能方案变得复杂std::array

首先,锁定堆栈上的内存不是问题。请参阅POSIX示例:

#include <iostream>
#include <sys/mman.h>
#include <array>

int main()
{
    std::array<int, 3> a = {1, 2, 3};        // std::array allocated on the stack
    if (mlock(a.data(), sizeof(a)) == 0)
    {
        std::cout << "LOCKED" << std::endl;
    }
}

因此,您可以直接拨打mlock或拨打任何便携式模拟电话SecureArray构造函数中。

其次,您期望获得什么性能提升?内存读/写速度与您在数组或堆上分配数组的位置无关。因此,这完全取决于您可以分配和锁定内存的速度。如果性能至关重要,那么SecureArray即使在堆栈上分配了内存,内存锁定也可能太慢(或者不知道,谁知道?),因此每次在构造函数中都不能调用它。

因此,std::vector与自定义分配器一起使用更方便。它可能会预分配和预锁大内存块,因此分配速度几乎与堆栈上的速度一样快。


这根本不关乎速度,关乎安全性和确保不移动任何东西,因为移动通常意味着复制。
Maarten Bodewes,

2
@ Maarten-reinstateMonica嗯。。。似乎我不是故意使用std::array而不是std::vector放在第一位。我认为这与分配速度有关。
Stas
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.