Maison  >  Article  >  développement back-end  >  Générez de manière déterministe des clés privées RSA avec io.Reader personnalisé à l'aide de Go

Générez de manière déterministe des clés privées RSA avec io.Reader personnalisé à l'aide de Go

WBOY
WBOYavant
2024-02-09 14:12:10374parcourir

使用 Go 通过自定义 io.Reader 确定性生成 RSA 私钥

L'éditeur php Baicao présentera comment utiliser le langage Go pour générer de manière déterministe des clés privées RSA via une interface io.Reader personnalisée. RSA est un algorithme de chiffrement asymétrique couramment utilisé pour le chiffrement des données et les signatures numériques. Lors de la génération d'une clé privée RSA, nous devons généralement obtenir des nombres aléatoires à partir d'une source aléatoire, mais nous devons parfois générer une clé privée déterministe selon des règles spécifiques. Cet article expliquera en détail comment implémenter une interface io.Reader personnalisée et utiliser cette interface pour générer une clé privée RSA déterministe. En lisant cet article, vous apprendrez cette technique utile pour donner plus de flexibilité et de contrôle à vos applications cryptographiques.

Contenu de la question

Pour des raisons qu'il vaut probablement mieux laisser sans réponse, je dois générer un nombre illimité de clés publiques/privées rsa. Notez que cela n’est utilisé pour rien de hautement sécurisé, alors ne me dites pas de ne pas le faire, et oui, je sais que ce n’est pas idéal. Ce que je veux dire par « infini », c'est que j'en ai besoin d'un nombre inconnu (des milliards à des milliards) et qu'il est impossible de les créer avant de les utiliser.

Étant donné que cela consomme un espace infini et prend un temps infini à générer, je dois le faire au moment de l'exécution.

Cependant, j'ai également besoin d'avoir la même paire de clés pour une entrée donnée. Cela signifie que je dois recréer de manière déterministe la clé rsa en fonction de l'entrée.

J'utilise go, généralement vous créez la clé en utilisant la commande suivante,

k, err := rsa.generatekey(rand.reader, 2048)

Bien sûr, le problème est que rand.reader 是由 crypto/rand est fourni, il ne peut donc pas être semé.

Je pensais qu'il serait possible de fournir ma propre implémentation de lecteur pour atteindre mon objectif. J'ai regardé le code source de generatekey et j'ai remarqué qu'il recherchait des nombres premiers, j'ai donc implémenté mon propre lecteur afin de pouvoir contrôler les nombres premiers "aléatoires" renvoyés, me permettant de générer la même clé si nécessaire,

type reader struct {
    data   []byte
    sum    int
    primes []int
}

func newreader(toread string) *reader {
    primes := sieveoferatosthenes(10_000_000)
    return &reader{[]byte(toread), 0, primes}
}

func (r *reader) read(p []byte) (n int, err error) {
    r.sum = r.sum + 1

    if r.sum >= 100_000 {
        return r.primes[rand.intn(len(r.primes))], io.eof
    }

    return r.primes[rand.intn(len(r.primes))], nil
}

func sieveoferatosthenes(n int) (primes []int) {
    b := make([]bool, n)
    for i := 2; i < n; i++ {
        if b[i] == true {
            continue
        }
        primes = append(primes, i)
        for k := i * i; k < n; k += i {
            b[k] = true
        }
    }
    return
}

Ensuite, je peux appeler générer une clé comme celle-ci

k, err := rsa.GenerateKey(NewReader(""), 2048)

Il se compile mais plante au moment de l'exécution en raison de pointeurs nuls. Je suis plutôt content de go, mais la mise en œuvre de rsa dépasse ma compréhension. Je cherche de meilleures façons d’y parvenir ou ce que je dois faire pour que cela fonctionne pour mes lecteurs.

Notez que ma seule exigence ici est de pouvoir générer la même clé pour une entrée donnée, en utilisant rsa.generatekey ou une substitution compatible. L'entrée peut être littéralement n'importe quoi tant que j'obtiens la même clé que la sortie.

Voici un lien Go Playground montrant où je me trouve actuellement sur https://go.dev/play/p/jd1naopr5ad

Workaround

read 方法未执行预期操作。它不会用随机字节填充输入 p 字节切片。如果您查看 crypto/rand.read Une implémentation Unix d'une méthode qui transmet une tranche d'octets d'entrée à un autre lecteur. Donc, fondamentalement, vous devez remplir la tranche d'octets avec des nombres aléatoires. Par exemple :

func (r *reader) read(p []byte) (n int, err error) {
        i := 0
        b := p

        for i < len(b) {
                if len(b) < 4 {
                        b[0] = 7
                        b = b[1:]
                } else {
                        binary.littleendian.putuint32(b, uint32(rand.intn(len(r.primes))))
                        b = b[4:]
                }
        }

        return len(p), nil
}

C'est le lien vers le terrain de jeu.

Mise à jour

Comme Erwin l'a mentionné dans sa réponse, il existe une fonction appelée maybereadrand qui a 50 % de chances de lire 1 octet du lecteur Rand, ce qui rend la fonction non déterministe. Mais vous pouvez le résoudre en ajoutant une instruction if dans la méthode read : si la longueur de la tranche d'entrée est de 1, ignorez tout et revenez. Sinon, fournissez des nombres premiers à la tranche d'entrée :

func (r *Reader) Read(p []byte) (n int, err error) {
    i := 0
    b := p

    if len(p) == 1 {
        println("maybeReadRand")
        return 1, nil
    }

    for i < len(b) {
        if len(b) < 4 {
            b[0] = 7
            b = b[1:]
        } else {
            binary.LittleEndian.PutUint32(b, uint32(r.primes[r.i]))
            r.i++
            b = b[4:]
        }
    }

    return len(p), nil
}

Dans cet extrait, j'ai créé 2 clés et elles sont toutes deux égales. p>

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer