3 votes

Octets pseudo-aléatoires déterministes pour la cryptographie

Existe-t-il un moyen de générer des octets aléatoires pour la cryptographie dans Go de manière déterministe, à partir d'une graine à forte entropie ?

J'ai trouvé crypto/rand ce qui est sûr pour la cryptographie mais pas déterministe.

J'ai trouvé math/rand qui peut être initialisé avec une graine, mais qui n'est pas sûr pour la cryptographie.

J'ai trouvé x/crypto/chacha20 et je me demandais si je pouvais l'utiliser en toute sécurité. XORKeyStream avec un src valeur de 1s. La graine serait la clé et le nonce, qui pourraient être générés avec crypto/rand.

Modifier

A titre d'exemple de ce que je recherche, cryptonite qui est la principale bibliothèque cryptographique Haskell, possède une fonction drgNewSeed que vous pouvez utiliser pour créer un générateur aléatoire à partir d'une graine.

4voto

Rob Napier Points 92148

Oui, XORKeyStream serait parfait pour cela, et c'est une bonne conception pour un CSPRNG. L'intérêt d'un chiffrement par flux est qu'il génère un flux de valeurs "effectivement aléatoires" à partir d'une graine (la clé et le IV). Ces valeurs de flux sont ensuite XORées avec le texte en clair. Dans ce contexte, "effectivement aléatoire" signifie qu'il n'existe aucun "algorithme efficace" (qui s'exécute en temps polynomial) capable de distinguer cette séquence d'une séquence "véritablement aléatoire". Et c'est ce que vous voulez.

Il n'y a pas besoin de tirer dans le ChaCha20, cependant. Vous pouvez utiliser un chiffrement intégré comme AES. Tout chiffrement par blocs peut être converti en chiffrement par flux en utilisant l'un des différents modes, tels que CTR, OFB ou CFB. Les différences entre ces modes n'ont pas vraiment d'importance pour ce problème.

// Defining some seed, split across a "key" and an "iv"
key, _ := hex.DecodeString("6368616e676520746869732070617373")
iv, _ := hex.DecodeString("0123456789abcdef0123456789abcdef")

// We can turn a block cipher into a stream cipher, and AES is handy
block, err := aes.NewCipher(key)

if err != nil {
    panic(err)
}

// Convert block cipher into a stream cipher using a streaming mode like CTR
// OFB or CFB would work, too
stream := cipher.NewCTR(block, iv)

for x := 0; x < 10; x++ {
        // Create a fixed value of the size you want
    value := []byte{0}

    // Transform it to a random value
    stream.XORKeyStream(value, value)

    fmt.Printf("%d\n", value)
}

Terrain de jeux

Il existe plusieurs autres approches que vous pouvez utiliser ici. Vous pouvez utiliser un hachage sécurisé comme SHA-256 pour hacher un compteur (choisissez un nombre aléatoire de 128 bits et continuez à l'incrémenter, en hachant chaque valeur). Ou vous pouvez hacher le résultat précédent (j'ai entendu une petite controverse sur la possibilité que des hachages répétés aient un impact sur la sécurité du hachage. Voir https://crypto.stackexchange.com/questions/19392/any-weakness-when-performing-sha-256-repeatedly y https://crypto.stackexchange.com/questions/15481/will-repeated-rounds-of-sha-512-provide-random-numbers/15488 pour en savoir plus).

Vous pouvez également utiliser un chiffrement par blocs pour faire la même chose, en chiffrant un compteur ou la sortie précédente. C'est assez proche de ce que font les modes de chiffrement par flux. Vous pouvez aussi le faire à la main.

Si vous voulez approfondir la question, vous pouvez rechercher les éléments suivants "csprng stream cipher" à crypto.stackexchange.com. C'est un meilleur endroit pour demander des conseils sur la cryptographie, mais, selon l'OMI, il s'agit d'une question spécifique à la programmation, qui a donc sa place ici.

3voto

kelalaka Points 4036

Dans la génération de nombres aléatoires, il faut d'abord limiter le caractère aléatoire. récolté de l'ordinateur éléments imprévisibles . Ce caractère aléatoire physique est ensuite nettoyé des biais possibles, comme le hachage, puis le plus petit le vrai hasard est étiré en plusieurs en utilisant un générateur de nombres pseudo-aléatoires (PRNG).

Les PRNG sont déterministes, ce qui signifie que si la valeur initiale (le vrai caractère aléatoire initial - la graine) est connue, le reste le sera aussi. Gardez cela toujours secret !

Nous ne sommes pas perdus, l'objectif important de la conception des PRNGs est que les sorties ne soient pas prévisibles à partir d'une autre sortie. Il s'agit d'une exigence forte indiquant qu'il devrait être impossible d'apprendre les états internes uniquement en regardant les sorties.

Go's crypto/rand utilise les fonctionnalités du système sous-jacent pour obtenir le caractère aléatoire physique.

Sous Linux et FreeBSD, Reader utilise getrandom(2) si disponible, /dev/urandom sinon. Sous OpenBSD, Reader utilise getentropy(2). Sur les autres systèmes Unix-like, Reader lit depuis /dev/urandom. Sur les systèmes Windows, Reader utilise l'API CryptGenRandom. Sur Wasm, Reader utilise l'API Crypto Web.

On peut alors utiliser d'éventuels bons RBG déterministes comme le Hash-DRGB, le HMAC-DRGB et le CTR-DRGB tels que définis dans NIST 800-90

Vous pouvez utiliser le x/crypto/chacha20 pour générer la longue séquence aléatoire déterministe. Garder la clé et le nonce fixes et secrets alors vous aurez un DRGB déterministe. C'est très rapide, et recherchable, aussi.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X