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.