Puis-je utiliser un allocateur personnalisé pour std :: array pour des clés cryptographiques sécurisées?

9

je connais std::array c'est complètement alloué dans la pile, mais cette question est motivée par des problèmes de sécurité qui nécessitent deux choses:

  1. Les données std::array seront zéros ou randomisées lors de la destruction
  2. Les données std::arrayseront verrouillées , de sorte qu'elles ne jamais stockées sur le disque ni en cas de panne ou de mémoire d'échange

Habituellement, avec std::vector, la solution consiste à créer un allocateur personnalisé qui fait ces choses . Cependant, pour std::array, je ne vois pas comment faire cela, et donc cette question.

Le mieux que j'ai pu faire est le suivant:

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

Mais cela manque évidemment de verrouillage de la mémoire et complique le schéma de performances std::arrayqui doit être obtenu en utilisant std::arrayen premier lieu.

Y a-t-il une meilleure solution?

Le physicien quantique
la source
Les commentaires ne sont pas pour une discussion approfondie; cette conversation a été déplacée vers le chat .
Samuel Liew
Désolé, c'était pour les mods; l'autre était le mod qui a rejeté le drapeau, pas vous. La seule chose que vous pouvez faire est bien sûr d'indiquer si les réponses sont correctes ou non, afin que je puisse attribuer la prime à la meilleure. Je peux m'évaluer bien sûr, mais je ne suis pas un grand expert. La raison de la prime disparaît de toute façon une fois qu'elle est attribuée.
Maarten Bodewes
@ Maarten-reinstateMonica Malheureusement, aucune des réponses ne résout le problème d'une manière propre.
The Quantum Physicist
@TheQuantumPhysicist Que faudrait-il pour être considéré comme une manière propre? Pourriez-vous essayer de rendre ces exigences explicites? Cela aide également à réfléchir à une solution possible. Je pense que je pourrais savoir ce que vous voulez dire, mais je pense aussi que vous pouvez probablement être plus précis.
Maarten Bodewes
@ Maarten-reinstateMonica Utilisation d'un allocateur que nous avons déjà en quelque sorte. Réécrire des trucs à partir de zéro est une mauvaise idée et nécessitera beaucoup de tests. Cela devrait être le dernier recours. Les réponses ci-dessous suggèrent des solutions évidentes que j'ai déjà mentionnées que j'évite dans les commentaires (avant de les déplacer vers le chat).
The Quantum Physicist

Réponses:

5

std::arrayne peut pas utiliser d'allocateur; cependant, il semble que votre classe SecureArray puisse réaliser ce que vous voulez grâce à un constructeur / déconstructeur personnalisé.

Quelque chose comme ça:

#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
la source
4

Je sais que std::arrayc'est complètement alloué dans la pile

Ce n'est pas tout à fait vrai. std::arrayn'alloue pas de mémoire, cela dépend donc de l'endroit où vous l'allouez.

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

Mais cela manque évidemment de verrouillage de la mémoire et complique le schéma de performances std::arrayqui doit être obtenu en utilisant std::arrayen premier lieu.

Tout d'abord, ce n'est pas un problème pour verrouiller la mémoire sur la pile. Voir l'exemple 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;
    }
}

Donc, vous pouvez simplement appeler mlockou n'importe quel analogique portable dansSecureArray constructeur.

Deuxièmement, quel gain de performances espérez-vous obtenir? La vitesse de lecture / écriture de la mémoire ne dépend pas de l'endroit où vous allouez votre baie, sur le tas ou sur la pile. Ainsi, tout dépend de la vitesse à laquelle vous pouvez allouer et verrouiller la mémoire. Si les performances sont critiques, le verrouillage de la mémoire peut être trop lent (ou pas, qui sait?) Pour l'appeler à chaque fois dans le SecureArrayconstructeur même si la mémoire est allouée sur la pile.

Il est donc plus pratique à utiliser std::vectoravec l'allocateur personnalisé. Il peut pré-allouer et pré-verrouiller de gros morceaux de mémoire, donc la vitesse d'allocation sera presque aussi rapide que sur la pile.

Stas
la source
Il ne s'agit pas du tout de vitesse, mais de sécurité et de s'assurer que les choses ne bougent pas, car déplacer signifie généralement copier.
Maarten Bodewes
2
@ Maarten-reinstateMonica hmm ... il semble que je n'ai pas eu l'intention d'utiliser std::arrayau lieu de la std::vectorpremière place. Je pensais que c'était une question de vitesse d'allocation.
Stas