TL;DR#
最近はRtlGenRandom
じゃなくてProcessPrng
が使われている。
本文#
Go 言語で暗号学的に安全な乱数を生成するためのパッケージとしてcrypto/rand
があるが
それの Windows 版の内部実装のコードを見ていたらいつの間にか RtlGenRandom
から
ProcessPrng
という関数に変わっていたということを今更見つけた。
具体的にはこのコミットで変更されたらしい https://github.com/golang/go/commit/693def151adff1af707d82d28f55dba81ceb08e1
RtlGenRandom
は advapi32.dll
から SystemFunction036
という名前でエクスポートされる関数で
ドキュメント化されているが互換性は保証されない、みたいな機能であった。
https://learn.microsoft.com/ja-jp/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom
一方変更された ProcessPrng
はBCryptPrimitives.dll
からエクスポートされており
仕様上も常に TRUE を返すとなっている。
https://learn.microsoft.com/ja-jp/windows/win32/seccng/processprng
Microsoft は CryptoAPI を次世代 API に置き換える方向に向かっておりおそらくその流れを汲んで 移行してっているようだ。 https://learn.microsoft.com/ja-jp/windows/win32/seccng/cng-portal
なお、私が知っていたのはRtlCryptGenRandom
が使われていることだけだったのだが
crypto/rand
の Windows 上の の乱数生成器の歴史を blame して見ていくと
最初に実装された頃(2010 年,14 年前!)は CryptGenRandom
を使っていたようだ
https://github.com/golang/go/commit/ccd28e8eb6f81f21093deb730ea70982cb381514 https://learn.microsoft.com/ja-jp/windows/win32/api/wincrypt/nf-wincrypt-cryptgenrandom
その後非推奨化されたのに伴って代替としてRtlGenRandom
になった。
https://github.com/golang/go/issues/33542 https://github.com/golang/go/commit/333e90448a0e55f2e1161853caecf3d30ef3a74a
その前後ではBCryptGenRandom
やGenRandom
などいくつかの変更候補が現れたりしていた。
いずれも最終的にRtlGenRandom
を呼ぶだけのラッパーだから遅いとか他のライブラリや言語の実装がみんなRtlGenRandom
を使っているとかと言う理由で却下されている。
議論の中にはRtlGenRandom
の内部をリバースエンジニアリングした結果ProcessPrng
が呼ばれているという報告なども存在した。
そして、最近(2023 年)になってRtlGenRandom
の内部で呼ばれていたProcessPrng
を直接呼び出すように
変更されていったという流れのようだ。
感想#
Windows API って抽象化層が厚いけどこういうシステムのベースのところだと邪魔だから 段々リバースエンジニアリングとかで内部構造の理解が深まっていくにつれて どんどん下のほうの関数を呼ぶようになっていてちょっとでもオーバーヘッドを減らそうという努力を感じた。
あと次世代 API は Windows 2008 Server とか Vista から使えるみたいなことが Microsoft のドキュメントには書いてあるけど普及するまでには時間がかかるんだなぁとも感じた。