はじめに
普段の生活で256bitの暗号論的疑似乱数を取得したいなぁって思うことありませんか? 僕はありませんが......。
この記事ではそんな願いを叶えるために、Rustでのプログラムを解説します。
暗号論的疑似乱数って?
暗号論的疑似乱数生成器 ( CSPRNG ) を用いて作られた乱数のことで、再現可能な周期が排除されています。
ただの疑似乱数発生器( PRNG )とちがい、それによって生成される乱数は推測することができないので、その分だけセキュリティ的に強固なわけですね。
アクセストークンの生成などのユースケースが考えられます。
暗号論的疑似乱数生成器の性質
暗号論的疑似乱数生成器には以下のような性質(というか、仕様)があります。
- 全ての暗号論的疑似乱数生成器は 乱数列の最初の k ビットを与えられたとき、k+1 番目のビットの値を多項式時間で2分の1をこえる確率で予測するアルゴリズムが存在しない。
- 全ての暗号論的疑似乱数生成器はその状態の一部または全部が明らかになっても(あるいは正しく推測されても)、明らかにされた状態より以前に生成された乱数列は再現できない。さらに、実行中にエントロピーの入力がある場合、その入力を知っていても暗号論的疑似乱数生成器の将来の状態を予測できない。
使ったクレート
- rand (乱数生成のクレート)
- rand_chacha (CSPRNGのアルゴリズム)
- bigint (64bit以上の大きなintを扱うクレート)
cargo.toml
rand = {version = "0.7.3"}
rand_chacha = "*"
bigint = "4"
コード
main.rs
use rand::prelude::*;
// rand クレートは乱数を扱うクレート
// 疑似乱数生成器の実装のほか、暗号的乱数生成器も用意されている
use rand_chacha::ChaCha20Rng;
// randクレートの暗号的乱数生成器のアルゴリズムは内部的に隠蔽されていて、
// 将来に渡って変更可能性があるため、こちらのrand_chachaクレートのアルゴリズムを直接使うのが公式で奨励されている
use bigint::U256;
// rustの標準では256bitの整数の型は用意されていないため、こちらのクレートを用いる。
fn main() {
let mut csp_rng = ChaCha20Rng::from_entropy();
// ChaCha20Rngは暗号的乱数生成器のアルゴリズムの名前らしい。
// from_entropy()関数は引数を与えなければ実行機のハードウェアの状態から乱数生成器を作成する。
let mut data = [0u8; 32];
// randクレートは直接256bitの乱数を扱えないため、8bit x 32ブロックのスライスとしてデータを保持する。
csp_rng.fill_bytes(&mut data);
// dataのスライスを埋める
let num :U256 = U256::from(data);
// U256の型には[u8; 32]へのFromトレイトが実装されているため、これで変換ができる。
println!("CSPRNG Generates: {:?}", num);
}
終わりに
暗号/セキュリティ関連は何も知らないので何か間違えたことや補足があれば教えて頂きたいです。