php小編草將為大家介紹如何使用Go語言透過自訂io.Reader介面來決定性產生RSA私鑰。 RSA是一種非對稱加密演算法,常用於資料加密和數位簽章。在產生RSA私鑰時,通常需要從隨機來源取得隨機數,但有時我們需要根據特定的規則產生確定性的私鑰。本文將詳細說明如何實作自訂的io.Reader接口,並使用此介面產生確定性的RSA私鑰。透過閱讀本文,您將掌握這項有用的技巧,為您的加密應用程式提供更多靈活性和可控性。
出於可能最好不回答的原因,我需要產生無限的 rsa 公鑰/私鑰。請注意,這沒有用於任何高度安全的事情,所以請不要告訴我不要這樣做,是的,我知道它並不理想。我所說的「無限」是指我需要其中未知數量(數十億到數萬億),並且在使用之前創建它們是不可能的。
由於這會消耗無限的空間並需要無限的時間來生成,因此我需要在運行時執行此操作。
但是,對於給定的輸入,我還需要具有相同的金鑰對。這意味著我需要根據輸入確定性地重新建立 rsa 金鑰。
我使用 go,通常您使用以下命令建立金鑰,
k, err := rsa.generatekey(rand.reader, 2048)
當然,問題是 rand.reader
是由 crypto/rand
提供的,因此無法為其提供種子。
我認為可以提供我自己的閱讀器實現來實現我的目標。我查看了generatekey
的源代碼,注意到它正在尋找素數,因此我實現了自己的閱讀器,這樣我就可以控制返回的“隨機”素數,從而允許我在需要時生成相同的密鑰,
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 }
然後我可以像這樣呼叫產生金鑰
k, err := rsa.GenerateKey(NewReader(""), 2048)
它可以編譯,但由於零指標而在運行時崩潰。我對 go 相當滿意,但 rsa 的實現超出了我的理解。尋找更好的方法來實現這一目標,或尋找我需要做的事情來讓我的讀者工作。
請注意,我在這裡唯一的硬性要求是能夠為給定的輸入產生相同的金鑰,並使用 rsa.generatekey
或相容替換。輸入實際上可以是任何東西,只要我得到與輸出相同的密鑰即可。
這是一個go playground 鏈接,展示了我目前所在的位置https://go.dev/play/p/jd1naopr5ad
##read 方法未執行預期操作。它不會用隨機位元組填滿輸入
p 位元組切片。如果您查看
crypto/rand.read 方法的 unix 實現,它將輸入位元組切片傳遞給另一個讀取器。所以基本上你需要用隨機數字填滿位元組片。例如:
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
}
連結。
更新正如erwin 在回答中提到的,有一個名為
maybereadrand 的函數,它有50% 的機會從rand 讀取器讀取1 個位元組,從而使該函數具有不確定性。但是您可以透過在 read 方法中新增 if 語句來解決:如果輸入切片的長度為 1,請忽略所有內容並返回。否則,向輸入切片提供質數:
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 }
以上是使用 Go 透過自訂 io.Reader 確定性產生 RSA 私鑰的詳細內容。更多資訊請關注PHP中文網其他相關文章!