Heim >Backend-Entwicklung >Golang >Generieren Sie deterministisch private RSA-Schlüssel mit dem benutzerdefinierten io.Reader mithilfe von Go

Generieren Sie deterministisch private RSA-Schlüssel mit dem benutzerdefinierten io.Reader mithilfe von Go

WBOY
WBOYnach vorne
2024-02-09 14:12:10409Durchsuche

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

php-Editor Baicao stellt Ihnen vor, wie Sie die Go-Sprache verwenden, um RSA-Privatschlüssel über die benutzerdefinierte io.Reader-Schnittstelle deterministisch zu generieren. RSA ist ein asymmetrischer Verschlüsselungsalgorithmus, der häufig zur Datenverschlüsselung und digitalen Signaturen verwendet wird. Beim Generieren eines privaten RSA-Schlüssels müssen wir normalerweise Zufallszahlen aus einer Zufallsquelle erhalten, aber manchmal müssen wir einen deterministischen privaten Schlüssel nach bestimmten Regeln generieren. In diesem Artikel wird ausführlich erläutert, wie Sie eine benutzerdefinierte io.Reader-Schnittstelle implementieren und diese Schnittstelle zum Generieren eines deterministischen privaten RSA-Schlüssels verwenden. Durch die Lektüre dieses Artikels lernen Sie diese nützliche Technik kennen, um Ihren kryptografischen Anwendungen mehr Flexibilität und Kontrolle zu verleihen.

Inhalt der Frage

Aus Gründen, die man am besten unbeantwortet lassen sollte, muss ich unbegrenzt öffentliche/private RSA-Schlüssel generieren. Beachten Sie, dass dies nicht für besonders sichere Zwecke verwendet wird. Bitte sagen Sie mir also nicht, dass ich es nicht tun soll, und ja, ich weiß, dass es nicht ideal ist. Was ich mit „unendlich“ meine, ist, dass ich eine unbekannte Anzahl davon benötige (Milliarden bis Billionen) und es unmöglich ist, sie zu erstellen, bevor ich sie verwende.

Da dies unendlich viel Platz verbraucht und die Generierung unendlich viel Zeit in Anspruch nimmt, muss ich dies zur Laufzeit tun.

Allerdings muss ich für eine bestimmte Eingabe auch dasselbe Schlüsselpaar haben. Das bedeutet, dass ich den RSA-Schlüssel basierend auf der Eingabe deterministisch neu erstellen muss.

Ich verwende go, normalerweise erstellt man den Schlüssel mit dem folgenden Befehl,

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

Das Problem ist natürlich, dass rand.reader 是由 crypto/rand bereitgestellt wird und daher nicht gesät werden kann.

Ich dachte, es wäre möglich, meine eigene Reader-Implementierung bereitzustellen, um mein Ziel zu erreichen. Ich habe mir den Quellcode von generatekey angesehen und festgestellt, dass nach Primzahlen gesucht wird. Deshalb habe ich meinen eigenen Reader implementiert, damit ich die zurückgegebenen „zufälligen“ Primzahlen steuern und bei Bedarf denselben Schlüssel generieren kann,

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
}

Dann kann ich den Generierungsschlüssel so aufrufen

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

Es wird kompiliert, stürzt jedoch zur Laufzeit aufgrund von Nullzeigern ab. Ich bin ziemlich zufrieden mit go, aber die Implementierung von RSA übersteigt mein Verständnis. Ich suche nach besseren Möglichkeiten, dies zu erreichen, oder suche nach dem, was ich tun muss, damit es für meine Leser funktioniert.

Beachten Sie, dass meine einzige harte Anforderung hier darin besteht, denselben Schlüssel für eine bestimmte Eingabe generieren zu können, indem ich rsa.generatekey oder eine kompatible Substitution verwende. Die Eingabe kann buchstäblich alles sein, solange ich denselben Schlüssel wie die Ausgabe erhalte.

Hier ist ein Go-Playground-Link, der zeigt, wo ich mich gerade befinde: https://go.dev/play/p/jd1naopr5ad

Workaround

read 方法未执行预期操作。它不会用随机字节填充输入 p 字节切片。如果您查看 crypto/rand.read Eine Unix-Implementierung einer Methode, die einen Teil der Eingabebytes an einen anderen Leser übergibt. Im Grunde müssen Sie also das Byte-Slice mit Zufallszahlen füllen. Zum Beispiel:

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
}

Dies ist der Link zum Spielplatz.

Update

Wie Erwin in seiner Antwort erwähnte, gibt es eine Funktion namens maybereadrand, die eine 50-prozentige Chance hat, 1 Byte vom Rand-Reader zu lesen, wodurch die Funktion nicht deterministisch ist. Sie können das Problem jedoch lösen, indem Sie der Lesemethode eine if-Anweisung hinzufügen: Wenn die Länge des Eingabe-Slice 1 beträgt, ignorieren Sie alles und kehren Sie zurück. Andernfalls stellen Sie dem Eingabe-Slice Primzahlen zur Verfügung:

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
}

In diesem Snippet habe ich zwei Schlüssel erstellt und sie sind beide gleich. p>

Das obige ist der detaillierte Inhalt vonGenerieren Sie deterministisch private RSA-Schlüssel mit dem benutzerdefinierten io.Reader mithilfe von Go. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:stackoverflow.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen