Bisakah saya menggunakan pengalokasi khusus untuk std :: array untuk kunci kriptografi yang aman?

9

Saya tahu std::arraybenar-benar dialokasikan dalam tumpukan, tetapi pertanyaan ini dimotivasi oleh masalah keamanan yang memerlukan dua hal:

  1. Data di std::arrayakan zerod atau acak pada kehancuran
  2. Data di std::arrayakan dikunci , sehingga tidak pernah masuk ke disk baik pada crash atau pada memori swap

Biasanya, dengan std::vector, solusinya adalah membuat pengalokasi khusus yang melakukan hal-hal ini . Namun, untuk std::array, saya tidak melihat bagaimana melakukan ini, dan karenanya pertanyaan ini.

Yang terbaik yang bisa saya lakukan adalah ini:

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

Tapi ini jelas tidak memiliki penguncian memori dan menyulitkan skema kinerja std::arrayyang harus diperoleh dengan menggunakan std::arraydi tempat pertama.

Apakah ada solusi yang lebih baik?

Fisikawan Kuantum
sumber
Komentar bukan untuk diskusi panjang; percakapan ini telah dipindahkan ke obrolan .
Samuel Liew
Maaf, itu untuk mod; yang lainnya adalah mod yang menolak bendera, bukan Anda. Satu-satunya hal yang dapat Anda lakukan tentu saja untuk menunjukkan apakah jawabannya benar atau tidak, jadi saya dapat memberikan hadiah kepada yang terbaik. Tentu saja saya bisa mengevaluasi diri sendiri, tetapi saya bukan ahli yang hebat. Alasan untuk hadiah itu tetap hilang begitu ditugaskan.
Maarten Bodewes
@ Maarten-reinstateMonica Sayangnya tidak ada jawaban yang menyelesaikan masalah dengan cara yang bersih.
Fisikawan Kuantum
@TheQuantumPhysicist Apa yang diperlukan untuk dianggap sebagai cara yang bersih? Bisakah Anda mencoba dan membuat persyaratan itu eksplisit? Itu membantu memikirkan solusi yang mungkin juga. Saya pikir saya mungkin tahu apa yang Anda maksud, tetapi saya juga berpikir Anda mungkin bisa lebih tepat.
Maarten Bodewes
@ Maarten-reinstateMonica Menggunakan pengalokasi yang sudah kita miliki. Menulis ulang hal-hal dari awal adalah ide yang buruk dan akan membutuhkan banyak pengujian. Itu harus menjadi pilihan terakhir. Jawaban di bawah ini menunjukkan solusi yang sudah saya sebutkan tadi saya hindari dalam komentar (sebelum memindahkan mereka untuk mengobrol).
Fisika Kuantum

Jawaban:

5

std::arraytidak dapat menggunakan pengalokasi; namun, sepertinya kelas SecureArray Anda dapat mencapai apa yang Anda inginkan melalui konstruktor / dekonstruksi kustom.

Sesuatu seperti ini:

#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);
    }
};
clyne
sumber
4

Saya tahu std::arraybenar-benar dialokasikan di tumpukan

Ini tidak sepenuhnya benar. std::arraytidak mengalokasikan memori apa pun, jadi itu tergantung di mana Anda mengalokasikannya.

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

Tapi ini jelas tidak memiliki penguncian memori dan menyulitkan skema kinerja std::arrayyang harus diperoleh dengan menggunakan std::arraydi tempat pertama.

Pertama, itu tidak masalah untuk mengunci memori di tumpukan. Lihat contoh 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;
    }
}

Jadi, Anda bisa memanggil mlockatau analog portabel di SecureArraykonstruktor.

Kedua, kenaikan kinerja apa yang Anda harapkan? Kecepatan membaca / menulis memori tidak tergantung pada di mana Anda mengalokasikan array Anda, pada heap atau pada stack. Jadi, ini semua tentang seberapa cepat Anda dapat mengalokasikan dan mengunci memori. Jika kinerjanya kritis, penguncian memori mungkin terlalu lambat (atau tidak, siapa tahu?) Untuk memanggilnya setiap kali dalam SecureArraykonstruktor bahkan jika memori dialokasikan pada stack.

Jadi, lebih mudah digunakan std::vectordengan pengalokasi khusus. Ini mungkin melakukan preallocate dan prelock big memory chunks, jadi kecepatan alokasi akan hampir secepat di stack.

Stas
sumber
Ini bukan tentang kecepatan sama sekali, ini tentang keamanan dan memastikan bahwa segala sesuatu tidak dipindahkan, karena bergerak umumnya berarti menyalin.
Maarten Bodewes
2
@ Maarten-reinstateMonica hmm ... sepertinya saya tidak mendapatkan niat untuk menggunakannya std::arraydaripada std::vectordi tempat pertama. Saya pikir ini tentang kecepatan alokasi.
Stas