安全な暗号化キーのstd :: arrayにカスタムアロケーターを使用できますか?


9

std::arrayは完全にスタックに割り当てられていることを知っていますが、この質問は2つのことを必要とするセキュリティの懸念によって動機付けられています:

  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::arraystd::arrayおり、そもそも使用することで得られるパフォーマンススキームが複雑になります。

より良い解決策はありますか?


コメントは詳細な議論のためのものではありません。この会話はチャットに移動さました
Samuel Liew

申し訳ありませんが、それは改造のためのものでした。もう1つはフラグを拒否したmodであり、あなたではありません。もちろん、あなたができる唯一のことは、答えが正しいかどうかを示すことですので、私は賞金を最良のものに割り当てることができます。もちろん自分自身を評価することはできますが、私はそれほど専門家ではありません。バウンティが割り当てられると、バウンティの理由はとにかく消えます。
Maarten Bodewes

@ Maarten-reinstateMonica残念ながら、どの回答も問題をきれいに解決しません。
量子物理学者

@TheQuantumPhysicistクリーンな方法と見なされるには何が必要ですか?これらの要件を明確にしてみてください。これは、可能な解決策について考えるのにも役立ちます。私はあなたが何を意味しているのか知っていると思いますが、私はあなたがおそらくもっと正確であることができると思います。
Maarten Bodewes

@ Maarten-reinstateMonicaすでに何らかの方法で持っているアロケータを使用します。ゼロからものを書き直すことは悪い考えであり、テストの地獄を必要とします。それが最後の手段になるはずです。以下の回答は、コメントで避けた(チャットに移動する前に)既に述べた明白な解決策を示唆しています。
量子物理学者

回答:


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::arraystd::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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.