Posso usare un allocatore personalizzato per std :: array per chiavi crittografiche sicure?


9

So che std::arrayè completamente allocato nello stack, ma questa domanda è motivata da problemi di sicurezza che richiedono due cose:

  1. I dati std::arraysaranno zerod o randomizzati alla distruzione
  2. I dati in std::arrayingresso verranno bloccati , in modo tale da non andare mai sul disco né in caso di arresto anomalo o di memoria di swap

Di solito, con std::vector, la soluzione è creare un allocatore personalizzato che faccia queste cose . Tuttavia, per std::array, non vedo come farlo, e quindi questa domanda.

Il meglio che potrei fare è questo:

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

Ma questo ovviamente manca del blocco della memoria e complica lo schema delle prestazioni std::arrayche si può ottenere usando std::arrayin primo luogo.

C'è qualche soluzione migliore?


I commenti non sono per una discussione estesa; questa conversazione è stata spostata in chat .
— Samuel Liew

Ci dispiace, era per le mod; l'altra era la mod che ha respinto la bandiera, non tu. L'unica cosa che puoi fare è ovviamente indicare se le risposte sono corrette o meno, quindi posso assegnare la taglia a quella migliore. Posso valutare me stesso ovviamente, ma non sono un grande esperto. Il motivo della generosità scompare comunque una volta assegnato.
— Maarten Bodewes,

@ Maarten-reinstateMonica Purtroppo nessuna delle risposte risolve il problema in modo pulito.
— Il fisico quantistico l'

@TheQuantumPhysicist Cosa ci vorrebbe per essere considerato un modo pulito? Potresti provare a rendere espliciti questi requisiti? Questo aiuta a pensare anche a una possibile soluzione. Penso che potrei sapere cosa intendi, ma penso anche che tu possa essere probabilmente più preciso.
— Maarten Bodewes,

@ Maarten-reinstateMonica Usando un allocatore che abbiamo già in qualche modo. Riscrivere le cose da zero è una cattiva idea e richiederà moltissimi test. Dovrebbe essere l'ultima risorsa. Le risposte di seguito suggeriscono soluzioni ovvie che ho già menzionato che sto evitando nei commenti (prima di spostarle in chat).
— The Quantum Physicist,

Risposte:


5

std::arraynon è possibile utilizzare un allocatore; tuttavia, sembra che la tua classe SecureArray possa ottenere ciò che desideri attraverso un costruttore / decostruttore personalizzato.

Qualcosa come questo:

#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

So che std::arrayè completamente allocato nello stack

Questo non è del tutto vero. std::arraynon alloca memoria, quindi dipende da dove la allocate.

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

Ma questo ovviamente manca del blocco della memoria e complica lo schema delle prestazioni std::arrayche si può ottenere usando std::arrayin primo luogo.

Innanzitutto, non è un problema bloccare la memoria nello stack. Vedi esempio 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;
    }
}

Quindi, puoi semplicemente chiamare mlock o qualsiasi analogo portatile nel SecureArraycostruttore.

In secondo luogo, quale miglioramento delle prestazioni ti aspetti di ottenere? La velocità di lettura / scrittura della memoria non dipende da dove viene allocato l'array, dall'heap o dallo stack. Quindi, tutto dipende da quanto velocemente è possibile allocare e bloccare la memoria. Se le prestazioni sono fondamentali, il blocco della memoria potrebbe essere troppo lento (o no, chi lo sa?) Per chiamarlo ogni voltaSecureArray costruttore anche se la memoria è allocata nello stack.

Quindi, è più utile da usare std::vectorcon l'allocatore personalizzato. Potrebbe preallocare e prelockare grossi blocchi di memoria, quindi la velocità di allocazione sarà quasi altrettanto veloce che nello stack.


Non si tratta affatto di velocità, si tratta di sicurezza e di assicurarsi che le cose non vengano spostate, poiché spostarsi in genere significa copiare.
— Maarten Bodewes,

2
@ Maarten-reinstateMonica hmm ... sembra che non ho avuto l'intenzione di usare std::arrayinvece che std::vectoral primo posto. Ho pensato che riguardasse la velocità di allocazione.
— Stas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.